GitHub で見る

MACD 4 色 2 Martingale 戦略

MACD 4 色 2 Martingale

この戦略では、「MACD Four Colors 2 Martingale」エキスパート アドバイザーを MetaTrader から StockSharp に移植します。 MACD の「色」解釈とマーチンゲール位置サイジング モデルを中心に構築された元のロジックが維持されています。

概要

基本的なインジケーターは、MACD ヒストグラムを 5 色でペイントします。デフォルトの「新しい」配色では、MACD の線がゼロ線の上または下にあるかどうかに応じて、ヒストグラムの色が変わります。エキスパートアドバイザーは、色が銀から黄色に変化するとき(負の MACD が再び下降する)、または赤から青に変化するとき(正の MACD が反転するとき)にポジションをオープンします。 StockSharp バージョンは、MACD の値から色を再構成することで、このシーケンスを再現します。

常に 1 方向の取引バスケットのみがアクティブになります。新しい取引は、その価格が現在のバスケットの平均エントリーを改善する場合にのみ許可されます(ロングの場合は価格が低く、ショートの場合は価格が高くなります)。新しいエントリごとに、最後に充填されたボリュームに設定可能なロット係数を乗算し、元の EA からのマーチンゲール平均を実装します。

取引ルール

  • インジケーター ロジック: クラシック 12/26/9 構成の MovingAverageConvergenceDivergenceSignal インジケーターは、MACD 値を生成します。
  • 色の再構成: この戦略では、最新の 2 つの MACD 値を比較します。負の立ち上がり MACD はカラー 1 (銀) にマッピングされ、正の立ち上がりはカラー 2 (赤) に、正の立ち下がりはカラー 3 (青) に、そして負の立ち下がりはカラー 4 (黄色) にマッピングされます。
  • ロングエントリ: 前のバーの MACD がゼロ未満のままで、再構成された色が 1 から 4 に移動するとトリガーされます。取引はショートエクスポージャーがなく、新しい価格が既存のロングエントリーよりも低い場合にのみ実行されます。
  • 簡単なエントリ: 前のバーの MACD が 0 を超えている間に色が 2 から 3 に移動するとトリガーされます。ロングエクスポージャーがなく、新しい価格が既存のショートエントリーよりも高い場合にのみ取引が開始されます。
  • ボリューム管理: 最初の注文では InitialVolume が使用されます。同じバスケット内の後続の注文はすべて、最後に実行された数量に LotCoefficient を掛けます。係数 ≤ 0 を設定すると、乗算器が無効になります。
  • 損益管理: 変動損益は完成したキャンドルごとに評価されます。 TargetProfit を押すと、すべてのポジションがクローズされ、マーチンゲール サイクルがリセットされます。 MaxDrawdown (損失しきい値として解釈される) に違反すると、すべてが閉じられ、サイクルが再開されます。元のコードと同様に、負のしきい値がサポートされます。
  • ポジションの出口: 目標金額とは別に、自動停止はありません。リスクしきい値に達するか、ユーザーが手動で介入するまで、ポジションはオープンしたままになります。

パラメーター

  • CandleType (DataType、デフォルトは 1h) – MACD 計算の時間枠。
  • InitialVolume (10 進数、デフォルトは 1) – バスケット内の最初の注文の数量。
  • LotCoefficient (10 進数、デフォルト 2) – マーチンゲールがアクティブなときに前のボリュームに適用される乗数。
  • MaxDrawdown (10 進数、デフォルト 50) – 清算を強制する変動損失のしきい値 (金額)。正の値は -MaxDrawdown を監視し、負の値は正確な値を使用します。
  • TargetProfit (10 進数、デフォルトは 150) – バスケットをクローズする変動利益目標 (金額)。負の値は、MQL バージョンと同様に比較を反転します。
  • FastEmaPeriod (int、デフォルト 12) – MACD の高速 EMA の長さ。
  • SlowEmaPeriod (int、デフォルト 26) – MACD の低速 EMA の長さ。
  • SignalPeriod (int、デフォルトは 9) – MACD 平滑化のための信号 EMA の長さ。

使用上の注意

  • 未実現損益は取引所の仕様から計算されるため、PriceStepStepPrice を定義するあらゆる商品で機能します。
  • マーチンゲールサイジングにより、ポジションが急速に拡大する可能性があります。ライブ口座での取引を有効にする前に、リスク制限を検証してください。
  • 視覚的な分析のために、戦略によって作成されたチャート領域を添付します。ローソク足、MACD インジケーター、および実行された取引をプロットします。

