GitHub で見る
レンジブレイクアウト2 戦略
概要
RangeBreakout2 戦略 は、MetaTrader エキスパート アドバイザー「RangeBreakout2」の StockSharp 移植です。このアルゴリズムは、設定可能な時間 (毎週、毎日、または連続) で価格範囲を準備し、買値/売値がその範囲を外れると単一の成行注文を開きます。各取引の後、レンジ準備サイクルが再開されます。この実装では、元の資金管理ルール (一定、線形、マーチンゲール、および Fibonacci スケーリング) と、負けた取引後の利益確定距離のオプションの拡張が再現されます。
この戦略は単一の証券で機能し、最良の買値/売値に依存します。ブレークアウト検出の応答性を維持できるように、アダプターが最新の注文帳データを提供していることを確認してください。
取引ロジック
- スケジュール – 設定された時間に、戦略は現在の売値を設定の中心として記録し、生の範囲から上限/下限ブレイクアウト レベルを導き出します。
- 範囲計算 – 生の範囲は、次の 3 つのモードのいずれかから取得されます。
- ATR – 最新の平均 True Range 値に
AtrPercentage を乗算します。
- パーセント – 現在の売値の
PricePercentage パーセントを使用します。
- 修正 –
FixedRangePoints の価格ステップを絶対距離に変換します。
- ブレイクアウト検出 –
Setup フェーズでは、戦略は最良の買値/売値を監視します。アスクが上限レベルを上回った場合、またはビッドが下限レベルを下回った場合、成行注文が発行されます。
- エントリ タイプ –
TradeMode は、ブレイクアウト (Stop)、フェード (Limit)、またはランダム動作のいずれかを選択します。ランダム モードでは、各エントリでブレイクアウトまたはフェードのいずれかを選択します。
- 保護 – ストップロスとテイクプロフィットのオフセットは生のレンジから導出されます。前回の取引が損失で終了し、
RangeMultiplier が 1 より大きい場合、利食い距離はその乗数によって拡大されます。
- 資金管理 – 注文量は、ポートフォリオの自由資本 (
CurrentValue - BlockedValue) と選択したロット モードから計算されます。
- 定数 – 常にベースボリュームを使用します。
- 線形 – 損失が発生するたびに線形に増加します。
- Martingale – 損失後、前のボリュームに
LotMultiplier を掛けます。
- Fibonacci – 損失後は Fibonacci シーケンスに従って成長します。
ポジションがクローズされると、戦略はスタンバイフェーズにリセットされ、次のスケジュールトリガーを待ちます。
パラメーター
| グループ |
名前 |
説明 |
デフォルト |
| スケジュール |
Periodicity |
レンジの準備頻度: 毎週、毎日、またはノンストップ。 |
Weekly |
| スケジュール |
Day |
Periodicity = 毎週の場合に使用される取引日。 |
Monday |
| スケジュール |
Hour |
セットアップが構築された時刻 (MetaTrader スタイルの調整: 保存された値 + 1、≥ 23 の場合は 0 に制限されます)。 |
0 |
| 範囲 |
RangeMode |
生の範囲の計算方法 (ATR / パーセント / 固定)。 |
Atr |
| 範囲 |
AtrPercentage |
ATR 値に適用されるパーセンテージ乗数。 |
50 |
| 範囲 |
AtrLength |
ATR インジケーターで使用されるローソク足の数。 |
20 |
| 範囲 |
PricePercentage |
RangeMode = Percent のときに使用される現在の売値のパーセンテージ。 |
1 |
| 範囲 |
FixedRangePoints |
RangeMode = Fixed の場合、価格ステップで表される固定範囲。 |
1000 |
| 取引 |
RangePercentage |
ブレイクアウト レベルに適用される生の範囲のパーセンテージ。 |
100 |
| 取引 |
TradeMode |
エントリースタイル: ストップ (ブレイクアウト)、リミット (フェード)、またはランダム。 |
Stop |
| 取引 |
TakeProfitPercentage |
(オプションで拡張された) レンジのパーセンテージとしてのテイクプロフィット距離。 |
100 |
| 取引 |
StopLossPercentage |
基本レンジのパーセンテージとしてのストップロス距離。 |
100 |
| リスク |
LotMode |
ロット管理スキーム (定数 / 線形 / Martingale / Fibonacci)。 |
Martingale |
| リスク |
MarginPercentage |
基本注文量のために確保されている自由資本の一部。 |
10 |
| リスク |
LotMultiplier |
マーチンゲールのようなスケーリング モードで適用される乗数。 |
2 |
| リスク |
RangeMultiplier |
損失取引後に適用されるテイクプロフィット乗数。 |
1 |
| データ |
SignalCandleType |
スケジュール条件を確認するために使用されるキャンドルのタイプ。 |
1m time-frame |
| データ |
AtrCandleType |
ATR の計算に使用されるローソクの種類。 RangeMode = Atr の場合にのみリクエストされます。 |
1d time-frame |
実装メモ
- この戦略では、ライブの入札/売値更新が必要です。これらがないと、ブレークアウト検出はトリガーされません。
- 基本ボリュームの計算はポートフォリオの資本 (
CurrentValue - BlockedValue) に依存します。コネクタがこれらのフィールドを提供しない場合、ボリュームは交換の最小値に戻ります。
- 秘密保持命令は、
SetStopLoss および SetTakeProfit を通じて発行されます。結果として得られるポジション (新しい取引後) は、基本クラスがスケーリング シナリオの組み合わせた保護を管理できるように渡されます。
- ATR フォールバックは、元のエキスパート アドバイザを模倣します。インジケーターの準備ができていない場合、範囲はデフォルトで現在のアスク価格の 1% に設定されます。
- ランダム取引モードでは、戦略構築にシードされた .NET
Random クラスを使用します。したがって、2 つの連続したブレイクアウトでは異なるエントリー タイプが選択される可能性があります。
使用のヒント
- スケジュール チェックの目的の解決策に一致するように
SignalCandleType を構成します。 1 分間のローソク足ストリームは、MQL バージョンのティック主導の動作を厳密に再現します。
- 毎週のスケジュールの場合、サーバーのタイムゾーンが元の EA の予想と一致していることを確認してください。
- マーチンゲールのようなロット モードを使用する場合は、
RangeMultiplier の影響を監視します。ボリュームの増加とともにテイクプロフィット ディスタンスを拡大すると、連敗後のエクスポージャが増加します。
- ストップロスとテイクプロフィットの距離は生の範囲から導出されるため、
RangePercentage の値が大きいと、保護オフセットも同様に大きくなります。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Range Breakout 2 strategy: Donchian channel breakout.
/// Buys on new high breakout, sells on new low breakout.
/// </summary>
public class RangeBreakout2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelPeriod;
private decimal _prevHigh;
private decimal _prevLow;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public RangeBreakout2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_channelPeriod = Param(nameof(ChannelPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Channel Period", "Highest/Lowest period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0m;
_prevLow = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highValue, decimal lowValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (_hasPrev)
{
if (close > _prevHigh && Position <= 0)
BuyMarket();
else if (close < _prevLow && Position >= 0)
SellMarket();
}
_prevHigh = highValue;
_prevLow = lowValue;
_hasPrev = true;
}
}
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.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class range_breakout2_strategy(Strategy):
def __init__(self):
super(range_breakout2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._channel_period = self.Param("ChannelPeriod", 30)
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def ChannelPeriod(self):
return self._channel_period.Value
@ChannelPeriod.setter
def ChannelPeriod(self, value):
self._channel_period.Value = value
def OnReseted(self):
super(range_breakout2_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(range_breakout2_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.ChannelPeriod
lowest = Lowest()
lowest.Length = self.ChannelPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._has_prev:
if close > self._prev_high and self.Position <= 0:
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
self.SellMarket()
self._prev_high = float(high_value)
self._prev_low = float(low_value)
self._has_prev = True
def CreateClone(self):
return range_breakout2_strategy()