GitHub で見る

ダイバージェンストレーダーバスケット戦略

概要

この戦略は、「Divergence Trader」MetaTrader エキスパート アドバイザーの StockSharp 移植です。 2 つの単純な移動平均を比較します。 設定可能な価格ソースに基づいて計算され、その差(乖離)が測定されます。速いものと遅いものの間に距離があるとき 平均が中立コリドー内にある場合、アルゴリズムは勢いが回復しようとしていると想定し、ポジションをオープンします。 一般的なバイアスの方向。この実装では、選択したタイムフレームの完了したローソク足のみを使用し、 インジケーター バインディングを備えた高レベルの API。

パラメーター

  • ロットサイズ – 新しいポジションごとに送信された取引量。値は楽器の音量ステップに合わせられます。
  • 高速 SMA 期間 / 価格 – 高速移動平均の長さと価格のソース。
  • 遅い SMA 期間 / 価格 – 遅い移動平均の長さと価格のソース。
  • 買いの閾値 – ロングポジションを開く前に最小限のプラスの発散が必要です。
  • ステイアウトしきい値 – 新規エントリーに許容される最大乖離。この範囲外の値は取引を無効にします。
  • 利益獲得 (pips) – 利益目標は pips で表されます。ゼロに設定すると無効になります。
  • ストップロス (pips) – 損失許容度 (pips)。ゼロに設定すると無効になります。
  • トレーリングストップ (pips) – トレードで利益が出た後に有効になるトレーリング距離。ゼロの場合は無効になります。
  • 損益分岐点トリガー / バッファー (pips) – 損益分岐点でのポジションを保護する前に必要なピップ ゲインとオプションのバッファー エントリー価格から損益分岐点を相殺します。
  • バスケット利益 / バスケット損失 – 口座資本ベースのしきい値で、到達するとすべてのポジションがフラットになります。ロスコントロールというのは、 デフォルトでは無効になっています。
  • 開始時間 / 終了時間 – 現地時間の取引ウィンドウ。両方の値が等しい場合、戦略は一日中機能します。
  • ローソク足タイプ – シグナル生成とリスク管理の両方に使用されるタイムフレーム。

取引ロジック

  1. 構成されたローソク足シリーズをサブスクライブし、高速および低速の単純移動平均を計算します。
  2. バー内のノイズを回避し、元の EA の動作に近づけるため、完成したキャンドルのみを使用してください。
  3. 以前に終了したローソク足で計算された発散 (速いマイナス遅い) を追跡します。
    • 乖離がプラスで、買い閾値ステイアウト閾値の間に残っている場合は、成行買い注文を送信します。
    • 乖離がマイナスで、その絶対値がコリドー内に留まっている場合は、成行売り注文を送信します。
  4. 許可された時間外、またはストラテジーにすでにオープンポジションがある場合、取引は無視されます。

ポジション管理

  • 損益分岐点制御 – 変動利益がトリガーに達すると、戦略は損益分岐点のストップレベルを保存します(オプション) バッファによってシフトされます)。このレベルに触れたローソク足はポジションを閉じます。
  • トレーリングストップ – 利益がトレーリング距離を超えると、ストップレベルは常に最も有利な価格に従います。 設定されたピップス数だけ後ろに留まります。
  • テイクプロフィット/ストップロス – エントリー価格からピップ単位で計算された固定エグジット。
  • バスケット プロテクション – ポートフォリオの資本が、設定された損益制限と比較されます。いずれかの境界に到達する 現在のポジションをクローズし、アクティブな注文をキャンセルし、MQL バージョンの「CloseEverything」ルーチンをエミュレートします。

使用上の注意

  • 発散コリドーは対称的です。ステイアウトしきい値を広げると、取引をより長く開いたままにすることができますが、その値を狭めることはできません。 信号の周波数が増加します。
  • 価格ソースのオプションは StockSharp CandlePrice の値に対応しており、始値、終値、中央値、または標準値を使用できます。 価格は MetaTrader と同様です。
  • この戦略は、監視とデバッグのためにチャート領域に移動平均と約定注文の両方のローソク足をプロットします。
  • 資金管理機能はポートフォリオ データに依存します。ポートフォリオ統計のないサンドボックスで実行すると、バスケット コントロールは 自動的に無視されます。
using System;
using System.Linq;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Divergence-based strategy converted from the Divergence Trader MQL expert advisor.
/// Trades based on the divergence between fast and slow moving averages.
/// </summary>
public class DivergenceTraderBasketStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<decimal> _buyThreshold;
	private readonly StrategyParam<decimal> _stayOutThreshold;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _previousDifference;
	private decimal _entryPrice;

	public DivergenceTraderBasketStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 7)
			.SetDisplay("Fast SMA Period", "Length of the fast simple moving average.", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 88)
			.SetDisplay("Slow SMA Period", "Length of the slow simple moving average.", "Indicators");

		_buyThreshold = Param(nameof(BuyThreshold), 0.0001m)
			.SetDisplay("Buy Threshold", "Minimum divergence value required before buying.", "Signals");

		_stayOutThreshold = Param(nameof(StayOutThreshold), 1000m)
			.SetDisplay("Stay-Out Threshold", "Upper divergence limit that disables new entries.", "Signals");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Primary timeframe used for calculations.", "General");
	}

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

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

	public decimal BuyThreshold
	{
		get => _buyThreshold.Value;
		set => _buyThreshold.Value = value;
	}

	public decimal StayOutThreshold
	{
		get => _stayOutThreshold.Value;
		set => _stayOutThreshold.Value = value;
	}

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

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

		_previousDifference = null;
		_entryPrice = 0;
	}

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

		_previousDifference = null;
		_entryPrice = 0;

		var fastMa = new SimpleMovingAverage { Length = FastPeriod };
		var slowMa = new SimpleMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastMa, slowMa, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var currentDiff = fastValue - slowValue;

		if (_previousDifference == null)
		{
			_previousDifference = currentDiff;
			return;
		}

		var prevDiff = _previousDifference.Value;
		_previousDifference = currentDiff;

		// Manage open position
		if (Position != 0)
		{
			// Exit on divergence sign change
			if (Position > 0 && currentDiff < 0)
			{
				SellMarket();
				_entryPrice = 0;
			}
			else if (Position < 0 && currentDiff > 0)
			{
				BuyMarket();
				_entryPrice = 0;
			}
			return;
		}

		// Entry logic: divergence crosses zero line
		if (currentDiff > 0 && prevDiff <= 0)
		{
			// Bullish divergence crossover
			BuyMarket();
			_entryPrice = candle.ClosePrice;
		}
		else if (currentDiff < 0 && prevDiff >= 0)
		{
			// Bearish divergence crossover
			SellMarket();
			_entryPrice = candle.ClosePrice;
		}
	}
}