GitHub で見る

ADX シンプルなトレンド戦略

概要

ADX シンプル トレンド戦略 は、古典的な MetaTrader エキスパート アドバイザー「ADX シンプル」の直接移植です。これは、正と負の方向性の動き指標 (DI+ と DI-) を比較し、取引を開始する前に ADX のメインラインが上昇することを要求することにより、平均方向性指標 (ADX) の方向に従います。 StockSharp バージョンは、元のシステムの最小限の性質を維持しながら、高レベルの API パターンとリスク管理に適応させます。

インジケータースタック

  • 平均方向性インデックス (ADX) 構成可能な期間 (デフォルトは 25)。
    • トレンドの強さを確認するために使用される メインの ADX ラインを提供します。
    • 強気または弱気の優位性を定義する DI+ および DI- 値を提供します。
  • タイムフレームは、CandleType を通じて選択できます (デフォルトは 15 分のローソク足です)。

信号の生成

ロングエントリー

  1. キャンドルが完成し、ADX の値が確定するまで待ちます。
  2. 同じバー上で DI+ が DI- より上にあることを確認します。
  3. ADX メインラインが以前の値よりも厳密に大きいことが必要です (傾向は強化されています)。
  4. オープンポジションが存在しない場合は、ストラテジーボリュームを使用して成行買い注文を送信します。

ショートエントリー

  1. キャンドルが点灯し、ADX の測定値が確定するまで待ちます。
  2. DI- が DI+ より大きいことを確認します。
  3. ADX の主線は以前の値より大きくする必要があります。
  4. 横ばいの場合は、戦略ボリュームで成行売り注文を送信します。

終了ロジック

  • ロングクローズ: DI- が DI+ を上回ったとき (トレンドの勢いが弱気に変わる)。
  • ショートで決済: DI+ が DI- を上回った場合 (トレンドの勢いが強気に変わる)。
  • ADX のスロープ チェックはエグジットには必要なく、DI クロスオーバーの直後にポジションをクローズした元の EA を反映しています。

ポジション管理

  • 戦略は常にフラット、ロング、ショートのいずれかです。両方向で同時に位置を保持することはありません。
  • 成行注文は、組み込みの Strategy.Volume プロパティ (デフォルトは 1) を使用してサイズ設定されます。インストゥルメントのサイズに一致するようにストラテジ インスタンスを設定するときに、このプロパティを調整します。
  • 自動ストップロス注文や利食い注文はありません。リスクは外部から、または戦略を変更することによって制御する必要があります。

パラメーター

パラメータ 種類 デフォルト 説明
AdxPeriod int 25 ADX、DI+、および DI- 計算のルックバック長。
CandleType DataType 15分の時間枠 インジケーターの計算を促進するためにキャンドルのサブスクリプションが使用されます。

オリジナルの MQL バージョンとの違い

  • 資金管理: 元の EA は口座残高に基づいてロットのサイズを変更しました。 StockSharp 戦略は Strategy.Volume を使用し、資本管理をホスティング環境に任せます。
  • 注文追跡: MetaTrader 注文プールを反復処理する代わりに、StockSharp は組み込みの Position 値に依存します。
  • データ処理: この戦略は未完成のローソク足を無視し、完成したデータのみを取引します。
  • ロギングと視覚化のフックは、デバッグを容易にするために、CreateChartAreaDrawCandles、および DrawIndicator ヘルパーを通じて利用できます。

使用ガイドライン

  1. 十分なトレンドの動きがある商品 (FX メジャーやインデックスなど) に戦略を付加します。
  2. 戦略を開始する前に、パラメータを通じて希望のローソクのタイプと ADX の長さを設定します。
  3. オプションで、ホスティング アプリケーションを通じてポートフォリオ レベルのリスク管理 (ストップアウト、ドローダウン制限) を有効にします。
  4. チャート ビジュアライザで DI クロスオーバーと ADX の傾きを監視して、動作を確認します。

戦略の拡張

  • ボラティリティ フィルター (ATR、標準偏差) を追加して、低ボラティリティ状態を回避します。
  • StartProtection または ProcessCandle のカスタム注文ロジックを呼び出して、ストップロス/テイクプロフィットの自動化を導入します。
  • 追加のローソク足ストリームをサブスクライブして、より高いタイムフレーム フィルターと組み合わせます。

このドキュメントは、ADX シンプル トレンド戦略の包括的な概要を提供し、StockSharp フレームワーク内で安全に展開および拡張できるようにすることを目的としています。

using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// ADX Simple: Trend following with EMA crossover and ATR momentum filter.
/// </summary>
public class AdxSimpleStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public AdxSimpleStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastEmaLength = Param(nameof(FastEmaLength), 10)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowEmaLength = Param(nameof(SlowEmaLength), 30)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

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

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

	public int FastEmaLength
	{
		get => _fastEmaLength.Value;
		set => _fastEmaLength.Value = value;
	}

	public int SlowEmaLength
	{
		get => _slowEmaLength.Value;
		set => _slowEmaLength.Value = value;
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
	}

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

		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };

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

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

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

		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (fastVal < slowVal && _prevFast >= _prevSlow)
			{
				SellMarket();
				_entryPrice = 0;
			}
			else if (close <= _entryPrice - atrVal * 2m)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow)
			{
				BuyMarket();
				_entryPrice = 0;
			}
			else if (close >= _entryPrice + atrVal * 2m)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (fastVal < slowVal && _prevFast >= _prevSlow)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}