GitHub で見る

ロボット ADX + 2 MA 戦略

概要

ロボット ADX + 2 MA 戦略は、MetaTrader のエキスパート Robot_ADX+2MA の StockSharp 移植です。このシステムは高速と低速を組み合わせています。 平均方向指数 (ADX) の +DI/-DI コンポーネントを使用した指数移動平均。注文は次の場合にのみオープンされます。 前のローソク足は十分に広い EMA の分離を示しており、現在のローソク足は方向性インデックスを通じて勢いを確認します。の 変換では、一度に最大 1 つの市場ポジションをオープンし、エグジットをストップロスとストップロスに委任するという元の動作が維持されます。 テイクプロフィット保護。

取引ロジック

  1. CandleType を通じて設定されたプライマリ キャンドル シリーズをサブスクライブし、完成したキャンドルのみを処理します。
  2. ローソク足の終値を使用して 2 つの指数移動平均 (期間 5 と 12) を入力します。前のローソク足からの値 MetaTrader で使用される shift = 1 ルックバックをエミュレートします。
  3. 同じローソク足で AverageDirectionalIndex インジケーター (期間 6) をフィードします。現在と以前の +DI/-DI の両方を保存する EA フィルターを複製するための読み取り値。
  4. 前のローソク足からの絶対距離 EMA を計算し、ポイントから変換された DifferenceThreshold と比較します。 価格単位 (MetaTrader の Point は StockSharp の Security.PriceStep と等しい)。
  5. 強気エントリー: オープンポジションがなく、以下の条件が満たされる場合にのみ許可されます:
    • 以前の高速な EMA は、前の低速な EMA を下回っています。
    • 以前の +DI は 5 未満、現在の +DI は 10 を超え、+DI は -DI よりも強いです。
    • EMA 距離は設定されたしきい値を超えています。
  6. 弱気エントリー: ロング ルールと対称で、低速 EMA よりも前の高速 EMA が必要で、-DI フィルターは 満足し、-DI が +DI を支配します。
  7. 取引が開始されると、StartProtection によって開始されたリスク モジュールに依存して、テイクプロフィットまたはストップロスを介して取引を終了します。マニュアルなし 元のエキスパートと一致する終了ルールが追加されます。

パラメーター

名前 種類 デフォルト 説明
CandleType DataType 1分間の時間枠 戦略によって処理されたプライマリーキャンドルシリーズ。
TakeProfitPoints int 4700 価格ステップで表されるテイクプロフィットターゲットまでの距離。無効にするには、ゼロに設定します。
StopLossPoints int 2400 価格ステップにおけるストップロスターゲットの距離。無効にするには、ゼロに設定します。
TradeVolume decimal 0.1 すべての成行注文に使用される正味出来高。
DifferenceThreshold int 10 信号が受け入れられるまでに必要な最小距離 EMA (価格ステップ単位)。

リスク管理

  • StockSharp バージョンは、UnitTypes.Step を使用して StartProtection を呼び出すため、設定されたストップロスとテイクプロフィットの距離は次のようになります。 ブローカーの価格ステップに自動的に変換されます。
  • 保護注文は市場終了 (useMarketOrders = true) として生成され、市場の即時決済動作を再現します。 MQL ヘルパー関数。

実装の詳細

  • インジケーター バインディングは高レベルの SubscribeCandles(...).Bind(...).BindEx(...) API を使用するため、手動のデータ ループは必要ありません。
  • 前のローソク足の EMA 値は、元の EA での iMA(..., shift = 1) 呼び出しを再現するためにキャッシュされます。
  • ADX データは AverageDirectionalIndexValue を通じて消費され、呼び出しを行わずに +DI コンポーネントと -DI コンポーネントに直接アクセスできます。 GetValue のヘルパーは禁止されています。
  • キャンドルごとのガード (_lastProcessedTime) により、EMA と ADX の両方のバインディングがトリガーされた場合でも、シグナルが 1 回だけ評価されることが保証されます 同じキャンドルのコールバック。

MetaTrader エキスパートとの違い

  • MQL コードの sell ブランチに存在する冗長な直接の OrderSend 呼び出しは削除されています。双方向で 1 つを使用する BuyMarket/SellMarket ヘルパー。
  • MetaTrader は注文を送信する前に無料証拠金を確認します。 StockSharp ポートはリスク制御をホスティング環境に委任し、 十分なバランスを想定しています。
  • 保護ロジックは、OrderSend を繰り返し呼び出すカスタム ループではなく、StockSharp のリスク マネージャーを介して実装されます。

使い方のヒント

  • ライブ取引を開始する前に、選択した証券のロットステップを尊重するように TradeVolume を調整します。
  • 市場で異なる価格スケールが使用されている場合は、EMA が 分離は MetaTrader 構成と同等です。
  • デフォルトの時間枠は 1 分ですが、CandleType パラメータを使用すると、データでサポートされている他のシリーズに切り替えることができます。 ソース。

インジケーター

  • ExponentialMovingAverage(5)は終値に基づいて計算されます。
  • ExponentialMovingAverage(12)は終値に基づいて計算されます。
  • AverageDirectionalIndex(6) は +DI/-DI および ADX 強度フィルターを提供します。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RobotADX2MA: Dual EMA crossover with RSI confirmation and ATR stops.
/// </summary>
public class RobotAdxTwoMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

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

	public RobotAdxTwoMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_fastEmaLength = Param(nameof(FastEmaLength), 5)
			.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
		_slowEmaLength = Param(nameof(SlowEmaLength), 12)
			.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI 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 RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

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

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

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fastEma, slowEma, rsi, 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 rsiVal, 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) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
		}

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