GitHub で見る

Twenty200 タイムブレイクアウト

この戦略は、MetaTrader エキスパート アドバイザー 20/200 エキスパート v4.2 (AntS) の StockSharp 移植です。取引日の特定の時間を待機し、過去の 2 つの時間ごとの始値 (デフォルト設定では 6 バーと 2 バー) を比較します。遠い始値が近い始値よりも Short Delta ピップ以上高い場合、戦略は売りになりますが、逆ギャップが Long Delta ピップを超えるとロングポジションがオープンします。

取引ロジック

  • この戦略は時間足ローソク足をサブスクライブします (Candle Type を通じて設定可能)。
  • 1日に許可される取引は1回のみです。注文は、時間が Trade Hour に等しいローソク足がアクティブになったときに発注されます。
  • シグナルは、現在のローソク足から遡った始値の LookbackFar バーと LookbackNear バーを使用します。
    • 簡単なセットアップ: Open[t1] - Open[t2] > Short Delta × pip
    • 長いセットアップ: Open[t2] - Open[t1] > Long Delta × pip
  • 計算された数量で成行注文が送信されます。ストップロスとテイクプロフィットの距離は、MetaTrader バージョンから取得され、ピップで表され、Security.PriceStep を介して価格に自動的に変換されます。
  • 一度に存在できるポジションは 1 つだけです。毎日の取引は次の暦日に再開されます。

ポジション管理

  • ストップロスとテイクプロフィットは、ローソク足の高値/安値の極値を使用して、ローソク足の更新ごとに評価されます。
  • Max Open Hours は、ポジションの有効期間が設定された時間数 (デフォルトでは 504 時間) を超えると強制的に市場から撤退します。セーフティタイマーを無効にするには、パラメータをゼロに設定します。

お金の管理

  • Fixed Volume は、Use Auto Lot が無効になっている場合、または残高情報が利用できない場合に使用されるフォールバック コントラクト サイズを定義します。
  • Use Auto Lot が有効な場合、ロットサイズはエキスパートアドバイザーからの巨大なステップテーブルに従います。 StockSharp では、テーブルはデフォルトの係数 0.000038 を使用して volume = round(balance × Auto Lot Factor, 2) によって近似され、文書化された範囲 (300 USD ~ 270,000 USD+) の出来高 1 ピップ以内の MT4 値を再現します。
  • 現在のポートフォリオの値が最後に記録された残高を下回ると、次の取引に Big Lot Multiplier が乗算され、元のコードの「Big Lot」リカバリ取引を模倣します。
  • ボリュームは Security.VolumeStep に調整され、利用可能な場合は MinVolume/MaxVolume の間にクランプされます。

MetaTrader EA との違い

  • MT4 スクリプトには、1,000 を超える手動しきい値行が保存されていました。 StockSharp バージョンでは、同じ階段に適合する線形係数 (Auto Lot Factor) が使用されます。別のブローカーの正確なレプリカが必要な場合は、係数を調整します。
  • ストップロス/テイクプロフィット注文は、ローソク足の極値での市場出口を通じてシミュレートされます。これにより、取引所側の逆指値注文のサポートに依存することなく、バックテストとライブ取引全体で動作の一貫性が維持されます。
  • グローバル変数 (globalBalansglobalPosic) はメモリ内の状態に置き換えられます。ファイル システムや端末状態は必要ありません。

パラメーター

パラメータ 説明
ロング/ショートテイクプロフィット 利益目標までの距離 (pips)。
ロング/ショートストップロス ストップロスのピップ単位の距離。
取引時間 シグナルがトリガーされるセッションの時間 (0 ~ 23)。
遠近のルックバック 2 つの始値を検査するために戻るバーの数。
ロング/ショート デルタ ポジションをオープンするために必要なピップギャップ。
最大営業時間 位置の最大存続期間 (時間単位) (0 はガードを無効にします)。
固定ボリューム 自動サイジングが無効になっている場合のベースライン契約ボリューム。
自動ロットを使用する 勘定科目値からのロットサイジングを有効にします。
自動ロット係数 MT4 ステップ テーブルをエミュレートするためにポートフォリオ値に適用される乗数。
ビッグロットマルチプライヤー 株価下落後に適用される出来高乗数。
キャンドルの種類 シグナルキャンドルに使用される時間枠。
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class Twenty200TimeBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _shortPeriod;
	private readonly StrategyParam<int> _longPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevShort;
	private decimal _prevLong;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int ShortPeriod { get => _shortPeriod.Value; set => _shortPeriod.Value = value; }
	public int LongPeriod { get => _longPeriod.Value; set => _longPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Twenty200TimeBreakoutStrategy()
	{
		_shortPeriod = Param(nameof(ShortPeriod), 20).SetDisplay("Short SMA", "Short SMA period", "Indicators");
		_longPeriod = Param(nameof(LongPeriod), 200).SetDisplay("Long SMA", "Long SMA period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevShort = default;
		_prevLong = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevShort = 0;
		_prevLong = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var shortSma = new SimpleMovingAverage { Length = ShortPeriod };
		var longSma = new SimpleMovingAverage { Length = LongPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(shortSma, longSma, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal shortSma, decimal longSma)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevShort = shortSma; _prevLong = longSma; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevShort = shortSma;
			_prevLong = longSma;
			return;
		}

		if (_prevShort <= _prevLong && shortSma > longSma && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevShort >= _prevLong && shortSma < longSma && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevShort = shortSma;
		_prevLong = longSma;
	}
}