GitHub で見る

ダイバージェンス MACD Stochastic 戦略

この戦略は、MetaTrader 5 エキスパート アドバイザー 「Divergence EA pip sl tp」 を StockSharp フレームワークで再作成します。このアルゴリズムは、価格変動と MACD ヒストグラムの間の古典的な乖離を検索し、反転取引を開始する前に買われすぎ/売られすぎの Stochastic オシレーター フィルターでシグナルを検証します。

取引ロジック

  1. CandleType パラメータで選択されたプライマリ タイムフレーム ローソク足をサブスクライブします。
  2. 完成したすべてのローソクの MACD ヒストグラム (MACD line - Signal line) と Stochastic %K/%D 値を計算します。
  3. 価格とヒストグラム値の両方の最新の 2 つのスイング高値と安値を追跡します。
  4. 弱気ダイバージェンス: MACD ヒストグラムのピークの低下と StochasticUpperLevel の Stochastic %K を伴う新たな高値により、ショート ポジションがトリガーされるか、既存のロングが反転します。
  5. 強気の発散: MACD ヒストグラムの谷が高く、%K が StochasticLowerLevel を下回る新たな安値がオープンまたはリバースしてロングポジションになります。
  6. オプションの保護 TakeProfitStepsStopLossSteps は、StockSharp ステップ ユニットに変換され、戦略開始時に 1 回有効になります。

実装メモ

  • MovingAverageConvergenceDivergenceSignal および StochasticOscillator インジケーターにバインドされた単一のローソク足サブスクリプションを使用して、StockSharp の高レベルの API で構築されています。
  • 変換ガイドラインに従い、インジケーター GetValue ヘルパーを呼び出さずに発散状態を維持します。
  • チャート統合では、チャート領域が使用可能な場合、価格ローソク足、MACD、および Stochastic 線が表示されます。
  • 位置は、絶対的な現在位置のサイズをベース Volume に加算することによって反転され、発散が確認された後に即座に方向が変更されることが保証されます。

パラメーター

パラメータ 説明 デフォルト
CandleType 発散の計算に使用される時間枠。 1時間キャンドル
MacdFastLength, MacdSlowLength, MacdSignalLength 元の EA 入力を複製する MACD EMA の長さ。 12/26/9
MacdDivergenceThreshold 発散を確認するために必要な、連続するスイング間のヒストグラムの差の最小値。 0.0005
StochasticLength Stochastic オシレーターの高速 %K 周期。 50
StochasticSlowK, StochasticSlowD EA 構成をミラーリングする追加の %K/%D スムージング長。 9/9
StochasticUpperLevel, StochasticLowerLevel 弱気/強気の設定を検証する買われすぎと売られすぎのフィルター。 80 / 20
TakeProfitSteps, StopLossSteps 価格ステップで表されるオプションの保護距離 (0 はレベルを無効にします)。 50

使用法

  1. 選択した時間枠をサポートする証券を使用して、戦略を StockSharp コネクタに接続します。
  2. 基本の Volume プロパティを通じてポジション サイズを設定し、必要に応じてインジケーター設定を調整します。
  3. 戦略を開始します。発散条件と Stochastic 条件が満たされるたびに注文が自動的に生成されます。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Divergence MACD Stochastic" MetaTrader expert.
/// Uses MACD histogram divergence (price vs histogram) with RSI confirmation.
/// MACD is computed manually from two EMAs.
/// </summary>
public class DivergenceMacdStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdFast;
	private readonly StrategyParam<int> _macdSlow;
	private readonly StrategyParam<int> _rsiPeriod;

	// Manual EMA for MACD
	private decimal _fastEma;
	private decimal _slowEma;
	private bool _emaInitialized;
	private int _barCount;
	private decimal _fastMultiplier;
	private decimal _slowMultiplier;

	private readonly decimal[] _macdWindow = new decimal[DivergenceLookback];
	private readonly decimal[] _priceWindow = new decimal[DivergenceLookback];
	private int _windowCount;
	private int _windowIndex;
	private const int DivergenceLookback = 10;

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

	public int MacdFast
	{
		get => _macdFast.Value;
		set => _macdFast.Value = value;
	}

	public int MacdSlow
	{
		get => _macdSlow.Value;
		set => _macdSlow.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public DivergenceMacdStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for divergence detection", "General");

		_macdFast = Param(nameof(MacdFast), 20)
			.SetGreaterThanZero()
			.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");

		_macdSlow = Param(nameof(MacdSlow), 50)
			.SetGreaterThanZero()
			.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
	}

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

		_windowCount = 0;
		_windowIndex = 0;
		_emaInitialized = false;
		_barCount = 0;
		_fastMultiplier = 2m / (MacdFast + 1);
		_slowMultiplier = 2m / (MacdSlow + 1);

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

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

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

		var close = candle.ClosePrice;
		_barCount++;

		// Manual EMA computation
		if (!_emaInitialized)
		{
			_fastEma = close;
			_slowEma = close;
			_emaInitialized = true;
		}
		else
		{
			_fastEma = close * _fastMultiplier + _fastEma * (1 - _fastMultiplier);
			_slowEma = close * _slowMultiplier + _slowEma * (1 - _slowMultiplier);
		}

		if (_barCount < MacdSlow)
			return;

		var macdLine = _fastEma - _slowEma;

		_macdWindow[_windowIndex] = macdLine;
		_priceWindow[_windowIndex] = close;
		_windowIndex = (_windowIndex + 1) % DivergenceLookback;
		if (_windowCount < DivergenceLookback)
			_windowCount++;

		if (_windowCount < DivergenceLookback)
			return;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var oldestIndex = _windowIndex;
		var newestIndex = (_windowIndex + DivergenceLookback - 1) % DivergenceLookback;
		var oldMacd = _macdWindow[oldestIndex];
		var newMacd = _macdWindow[newestIndex];
		var oldPrice = _priceWindow[oldestIndex];
		var newPrice = _priceWindow[newestIndex];

		var minPriceMove = oldPrice * 0.005m;
		// Bullish divergence: price makes lower low but MACD makes higher low.
		var bullishDiv = newPrice < oldPrice - minPriceMove && newMacd > oldMacd;
		// Bearish divergence: price makes higher high but MACD makes lower high.
		var bearishDiv = newPrice > oldPrice + minPriceMove && newMacd < oldMacd;

		if (bullishDiv)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (bearishDiv)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}
	}

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

		_fastEma = 0;
		_slowEma = 0;
		_emaInitialized = false;
		_barCount = 0;
		_fastMultiplier = 0;
		_slowMultiplier = 0;
		Array.Clear(_macdWindow, 0, _macdWindow.Length);
		Array.Clear(_priceWindow, 0, _priceWindow.Length);
		_windowCount = 0;
		_windowIndex = 0;
	}
}