カタログフィルター

  • カテゴリ: トレンド/モメンタム平均化
  • 方向: 両方 (長いバスケットと短いバスケット)
  • インジケーター: MACD
  • 停留所: 金銭ベースの降車のみ
  • 時間枠: 設定可能 (デフォルトは 1 時間)
  • 複雑さ: 中級
  • リスク: マーチンゲール法による高リスク
  • 自動化: 一度開始すると完全に自動化されます
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD histogram crossover with martingale volume scaling.
/// Based on the MACD Four Colors 2 Martingale expert advisor.
/// </summary>
public class MacdFourColors2MartingaleStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<decimal> _lotCoefficient;
	private readonly StrategyParam<int> _maxMartingale;

	private MovingAverageConvergenceDivergence _macd;
	private readonly System.Collections.Generic.Queue<decimal> _macdHistory = new();
	private decimal? _prevHistogram;
	private decimal _currentVolume;
	private int _consecutiveLosses;
	private decimal _entryPrice;

	/// <summary>
	/// Type of candles used for MACD analysis.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Period of the fast EMA inside MACD.
	/// </summary>
	public int FastEmaPeriod
	{
		get => _fastEmaPeriod.Value;
		set => _fastEmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the slow EMA inside MACD.
	/// </summary>
	public int SlowEmaPeriod
	{
		get => _slowEmaPeriod.Value;
		set => _slowEmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the signal line.
	/// </summary>
	public int SignalPeriod
	{
		get => _signalPeriod.Value;
		set => _signalPeriod.Value = value;
	}

	/// <summary>
	/// Multiplier applied after a losing trade.
	/// </summary>
	public decimal LotCoefficient
	{
		get => _lotCoefficient.Value;
		set => _lotCoefficient.Value = value;
	}

	/// <summary>
	/// Maximum number of martingale steps before resetting.
	/// </summary>
	public int MaxMartingale
	{
		get => _maxMartingale.Value;
		set => _maxMartingale.Value = value;
	}

	/// <summary>
	/// Initialize strategy parameters.
	/// </summary>
	public MacdFourColors2MartingaleStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles for MACD analysis", "General");

		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 20)
			.SetDisplay("Fast EMA", "Fast EMA period for MACD", "Indicators")
			.SetGreaterThanZero();

		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 50)
			.SetDisplay("Slow EMA", "Slow EMA period for MACD", "Indicators")
			.SetGreaterThanZero();

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

		_lotCoefficient = Param(nameof(LotCoefficient), 1.5m)
			.SetDisplay("Lot Coefficient", "Multiplier after a loss", "Money Management")
			.SetGreaterThanZero();

		_maxMartingale = Param(nameof(MaxMartingale), 5)
			.SetDisplay("Max Martingale", "Maximum consecutive doublings", "Money Management")
			.SetGreaterThanZero();
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevHistogram = null;
		_currentVolume = Volume > 0 ? Volume : 1;
		_consecutiveLosses = 0;
		_entryPrice = 0;
		_macdHistory.Clear();

		_macd = new MovingAverageConvergenceDivergence
		{
			ShortMa = { Length = FastEmaPeriod },
			LongMa = { Length = SlowEmaPeriod }
		};

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

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

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

		_macdHistory.Enqueue(macdValue);
		while (_macdHistory.Count > SignalPeriod)
			_macdHistory.Dequeue();

		if (!_macd.IsFormed || _macdHistory.Count < SignalPeriod)
		{
			_prevHistogram = null;
			return;
		}

		// Calculate signal line (SMA of MACD)
		var sum = 0m;
		var history = _macdHistory.ToArray();
		foreach (var v in history)
			sum += v;
		var signalValue = sum / history.Length;

		var histogram = macdValue - signalValue;

		if (_prevHistogram is null)
		{
			_prevHistogram = histogram;
			return;
		}

		var crossUp = _prevHistogram < 0 && histogram >= 0;
		var crossDown = _prevHistogram >= 0 && histogram < 0;

		if (crossUp)
		{
			// Check for loss on closing short
			if (Position < 0)
			{
				var pnl = _entryPrice - candle.ClosePrice;
				if (pnl < 0)
				{
					_consecutiveLosses++;
					if (_consecutiveLosses <= MaxMartingale)
						_currentVolume *= LotCoefficient;
				}
				else
				{
					_consecutiveLosses = 0;
					_currentVolume = Volume > 0 ? Volume : 1;
				}

				BuyMarket(Math.Abs(Position) + _currentVolume);
				_entryPrice = candle.ClosePrice;
			}
			else if (Position == 0)
			{
				BuyMarket(_currentVolume);
				_entryPrice = candle.ClosePrice;
			}
		}
		else if (crossDown)
		{
			// Check for loss on closing long
			if (Position > 0)
			{
				var pnl = candle.ClosePrice - _entryPrice;
				if (pnl < 0)
				{
					_consecutiveLosses++;
					if (_consecutiveLosses <= MaxMartingale)
						_currentVolume *= LotCoefficient;
				}
				else
				{
					_consecutiveLosses = 0;
					_currentVolume = Volume > 0 ? Volume : 1;
				}

				SellMarket(Math.Abs(Position) + _currentVolume);
				_entryPrice = candle.ClosePrice;
			}
			else if (Position == 0)
			{
				SellMarket(_currentVolume);
				_entryPrice = candle.ClosePrice;
			}
		}

		_prevHistogram = histogram;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_macd = null;
		_prevHistogram = null;
		_currentVolume = 0;
		_consecutiveLosses = 0;
		_entryPrice = 0;
		_macdHistory.Clear();

		base.OnReseted();
	}
}