GitHub で見る

TrueSort 1001 戦略

TrueSort 1001 は、オリジナルの MQL エキスパート アドバイザーを反映した厳密なトレンド追跡システムです。この戦略は 5 つの単純な移動平均を監視し、それらが 3 つの連続する完成したローソク足で完全に順序付けられている場合にのみ機能します。平均方向性指数 (ADX) の上昇は、取引が開始される前に勢いを確認します。市場に入ると、ポジションは価格ステップで測定される適応型トレーリングストップによって保護され、移動平均が整合性を失うとすぐに取引が終了します。

ロジック

トレンドと勢いのフィルター

  • 選択した時間枠で 5 つの SMA (デフォルトでは 10、20、50、100、200 期間) が計算されます。
  • 長いセットアップの場合、高速 SMA は、最後の 3 つの完了したローソク足のそれぞれで、低速 SMA より厳密に上になければなりません: SMA10 > SMA20 > SMA50 > SMA100 > SMA200
  • 短いセットアップの場合は、同じ 3 つのキャンドルに対して逆の順序が必要です。
  • 期間 AdxPeriod の ADX は AdxThreshold を上回っており、トレンドの強さが確実に増加していることを確認するために、現在の値が前のローソク足よりも高くなければなりません。

エントリー条件

  1. 開いているポジションはありません。
  2. 3 つのヒストリカル ローソク足が上記の順序ルールを満たしています。
  3. ADX フィルターは合格しました。
  4. Volume ロットの成行注文は、現在のローソク足の終値と同時に送信されます。

終了条件

  • 移動平均の非同期: 現在のローソク足が閉じ、MA スタックが取引の方向に厳密に順序付けされなくなった場合、ポジションは清算されます。
  • トレーリングプロテクション: StopLossPoints は商品 PriceStep を乗算することで絶対価格距離に変換されます。ロングトレードの場合、ストップは SMA100Close - distance の間の最大値で初期化されます。ショートパンツの場合、SMA100Close + distance の間の最小値です。すべてのローソク足の後、ストップは価格に向けて締められますが、緩むことはありません。価格がストップを越えた場合、ポジションは市場でクローズされます。

追加の注意事項

  • すべての決定は完成したキャンドルに対してのみ行われます。未完成のキャンドルは無視されます。
  • このアルゴリズムは、インジケーター履歴を要求せずに、元の MQL スクリプトから shift ロジックを複製するために、最後の 3 つの SMA 値を内部的に保存します。
  • ADX の値は BindEx を介して処理され、戦略がオンラインでデータが完全に形成されている場合にのみ取引が試行されます。

パラメーター

名前 デフォルト 説明
Volume 0.1 市場参入ごとのロット単位での注文サイズ。
StopLossPoints 100 商品の価格ステップで表されるトレーリングストップ距離。 0 は末尾を無効にします。
Sma10Length 10 最速の SMA の期間。
Sma20Length 20 2 番目の SMA の期間。
Sma50Length 50 媒体 SMA の期間。
Sma100Length 100 アライメントと初期停止基準の両方に使用される期間。
Sma200Length 200 最も遅い SMA は長期的な傾向を裏付けています。
AdxPeriod 14 ADX インジケーターの期間。
AdxThreshold 25 エントリの前に最小の ADX レベルと上昇条件が必要です。
CandleType TimeSpan.FromHours(1).TimeFrame() すべてのインジケーターの計算に使用されるローソク足シリーズ。

実装の詳細

  • このコードは、高レベルの StockSharp キャンドル サブスクリプションに依存し、6 つのインジケーター (5 つの SMA と ADX) を単一のパイプラインにバインドします。
  • 長さ 3 の履歴バッファには最新の SMA 値が保存され、GetValue() の呼び出しを回避しながら、MQL シフトとの正確なパリティを維持します。
  • トレーリングストップは手動で管理されます。 StartProtection() はまだアクティブ化されているため、さらなる保護が必要な場合でも標準インフラストラクチャの準備が整っています。
  • コード内のコメントでは、メンテナンスを容易にするために各ステップを英語で説明しています。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trend-following strategy requiring strict moving average alignment
/// and rising volatility (ATR) before entering trades.
/// Exits when alignment is lost.
/// </summary>
public class TrueSort1001Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _midLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevMid;
	private decimal _prevSlow;
	private decimal _prevAtr;
	private decimal _entryPrice;

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

		_fastLength = Param(nameof(FastLength), 10)
			.SetDisplay("Fast SMA", "Fast SMA period.", "Indicators");

		_midLength = Param(nameof(MidLength), 50)
			.SetDisplay("Mid SMA", "Medium SMA period.", "Indicators");

		_slowLength = Param(nameof(SlowLength), 200)
			.SetDisplay("Slow SMA", "Slow SMA period.", "Indicators");

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

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

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int MidLength
	{
		get => _midLength.Value;
		set => _midLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

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

	/// <inheritdoc />
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0;
		_prevMid = 0;
		_prevSlow = 0;
		_prevAtr = 0;
		_entryPrice = 0;
	}

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

		_prevFast = 0;
		_prevMid = 0;
		_prevSlow = 0;
		_prevAtr = 0;
		_entryPrice = 0;

		var fast = new SimpleMovingAverage { Length = FastLength };
		var mid = new SimpleMovingAverage { Length = MidLength };
		var slow = new SimpleMovingAverage { Length = SlowLength };
		var atr = new AverageTrueRange { Length = AtrLength };

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

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

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

		if (_prevFast == 0 || _prevMid == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevMid = midVal;
			_prevSlow = slowVal;
			_prevAtr = atrVal;
			return;
		}

		var close = candle.ClosePrice;
		var bullishAligned = fastVal > midVal && midVal > slowVal;
		var bearishAligned = fastVal < midVal && midVal < slowVal;
		var atrRising = atrVal > _prevAtr;

		// Exit on alignment lost
		if (Position > 0 && !bullishAligned)
		{
			SellMarket();
		}
		else if (Position < 0 && !bearishAligned)
		{
			BuyMarket();
		}

		// Entry on alignment + rising ATR
		if (Position == 0)
		{
			if (bullishAligned && atrRising && close > fastVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (bearishAligned && atrRising && close < fastVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevMid = midVal;
		_prevSlow = slowVal;
		_prevAtr = atrVal;
	}
}