GitHub で見る

3874 トレンドキャプチャ戦略

概要

Trendcapture Strategy は、MetaTrader エキスパート アドバイザー MQL/7772/Trendcapture.mq4 の上位レベルの StockSharp 移植です。元の EA は、Parabolic SAR のトレンド方向を監視し、弱い ADX 環境が新しいポジションに入るのを待ちます。取引が終了するたびに、実現利益に応じて取引の方向を維持するか反転するかを決定し、オープンポジションが数ポイント獲得すると、損益分岐点までストップを引きます。

このポートは、StockSharp の順序ヘルパーとインジケーター バインディングに依存しながら、動作をそのまま維持します。すべてのシグナルは、設定可能な時間枠の完了したローソク足で処理されます。

取引ロジック

  1. インジケーターのセットアップ
    • Parabolic SAR (ParabolicSar)、設定可能な加速ステップと上限。
    • メイントレンドの強さの値の平均方向性インデックス (AverageDirectionalIndex)。
  2. エントリーの選択
    • 一度にオープンできるポジションは 1 つだけです。
    • 次の場合に長いエントリが許可されます。
      • 希望の方向 (最後に終了した取引から派生) は買いを指します。
      • 現在のローソク足は SAR の値を上回って終了します。
      • ADX のメインラインは 20 の下にあり、元のコードで必要な測距体制を示しています。
    • 短いエントリーはルールを反映しています(希望の方向は売りを指し、終値は SAR を下回り、ADX は 20 を下回ります)。
  3. 出口管理
    • 約定するたびに、戦略は StopLossPointsTakeProfitPoints の距離 (証券価格ステップを通じて変換) でストップロス注文と利食い注文を送信します。
    • 変動利益が GuardPoints に達すると、損益分岐点の下限を確定するためにエントリー価格でアクティブ ストップが再発行されます。
    • 取引を終了すると方向性の更新がトリガーされます。収益性の高い取引では同じバイアスが維持され、負けまたは横ばいの取引ではバイアスが逆転し、エキスパートからの OrderProfit() チェックが再現されます。

パラメーター

パラメータ 説明 デフォルト
CandleType インジケーターの計算に使用されるローソク足のデータ型。 1時間枠
SarStep 初期加速係数は Parabolic SAR です。 0.02
SarMax Parabolic SAR の最大加速係数。 0.2
AdxPeriod ADXの平滑化期間。 14
TakeProfitPoints 価格ステップで表される利食い距離。 180
StopLossPoints 価格ステップで表されるストップロス距離。 50
GuardPoints ストップを損益分岐点に移動する前に必要な利益しきい値 (価格ステップ単位)。 5
MaximumRisk ボリュームのスケーリング係数。 0.03 は元のロットサイジングを再現します。 0.03

使用上の注意

  • ポイント距離が価格値に正しく変換されるように、選択した証券が PriceStep (または少なくとも MinStep) を公開していることを確認してください。
  • 基本の Volume プロパティは、MaximumRisk0.03 に等しい場合に使用されるロットサイズを表します。リスク係数を増やすと、送信される量も比例して増加します。
  • EA は市場で取引され、すぐに保護注文を発注するため、戦略がアイドル状態のときは帳簿に保留中のエントリが残りません。
  • 損益分岐点ガードは、エントリー価格で保護ストップをキャンセルして再発行します。これは、ストップロスを損益分岐点に移動した元の OrderModify コールを反映しています。

ファイル

  • CS/TrendcaptureStrategy.cs – Trendcapture EA の高レベルの StockSharp 実装。
  • README_zh.md – この文書の中国語翻訳。
  • README_ru.md – この文書のロシア語翻訳。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trendcapture strategy - EMA trend with ADX strength filter.
/// Buys when close is above EMA and ADX indicates trending.
/// Sells when close is below EMA and ADX indicates trending.
/// </summary>
public class TrendcaptureStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _adxPeriod;
	private readonly StrategyParam<decimal> _adxThreshold;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevEma;
	private bool _hasPrev;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int AdxPeriod { get => _adxPeriod.Value; set => _adxPeriod.Value = value; }
	public decimal AdxThreshold { get => _adxThreshold.Value; set => _adxThreshold.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public TrendcaptureStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetDisplay("EMA Period", "EMA lookback", "Indicators");
		_adxPeriod = Param(nameof(AdxPeriod), 14)
			.SetDisplay("ADX Period", "ADX lookback", "Indicators");
		_adxThreshold = Param(nameof(AdxThreshold), 30m)
			.SetDisplay("ADX Threshold", "Minimum ADX for trending", "Levels");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevEma = 0m; _hasPrev = false; }

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;

		var fast = new ExponentialMovingAverage { Length = EmaPeriod };
		var slow = new ExponentialMovingAverage { Length = EmaPeriod * 3 };

		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 (!_hasPrev) { _prevClose = fast; _prevEma = slow; _hasPrev = true; return; }

		if (_prevClose <= _prevEma && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (_prevClose >= _prevEma && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevClose = fast; _prevEma = slow;
	}
}