GitHub で見る

TSTプルバックリバーサル戦略

概要

TST プルバック リバーサル戦略 は、積極的なバー内リバーサルを監視します。これは、元の MetaTrader 4 Expert Advisor TST.mq4 から変換され、高レベルの StockSharp API を使用して再構築されました。この方法では、日中の極値を設定した後、価格がローソク足の始値から急激に離れたローソク足を探し、平均値の戻りを期待してその動きをフェードアウトします。この戦略はロングとショートの両方を取引し、価格ステップで測定される静的なストップロスとテイクプロフィットのレベルを使用します。

信号ロジック

  • 長いセットアップ

    1. ローソクは開いた状態 (Open > Close) よりも下で閉じます。
    2. ローソク足の高値と終値の間の距離が GapPoints * PriceStep を超えています。
    3. 同じバーで以前に取引が実行されたことはありません。 満足すると、この戦略はショートエクスポージャーをクローズし、OrderVolume 単位(プラス、ショートポジションからロングポジションに切り替えるのに必要なサイズ)を購入します。
  • 簡単なセットアップ

    1. ローソクは開いた状態 (Close > Open) よりも上で閉じます。
    2. 終値とローソク足の安値の間の距離は GapPoints * PriceStep を超えています。
    3. 同じバーで以前に取引が実行されたことはありません。 満足すると、この戦略はロングエクスポージャーをクローズし、OrderVolume ユニット(プラス、ロングポジションからショートポジションに切り替えるのに必要なサイズ)を売ります。

ポジション管理

  • 新しい取引では、約定価格と StopLossPoints/TakeProfitPoints パラメータから計算された静的なストップロスとテイクプロフィットのレベルがすぐに割り当てられます。
  • 完成したローソク足ごとに、戦略はローソク足の高値/安値をチェックしてストップまたはターゲットに触れたかどうかを確認し、トリガーされた場合はポジションを終了します。ストップロスチェックはテイクプロフィットチェックよりも優先されます。
  • エグジット後、保存されたリスクレベルはクリアされますが、ストラテジーは同じローソク足の間に再エントリーを避けるためにバータイムを記憶しています(MQL4 バージョンの NevBar() ガードを再現しています)。

パラメーター

  • StopLossPoints (デフォルト 500): エントリーから保護ストップまでの距離。価格ステップで表されます。
  • TakeProfitPoints (デフォルト 100): エントリーから利益目標までの距離。価格ステップで表されます。
  • GapPoints (デフォルト 500): シグナルを生成するために必要なローソク足の極値と終値の間の最小プルバック。
  • OrderVolume (デフォルト 0.1): 新しい成行注文ごとに送信される数量。
  • CandleType (デフォルト 1 hour): SubscribeCandles を通じて提供されるローソク足のタイムフレーム。

すべての距離ベースの設定には、機器の PriceStep が乗算されます。セキュリティがステップを報告しない場合、戦略は 1 に戻ります。

実装メモ

  • 変換では、StockSharp の高レベルの API が使用され、カスタム インジケーター コレクションは作成されません。
  • 完成したキャンドルのみが、Strategy Designer との互換性を維持するために処理されます。これは、完成したバー データを使用して、MT4 ロボットのバー内決定を近似します。
  • 専用フラグ _lastSignalBarTime は、MQL4 コードから NevBar() ガードを複製するため、キャンドルごとに 1 つの注文のみを開くことができます。
  • 注文量の処理は MT4 の動作を反映しています。既存の反対のポジションは、単一の成行注文で新しい方向を確立する前にフラット化されます。
  • ストップロス注文とテイクプロフィット注文は、StockSharp 内でコントロールを維持しながら、元の距離と一致するように (サーバー側の注文ではなく) 戦略ロジック内でシミュレートされます。

使用のヒント

  • 取引商品のボラティリティに応じて GapPoints を選択します。値を大きくすると取引頻度は減りますが、より小さい値戻しはフィルターされます。
  • ストップとターゲットのチェックは完了したローソク足に依存するため、より厳密な実行が必要な場合は、より短いローソク足の期間を使用することを検討してください。
  • ライブ市場に展開するときに戦略を追加のフィルター (トレンド、時間帯、出来高) と組み合わせて、ホイップソー取引を削減します。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// TST Pullback Reversal: buys after deep pullback from candle high,
/// sells after rally from candle low. Uses ATR for thresholds.
/// </summary>
public class TstStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _pullbackMultiplier;
	private readonly StrategyParam<decimal> _stopMultiplier;
	private readonly StrategyParam<decimal> _takeMultiplier;

	private decimal _entryPrice;
	private decimal _stopPrice;
	private decimal _takePrice;

	public TstStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");

		_pullbackMultiplier = Param(nameof(PullbackMultiplier), 0.5m)
			.SetDisplay("Pullback Mult", "ATR multiplier for pullback threshold.", "Signals");

		_stopMultiplier = Param(nameof(StopMultiplier), 2.0m)
			.SetDisplay("Stop Mult", "ATR multiplier for stop loss.", "Risk");

		_takeMultiplier = Param(nameof(TakeMultiplier), 1.0m)
			.SetDisplay("Take Mult", "ATR multiplier for take profit.", "Risk");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public decimal PullbackMultiplier
	{
		get => _pullbackMultiplier.Value;
		set => _pullbackMultiplier.Value = value;
	}

	public decimal StopMultiplier
	{
		get => _stopMultiplier.Value;
		set => _stopMultiplier.Value = value;
	}

	public decimal TakeMultiplier
	{
		get => _takeMultiplier.Value;
		set => _takeMultiplier.Value = value;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_entryPrice = 0;
		_stopPrice = 0;
		_takePrice = 0;

		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (atrVal <= 0)
			return;

		var close = candle.ClosePrice;
		var open = candle.OpenPrice;
		var high = candle.HighPrice;
		var low = candle.LowPrice;
		var threshold = atrVal * PullbackMultiplier;
		var stopDist = atrVal * StopMultiplier;
		var takeDist = atrVal * TakeMultiplier;

		// Risk management
		if (Position > 0)
		{
			if (_stopPrice > 0 && close <= _stopPrice)
			{
				SellMarket();
				_entryPrice = 0;
				_stopPrice = 0;
				_takePrice = 0;
				return;
			}
			if (_takePrice > 0 && close >= _takePrice)
			{
				SellMarket();
				_entryPrice = 0;
				_stopPrice = 0;
				_takePrice = 0;
				return;
			}
		}
		else if (Position < 0)
		{
			if (_stopPrice > 0 && close >= _stopPrice)
			{
				BuyMarket();
				_entryPrice = 0;
				_stopPrice = 0;
				_takePrice = 0;
				return;
			}
			if (_takePrice > 0 && close <= _takePrice)
			{
				BuyMarket();
				_entryPrice = 0;
				_stopPrice = 0;
				_takePrice = 0;
				return;
			}
		}

		// Entry: deep pullback from high = buy reversal
		if (Position == 0)
		{
			if (open > close && high - close > threshold)
			{
				_entryPrice = close;
				_stopPrice = close - stopDist;
				_takePrice = close + takeDist;
				BuyMarket();
			}
			else if (close > open && close - low > threshold)
			{
				_entryPrice = close;
				_stopPrice = close + stopDist;
				_takePrice = close - takeDist;
				SellMarket();
			}
		}
	}
}