GitHub で見る
レンジブレイクアウトウィークリー戦略 (ID 3412)
レンジ ブレイクアウト ウィークリー戦略は、MetaTrader 5 エキスパート アドバイザー RangeBreakout.mq5 の StockSharp の高レベルの API 変換です。システムは、構成可能な曜日と時間帯を使用して週に 1 回ブレイクアウト レベルを準備し、価格が計算された範囲を上または下にブレイクしたときに単一の取引を開始します。 Martingale スタイルのポジションサイジングと損失補償ロジックは元のスクリプトを反映しており、実装ではローソク足、レベル 1 相場、インジケーター バインディングの StockSharp サブスクリプションを活用しています。
取引ロジック
- 毎週の準備ウィンドウ。 構成された平日の指定された時間足ローソク足の終値で、ストラテジーはローソク足の終値を参照価格として記録し、スタンバイ フェーズから セットアップ フェーズに移行します。
- 範囲の計算。
- プライマリ範囲は、20 期間の毎日の平均真の範囲 (ATR) から導出されます。 ATR の値は
ATR Percentage で乗算され、商品のティック サイズに正規化されます。
- ATR データが欠落している場合、アルゴリズムは現在の売値に
Price Percentage を乗算することに戻ります。
- 保護レベル
- 上下のブレイクアウトトリガーは、基準終値の上下 1 レンジに配置されます。
- テイクプロフィットとストップロスのオフセットは範囲のパーセンテージとして計算されます。損失後に補償がアクティブになると、MetaTrader ロジックと同様に、テイクプロフィットが累積された補償オフセットに置き換えられ、ストップロスが同じ量だけ拡大されます。
- 実行。
- セットアップ 中に、ストラテジーはレベル 1 の引用をリッスンします。上部トリガーを超えるブレークはロングポジションに入ります。下のトリガーを下回るとショートポジションがオープンします。注文は、ティックに合わせた価格チェックを伴う成行注文として送信されます。
- ポジションがアクティブになると (取引 フェーズ)、レベル 1 の相場が継続的に監視されます。保護ストップまたはターゲットに到達すると、成行注文でポジションがクローズされます。
- Martingale が回復しました。
- 損失エグジット後、次の取引サイズは 2 倍になり、損失相殺が補償バッファーに追加されるため、次のターゲットは累積損失の回復を目指します。
- 勝利終了により、乗数と補償バッファの両方が初期値にリセットされます。
- 毎日リセット。 取引が終了すると、ストラテジーは スタンバイ フェーズに戻り、次の適格な曜日と時間の組み合わせまで待機して、新しいセットアップを準備します。
パラメーター
| パラメータ |
デフォルト |
説明 |
Trading Day |
月曜日 |
ブレイクアウト基準ローソク足の測定に使用される平日。週末の選択は自動的に月曜日に再マップされ、元の警告動作と一致します。 |
Start Hour |
0 |
ローソク足の終値が基準となる時間 (0 ~ 23)。さまざまなセッション開始をカバーするように最適化可能。 |
Price Percentage |
1.0 |
ATR データが欠落している場合に範囲を計算するために使用される売値のフォールバック率。 |
ATR Percentage |
100 |
ブレイクアウト範囲を取得するために毎日の ATR 値に適用される乗数。 |
Take Profit Percentage |
100 |
利食い価格を定義するためにエントリーを超えて追加される範囲のパーセンテージ。連続損失の後は補償バッファによって上書きされます。 |
Stop Loss Percentage |
100 |
ストップロス価格を設定するためにエントリーから差し引かれる範囲のパーセンテージ。補償バッファは、損失後にこの距離を広げます。 |
Base Volume |
0.1 |
マーチンゲール スケーリング前の初期取引高。値は自動的にインストゥルメントのボリュームステップに丸められ、最小/最大制約によってクランプされます。 |
ATR Period |
20 |
ATR インジケーターに供給される毎日のローソク足の数。 |
Hour Candle Type |
1時間枠 |
準備ウィンドウを検出するために使用されるキャンドルのサブスクリプション。 |
ATR Candle Type |
1日の時間枠 |
ATR インジケーターをフィードするキャンドル サブスクリプション。 |
実装メモ
- データ サブスクリプション。 この戦略は、スケジュール設定用に時間ごとのローソク足、ATR の計算用に日次ローソク足、買値/売値モニタリング用にレベル 1 データをサブスクライブします。高レベルの
Bind API は、手動のバッファー処理を行わずにインジケーター値をストリーミングするために使用されます。
- ティック調整。 すべての価格レベル(リファレンス、トリガー、ストップロス、テイクプロフィット)は、ティックサイズの制約を尊重するために
Security.ShrinkPrice を通じて正規化され、MetaTrader の NormalizeDouble の動作を模倣します。
- 取引量の処理。 取引量は商品の
VolumeStep に四捨五入され、注文送信前に VolumeMin/VolumeMax によって制限され、元のロットのサニタイズが再現されます。
- フェーズ マシン。 内部フェーズ (
Standby、Setup、Trade) は元の enum ロジックを置き換え、準備サイクルごとに 1 つの取引を保証します。各終了後、次の条件を満たすローソク足が発生するまで、状態は Standby にリセットされます。
- 補償バッファ。
compensationOffset フィールドには、価格単位で表現された累積損失距離が格納されます。アクティブな場合、次の設定は利益確定オフセットをこの値に置き換え、ストップを同じ量だけ広げ、過去の金銭的損失を価格距離に変換する MetaTrader 式を反映します。
- ログ。 土曜日または日曜日を選択すると、情報ログがトリガーされ、MQL バージョンで表示される警告と一致して、営業日が自動的に月曜日に切り替わります。
使用のヒント
Trading Day と Start Hour を、意味のあるレンジを生成するセッション (アジアのレンジ ブレイクアウトやロンドン オープン ブレイクアウトなど) に合わせます。
ATR Percentage、Take Profit Percentage、および Stop Loss Percentage を一緒に校正します。レンジ乗数を増やすとトリガーが広くなり、取引が遅くなりますが、損益パーセンテージを調整すると報酬対リスクの比率が変更されます。
Start Hour、Base Volume、またはパーセンテージ パラメータの最適化を有効にして、元のエキスパート アドバイザーからのパラメータ スイープを再現します。
- マーチンゲール乗数によって作成される累積エクスポージャを監視します。高レバレッジのアカウントで実行する場合は、
Base Volume を下げることを検討してください。
- この戦略は単一の金融商品向けに設計されています。異なる証券またはセッション設定を使用して複数のコピーを展開して、対象範囲を多様化します。
コンバージョンカバレッジ
- ✅
RangeBreakout.mq5 からの毎週のスケジュール、範囲計算、保護レベル、およびマーチンゲール動作が維持されます。
- ✅ MetaTrader 固有の API 呼び出し (
iATR、CopyBuffer、OrderSend など) を慣用的な StockSharp 抽象化 (SubscribeCandles、AverageTrueRange、BuyMarket/SellMarket) に置き換えました。
- ✅ 要求に応じて、英語のインライン コメントと広範なドキュメントを実装しました。
- ✅ テストプロジェクトはそのままにし、タスクの制約に従って Python バリアントを作成しませんでした。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Range Breakout Weekly strategy: periodic range breakout using highest/lowest channels.
/// Buys on breakout above recent high, sells on breakout below recent low.
/// </summary>
public class RangeBreakoutWeeklyStrategy : 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 RangeBreakoutWeeklyStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_channelPeriod = Param(nameof(ChannelPeriod), 20)
.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_breakout_weekly_strategy(Strategy):
def __init__(self):
super(range_breakout_weekly_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._channel_period = self.Param("ChannelPeriod", 20)
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_breakout_weekly_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(range_breakout_weekly_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_breakout_weekly_strategy()