HSI 最初の30分ロウソク足戦略
この戦略は香港セッション開始後最初の30分の高値と安値を記録し、5分足チャートでそのブレイクアウトを取引します。1日1取引のみ許可されます。
詳細
- エントリー条件:
- ロング: セッション中に価格が最初の30分高値を上抜ける。
- ショート: セッション中に価格が最初の30分安値を下抜ける。
- ロング/ショート: 両方向。
- エグジット条件:
- レンジの反対側でストップロス。
- エントリーから
RiskReward倍のレンジサイズでテイクプロフィット。
- ストップ: あり。
- デフォルト値:
RiskReward= 1.CandleType= TimeSpan.FromMinutes(5).TimeFrame().
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: 両方
- インジケーター: Price action
- ストップ: はい
- 複雑さ: 基本
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// HSI First 30m Candle strategy.
/// Records the high and low of the first 30 minutes after the Hong Kong session opens (09:30 HKT, 01:30 UTC). During the rest of
/// the session a close above that high goes long and a close below that low goes short, at most one trade per day. The stop sits
/// at the opposite side of the range and the target at the range size multiplied by RiskReward from the entry.
/// </summary>
public class HsiFirst30mCandleStrategy : Strategy
{
private static readonly TimeSpan _sessionOpen = new(1, 30, 0);
private static readonly TimeSpan _rangeEnd = new(2, 0, 0);
private static readonly TimeSpan _sessionClose = new(8, 0, 0);
private readonly StrategyParam<decimal> _riskReward;
private readonly StrategyParam<DataType> _candleType;
private DateTime _currentDay;
private decimal? _rangeHigh;
private decimal? _rangeLow;
private bool _tradedToday;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Target distance as a multiple of the range size.
/// </summary>
public decimal RiskReward
{
get => _riskReward.Value;
set => _riskReward.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public HsiFirst30mCandleStrategy()
{
_riskReward = Param(nameof(RiskReward), 1m)
.SetGreaterThanZero()
.SetDisplay("Risk Reward", "Target distance as a multiple of the range size", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_currentDay = default;
_rangeHigh = null;
_rangeLow = null;
_tradedToday = false;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var openTime = candle.OpenTime;
var day = openTime.Date;
var timeOfDay = openTime.TimeOfDay;
if (day != _currentDay)
{
_currentDay = day;
_rangeHigh = null;
_rangeLow = null;
_tradedToday = false;
}
if (timeOfDay >= _sessionOpen && timeOfDay < _rangeEnd)
{
_rangeHigh = _rangeHigh is decimal h ? Math.Max(h, candle.HighPrice) : candle.HighPrice;
_rangeLow = _rangeLow is decimal l ? Math.Min(l, candle.LowPrice) : candle.LowPrice;
return;
}
if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
SellMarket(Position);
return;
}
if (Position < 0)
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
BuyMarket(-Position);
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_tradedToday || timeOfDay < _rangeEnd || timeOfDay >= _sessionClose)
return;
if (_rangeHigh is not decimal high || _rangeLow is not decimal low)
return;
var range = high - low;
if (range <= 0)
return;
var close = candle.ClosePrice;
if (close > high)
{
BuyMarket(Volume);
_stopPrice = low;
_takePrice = close + range * RiskReward;
_tradedToday = true;
}
else if (close < low)
{
SellMarket(Volume);
_stopPrice = high;
_takePrice = close - range * RiskReward;
_tradedToday = true;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
# Minutes after midnight UTC.
SESSION_OPEN = 90.0
RANGE_END = 120.0
SESSION_CLOSE = 480.0
class hsi_first_30m_candle_strategy(Strategy):
"""
HSI First 30m Candle strategy.
Records the high and low of the first 30 minutes after the Hong Kong session opens (09:30 HKT, 01:30 UTC). During the rest of
the session a close above that high goes long and a close below that low goes short, at most one trade per day. The stop sits
at the opposite side of the range and the target at the range size multiplied by RiskReward from the entry.
"""
def __init__(self):
super(hsi_first_30m_candle_strategy, self).__init__()
self._risk_reward = self.Param("RiskReward", 1.0).SetGreaterThanZero().SetDisplay("Risk Reward", "Target distance as a multiple of the range size", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._current_day = None
self._range_high = None
self._range_low = None
self._traded_today = False
self._stop_price = 0.0
self._take_price = 0.0
def OnReseted(self):
super(hsi_first_30m_candle_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(hsi_first_30m_candle_strategy, self).OnStarted2(time)
self._reset_state()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_time = candle.OpenTime
day = open_time.Date
time_of_day = open_time.TimeOfDay.TotalMinutes
if self._current_day is None or day != self._current_day:
self._current_day = day
self._range_high = None
self._range_low = None
self._traded_today = False
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
if time_of_day >= SESSION_OPEN and time_of_day < RANGE_END:
self._range_high = high_price if self._range_high is None else max(self._range_high, high_price)
self._range_low = low_price if self._range_low is None else min(self._range_low, low_price)
return
if self.Position > 0:
if low_price <= self._stop_price or high_price >= self._take_price:
self.SellMarket(self.Position)
return
if self.Position < 0:
if high_price >= self._stop_price or low_price <= self._take_price:
self.BuyMarket(-self.Position)
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._traded_today or time_of_day < RANGE_END or time_of_day >= SESSION_CLOSE:
return
if self._range_high is None or self._range_low is None:
return
high = self._range_high
low = self._range_low
rng = high - low
if rng <= 0:
return
close = float(candle.ClosePrice)
rr = float(self._risk_reward.Value)
if close > high:
self.BuyMarket(self.Volume)
self._stop_price = low
self._take_price = close + rng * rr
self._traded_today = True
elif close < low:
self.SellMarket(self.Volume)
self._stop_price = high
self._take_price = close - rng * rr
self._traded_today = True
def CreateClone(self):
return hsi_first_30m_candle_strategy()