GitHub で見る
アーリーバードレンジブレイク戦略
概要
Early Bird Range Break Strategy は、MetaTrader「earlyBird3」エキスパート アドバイザーの C# ポートです。欧州取引開始直後に起こるレンジブレイクアウトをターゲットにしている。このアルゴリズムは早朝の保ち合いレンジを観察し、14 期間の RSI で潜在的なブレイクアウトをフィルターし、ブレイクアウトの方向に最大 3 つの成行注文を入力します。各注文は、事前定義されたテイクプロフィットレベル、共有ストップロス、およびボラティリティが最近の平均を超えて拡大した場合にのみ有効になるオプションのトレーリングメカニズムを使用します。
データ要件
- 取引商品の単一タイムフレームのローソク足ストリーム (デフォルト: 5 分足のローソク足)。
- すべてのストップロスとテイクプロフィットの距離はポイントで定義されるため、商品は有効な
PriceStep を提供する必要があります。
- 取引時間は、受信キャンドルのタイムスタンプ (データ ソースのサーバー時間) を使用して評価されます。
取引セッション
- レンジの構築 –
RangeStartHour と RangeEndHour の間で、戦略は最高値と最低値を記録します。
- 取引ウィンドウ –
TradingStartHour:TradingStartMinute の後、TradingEndHour の前にブレイクアウト ロジックがアクティブになります。
- 強制終了 –
ClosingHour で、損益に関係なく、残りのポジションはすべて清算されます。
- 平日のみ – 信号は月曜日から金曜日まで処理されます。
エントリーロジック
- 長いブレイクアウト レベルは
range high + EntryBufferPoints に設定され、短いブレイクアウト レベルは range low - EntryBufferPoints に設定されます。バッファーは価格ポイントで表されます。
- RSI フィルタは、長いセットアップの場合は 50 より大きく、短いセットアップの場合は 50 以下である必要があります。
- ブレイクアウトは取引日ごとに 1 方向につき 1 回のみ許可されます。トリガーされると、3 つの成行注文 (デフォルトの数量
0.1) が直ちに送信されます。
- 反対のポジションがすでにオープンしていて、
HedgeTrading が無効になっている場合、新しいシグナルは無視されます。 HedgeTrading が有効な場合、戦略はまず既存のポジションを決済し、次に新しい方向に入ります。これは元の EA の意図を反映していますが、StockSharp アカウントがネッティングされているため、ポジション反転を使用します。
出口管理
- ストップロス – 共有ストップロス (
StopLossPoints) が集計ポジションに適用されます。価格がそのレベルを超えると、残りのサイズは直ちにクローズされます。
- テイクプロフィットラダー – 3 つのターゲット (
TakeProfit1Points、TakeProfit2Points、TakeProfit3Points) はそれぞれ 1 つのポジション部分をクローズします。残りの部分は、セッションの終了によって停止、追跡、または閉じられるまで、開いたままになります。
- トレーリングストップ – 1 つの部分だけが残っている場合、現在のローソク足の範囲は
ATR * TrailingRiskMultiplier を超える必要があります。価格が少なくとも TrailingStopPoints 進んでいる場合、最初のストップ距離を維持しながらストップロスが取引方向にステップされます。
- セッション終了 – 現在時刻が
ClosingHour に達すると、開いている露出は完全に平坦化されます。
パラメーター
| パラメータ |
説明 |
デフォルト |
AutoTrading |
注文の実行を有効/無効にします。 |
true |
HedgeTrading |
反対の信号での位置反転を可能にします (フラットアンドリバースとして実装)。 |
true |
OrderType |
0 – 両方向、1 – ロングのみ、2 – ショートのみ。 |
0 |
TradeVolume |
発行された成行注文ごとの出来高。 |
0.1 |
StopLossPoints |
価格ポイントでのストップロス距離。 |
60 |
TakeProfit1Points |
最初の部分のテイクプロフィット距離。 |
10 |
TakeProfit2Points |
2 番目の部分のテイクプロフィット距離。 |
20 |
TakeProfit3Points |
3 番目の部分のテイクプロフィット距離。 |
30 |
TrailingStopPoints |
トレーリングストップが作動する前の最小限の有利な動き。 |
15 |
TrailingRiskMultiplier |
ボラティリティの拡大を検証するときに ATR に適用される乗数。 |
1.0 |
EntryBufferPoints |
ブレイクアウトレベルに追加距離が追加されました。 |
2 |
RangeStartHour |
基準範囲が始まる時間。 |
3 |
RangeEndHour |
基準範囲が終了する時刻。 |
7 |
TradingStartHour |
ブレイクアウトエントリーが許可される時間。 |
7 |
TradingStartMinute |
ブレイクアウトエントリーが許可される分。 |
15 |
TradingEndHour |
新しいエントリが取得されなくなるまでの 1 時間。 |
15 |
ClosingHour |
すべての取引が終了する時間。 |
17 |
RsiPeriod |
RSI ルックバックはフィルタリングに使用されます。 |
14 |
VolatilityPeriod |
ATR のボラティリティ ゲートのルックバック。 |
16 |
CandleType |
分析に使用されるローソク足シリーズ (デフォルトは 5 分)。 |
TimeSpan.FromMinutes(5) |
実装メモ
- この戦略は、StockSharp の高レベル API を介してローソク足をサブスクライブし、RSI および ATR インジケーターをサブスクリプションに直接バインドします。
- インジケーター値は、プロジェクト ガイドラインに従って、
GetValue の呼び出しやカスタム バッファーの保存を行わずに、ProcessCandle コールバック内で消費されます。
- 完成したキャンドルのみが加工されます。部分的な更新は無視されます。
- すべての価格距離は、商品
PriceStep を使用してポイントから絶対価格に変換されます。セキュリティ定義で正しいティック サイズが公開されていることを確認してください。
- 元のエキスパートアドバイザーは、ヘッジのために個別の MQL 注文を保存していました。 StockSharp はネット ポジションを使用するため、
HedgeTrading が有効な場合、このポートはクローズ アンド リバース操作を実行します。
使い方のヒント
- ローソク足の時間枠を、元の EA で使用された取引会場 (MetaTrader の M5 から H1) に合わせます。データ フィードのローカル市場スケジュールを反映するように、
RangeStartHour、RangeEndHour、および取引ウィンドウを調整します。
- 最適化するときは、ブレイクアウト バッファー、テイクプロフィット ラダー、ボラティリティ フィルターに焦点を当てます。これらは誤ったブレイクアウトと見逃した動きの間のバランスを定義するためです。
- トレーリングは意図的に保守的です。より厳密な終了が必要な場合は、トレーリング調整がより頻繁に行われるように、
TrailingRiskMultiplier または StopLossPoints を減らすことを検討してください。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Early Bird RangeBreak: EMA trend following with ATR stops.
/// </summary>
public class EarlyBirdRangeBreakStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevClose;
private decimal _entryPrice;
public EarlyBirdRangeBreakStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0; _entryPrice = 0;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (_prevClose == 0 || atrVal <= 0) { _prevClose = close; return; }
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || close < emaVal) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || close > emaVal) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (close > emaVal && _prevClose <= emaVal) { _entryPrice = close; BuyMarket(); }
else if (close < emaVal && _prevClose >= emaVal) { _entryPrice = close; SellMarket(); }
}
_prevClose = close;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
class early_bird_range_break_strategy(Strategy):
def __init__(self):
super(early_bird_range_break_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_close = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(early_bird_range_break_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._entry_price = 0.0
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
ev = float(ema_val)
av = float(atr_val)
close = float(candle.ClosePrice)
if self._prev_close == 0 or av <= 0:
self._prev_close = close
return
if self.Position > 0:
if close >= self._entry_price + av * 2.5 or close <= self._entry_price - av * 1.5 or close < ev:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 2.5 or close >= self._entry_price + av * 1.5 or close > ev:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_close = close
return
if self.Position == 0:
if close > ev and self._prev_close <= ev:
self._entry_price = close
self.BuyMarket()
elif close < ev and self._prev_close >= ev:
self._entry_price = close
self.SellMarket()
self._prev_close = close
def OnReseted(self):
super(early_bird_range_break_strategy, self).OnReseted()
self._prev_close = 0.0
self._entry_price = 0.0
def CreateClone(self):
return early_bird_range_break_strategy()