GitHub で見る

トレンドキャプチャレガシー戦略

トレンド キャプチャ レガシー戦略は、MetaTrader エキスパート TrendCapture.mq4 をハイレベルの StockSharp API に移植します。 C# バージョンでは、Parabolic SAR の方向、低い ADX フィルター、シンプルな損益分岐点管理に基づいた元のルール セットが維持されます。

核となるアイデア

  • 選択した時間枠の完了したローソク足を処理し、それらを Parabolic SAR (0.02/0.2) と平均方向性インデックス (14) にフィードします。
  • ADX が AdxThreshold を下回っている場合にのみエントリーし、SAR の反転がより信頼できる穏やかな市場を示します。
  • 最後に終了した取引の方向と結果を覚えておいてください。勝者になった後は同じサイドを繰り返し、敗者になった後は反対側に反転します。
  • 固定距離のストップロスとテイクプロフィットレベル(価格ポイントで構成)を適用し、取引が BreakEvenGuard ポイントを獲得したらストップを損益分岐点に移動します。
  • 利用可能なポートフォリオ値と MaximumRisk から注文量を決定します。ポートフォリオ情報が利用できない場合は、戦略 Volume に戻ります。

パラメーター

名前 デフォルト 説明
SarStep 0.02 最初の Parabolic SAR 加速ステップ。
SarMax 0.2 最大 Parabolic SAR 加速。
AdxPeriod 14 ADX の平均期間。
AdxThreshold 20 新しいエントリをまだ許可する最大 ADX 値。
TakeProfitPoints 180 価格ポイントでの利食い距離。
StopLossPoints 50 価格ポイントでのストップロス距離。
BreakEvenGuard 5 ストップをエントリーに移動する前に必要な利益バッファー (ポイント単位)。
MaximumRisk 0.03 ポジションサイジングに使用される空きマージンの割合。
CandleType 1時間キャンドル インジケーターの計算と取引シグナルの時間枠。

注文管理

  • ロングエントリーには、終値が SAR を上回り、ADX が低いことが必要です。ショートには、同じ ADX フィルターを使用して、終値が SAR 未満である必要があります。
  • ストップロスとテイクプロフィットのレベルはエントリーごとに再計算され、完了したローソク足ごとに評価されます。
  • 損益分岐点アクティベーションは単にストップをエントリー価格にシフトするだけです。ストップロスが設定されていない場合 (ゼロまたは負の距離)、ガードは無視されます。

インジケーター

  • ParabolicSar 方向バイアス。
  • 強度フィルターの AverageDirectionalIndex (メインの ADX 行のみが使用されます)。

注意事項

  • この戦略では、プロジェクト ガイドラインに従って、BindEx を使用して直接バッファー アクセスを回避します。
  • ポートフォリオベースのボリューム計算では、ボードの制約 (LotStepMinVolumeMaxVolume) が考慮されます。
  • 方向バイアスに必要な取引履歴は OnNewMyTrade 経由で収集されるため、部分的な約定は引き続きサポートされます。
using System;



using StockSharp.Algo.Indicators;

using StockSharp.Algo.Strategies;

using StockSharp.BusinessEntities;

using StockSharp.Messages;



namespace StockSharp.Samples.Strategies;



public class TrendCaptureLegacyStrategy : Strategy

{

	private readonly StrategyParam<int> _fastPeriod;

	private readonly StrategyParam<int> _slowPeriod;

	private readonly StrategyParam<DataType> _candleType;



	private decimal _prevFast; private decimal _prevSlow; private bool _hasPrev;

	private int _cooldown;



	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }

	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

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



	public TrendCaptureLegacyStrategy()

	{

		_fastPeriod = Param(nameof(FastPeriod), 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");

	}



	/// <inheritdoc />

	protected override void OnReseted()

	{

		base.OnReseted();

		_prevFast = default;

		_prevSlow = default;

		_hasPrev = default;

		_cooldown = default;

	}



	/// <inheritdoc />

	protected override void OnStarted2(DateTime time)

	{

		base.OnStarted2(time);

		_hasPrev = false;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };

		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);

		subscription.Bind(fast, slow, ProcessCandle).Start();

	}



	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)

	{

		if (candle.State != CandleStates.Finished) return;

		if (!IsFormedAndOnlineAndAllowTrading()) return;

		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldown > 0)

		{

			_cooldown--;

			_prevFast = fast; _prevSlow = slow;

			return;

		}



		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)

		{

			var volume = Volume + Math.Abs(Position);

			BuyMarket(volume);

			_cooldown = 2;

		}

		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)

		{

			var volume = Volume + Math.Abs(Position);

			SellMarket(volume);

			_cooldown = 2;

		}

		_prevFast = fast; _prevSlow = slow;

	}

}