GitHub で見る

MACD Simple Reshetov 戦略

概要

この戦略は、StockSharp フレームワーク内で Yury Reshetov の「MACDSimple」MetaTrader エキスパートアドバイザーの動作を再現します。単一の証券を扱い、2 つのオフセットパラメーターで修正された古典的な MACD シグナルを評価します。アルゴリズムは完成したローソク足のみを処理し、すべての取引決定が確認されたデータで行われることを保証し、バー内のノイズを避けます。

インジケーターと計算

  • MACD (Moving Average Convergence Divergence) – MACD ラインとシグナルラインはカスタム期間で計算されます:
    • 速い EMA 期間 = SignalPeriod + DF
    • 遅い EMA 期間 = SignalPeriod + DS + DF
    • シグナルライン期間 = SignalPeriod オフセット DFDS は元のエキスパートの入力に従い、トレーダーが MACD コンポーネントを引き伸ばしたり圧縮したりしながら、それらの関係を保持できます。

パラメーター

名前 説明 デフォルト
Volume 各成行エントリーに使用される注文サイズ。 2
DF 速い MACD EMA の長さに追加されるオフセット。ゼロまたは正でなければなりません。 1
DS 遅い MACD EMA の長さに適用される追加オフセット。ゼロまたは正でなければなりません。 2
SignalPeriod 速いおよび遅い EMA の長さが導出される基本期間。 10
CandleType 分析と取引に使用されるローソク足の時間軸。 30 分足の時間軸

取引ロジック

ポジション処理

  1. 完成した各ローソク足で、戦略は MACD インジケーターを更新し、インジケーターがまだ完全に形成されていない場合はバーを無視します。
  2. ロングポジションが開いていて MACD ラインがゼロを下回った場合、戦略は市場価格でロングポジション全体をクローズします。
  3. ショートポジションが開いていて MACD ラインがゼロを上回った場合、戦略は市場価格でショートポジション全体をクローズします。
  4. 指定されたバーでポジションをクローズした後、アルゴリズムはそのバーの処理を停止し、元のエキスパートアドバイザーの動作を反映します。

エントリールール

  1. アルゴリズムは MACD ラインとシグナルラインが同じ符号を共有していることを確認します(両方とも正または両方とも負)。符号が混在する場合はトレードが生成されません。
  2. 両方のラインがのとき、MACD ラインがシグナルラインを上回っていればロングポジションが開かれます。
  3. 両方のラインがのとき、MACD ラインがシグナルラインを下回っていればショートポジションが開かれます。
  4. 成行注文は設定された Volume パラメーターのサイズになります。一度に 1 つのポジションのみが存在できます。

エグジットルール

  • 出口は、ポジション処理セクションで説明されているように、MACD ラインがオープンポジションに対してゼロレベルを交差することによってのみ駆動されます。デフォルトでは部分的な出口、ストップロス、またはテイクプロフィットは実装されていません。

補足事項

  • 戦略は IsFormedAndOnlineAndAllowTrading() が満たされた場合のみ取引し、新しいポジションに入る前にライブデータが利用可能で取引が有効であることを確認します。
  • 自動リスク管理は組み込まれていません。ユーザーは必要に応じて StartProtection() などのカスタム保護を追加したり、戦略をポートフォリオレベルのリスクコントロールと組み合わせたりできます。
  • MACD パラメーターは単一の基本期間にオフセットを加えて導出されるため、SignalPeriodDF、または DS を調整するとすべてのコンポーネントに同時に影響し、元のエキスパートアドバイザーが意図した相対的な間隔を保持します。

実装の詳細

  • インジケーターのバインディングは StockSharp の高レベル SubscribeCandles().Bind() API を使用し、実装を簡潔でイベント駆動型に保ちます。
  • 変換は AGENTS.md に記述されたルールセットに従います:インデントにはタブを使用し、インジケーター値はバインディングコールバックから直接消費され、取引関数 BuyMarket/SellMarket がエントリーとエグジットを管理します。
  • 戦略構造は拡張の準備ができており(例えばフィルターやリスクロジックの追加)、元の MetaTrader エキスパートロジックに忠実であり続けます。
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD-based strategy adapted from Yury Reshetov's MACDSimple expert advisor.
/// </summary>
public class MacdSimpleReshetovStrategy : Strategy
{
	private readonly StrategyParam<int> _df;
	private readonly StrategyParam<int> _ds;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private MovingAverageConvergenceDivergenceSignal _macd;

	public int Df { get => _df.Value; set => _df.Value = value; }
	public int Ds { get => _ds.Value; set => _ds.Value = value; }
	public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MacdSimpleReshetovStrategy()
	{

		_df = Param(nameof(Df), 1)
			.SetNotNegative()
			.SetDisplay("DF", "Offset for the fast EMA", "Indicators");

		_ds = Param(nameof(Ds), 2)
			.SetNotNegative()
			.SetDisplay("DS", "Offset for the slow EMA", "Indicators");

		_signalPeriod = Param(nameof(SignalPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Signal Period", "Signal line period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

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

		// The MQL version derives MACD periods from the signal period with DF and DS offsets.
		var fastPeriod = SignalPeriod + Df;
		var slowPeriod = SignalPeriod + Ds + Df;

		_macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd = { ShortMa = { Length = fastPeriod }, LongMa = { Length = slowPeriod } },
			SignalMa = { Length = SignalPeriod }
		};

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

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

		var result = _macd.Process(candle);
		if (!_macd.IsFormed)
			return;

		var macdValue = result as MovingAverageConvergenceDivergenceSignalValue;
		if (macdValue == null)
			return;

		var macdLine = macdValue.Macd ?? 0m;
		var signalLine = macdValue.Signal ?? 0m;

		// Manage existing positions before evaluating new signals.
		if (Position > 0)
		{
			if (macdLine < 0m)
				SellMarket(Position);

			return;
		}

		if (Position < 0)
		{
			if (macdLine > 0m)
				BuyMarket(-Position);

			return;
		}

		// Enter only when MACD and signal lines share the same sign.
		if (macdLine * signalLine <= 0m)
			return;

		if (macdLine > 0m && macdLine > signalLine)
		{
			BuyMarket(Volume);
		}
		else if (macdLine < 0m && macdLine < signalLine)
		{
			SellMarket(Volume);
		}
	}
}