Auf GitHub ansehen

Macd Pattern Trader DoubleTop-Strategie

Überblick

Port of the MetaTrader 4 expert advisor MacdPatternTraderv04cb. Die Strategie durchsucht eine konfigurierbare MACD-Hauptzeile nach bärische Double-Top- und bullische Double-Bottom-Muster. Wenn der zweite Schwung den ersten nicht überschreitet, während der MACD Bleibt der Wert über einem positiven oder negativen Auslöseniveau, eröffnet die Strategie eine Marktposition in Richtung des erwartete Umkehr. Schutzaufträge reproduzieren die ursprünglich festgelegte Stop-Loss-Distanz von 100 Pip und die Take-Profit-Distanz von 300 Pip.

Handelsregeln

  1. Abonnieren Sie die ausgewählte Kerzenserie (Standard: 30-Minuten-Zeitrahmen) und berechnen Sie die MACD-Hauptlinie mit dem konfigurierte Schnell-, Langsam- und Signalperioden (Standard: 5, 13 und 1).
  2. Verfolgen Sie die letzten drei abgeschlossenen MACD-Werte. Ein rückläufiges Setup wird aktiviert, sobald der MACD über dem TriggerLevel bleibt. bildet ein lokales Hoch und sinkt dann. Das Setup wird validiert, wenn der nächste Höchstwert von MACD niedriger ist als der zuvor gespeicherte Wert hoch, während MACD noch über dem Auslöser liegt. In diesem Moment wird ein Marktverkauf gesendet.
  3. Spiegeln Sie die gleiche Logik unter Null. Wenn der MACD unter -TriggerLevel bleibt, bildet sich ein Trog und der folgende Trog is higher than the previous one, the strategy opens a market buy.
  4. Setzen Sie die gespeicherten Spitzen und Tiefststände zurück, wenn die MACD-Linie wieder innerhalb der [-TriggerLevel, TriggerLevel]-Linie kreuzt. Reichweite. Dies entspricht dem ursprünglichen EA-Verhalten, das die Mustersuche abbricht, wenn der Impuls an Stärke verliert.
  5. Positionsgrößen beginnen ab dem konfigurierten TradeVolume. Beim Richtungswechsel fügt die Strategie ausreichend Volumen hinzu Reduzieren Sie das entgegengesetzte Risiko, bevor Sie den neuen Handel einrichten.
  6. Call StartProtection once on start so that both the 100 pip stop-loss and the 300 pip take-profit are managed by the Plattform auch nach Neustarts.

Parameter

Name Beschreibung
FastPeriod Schnelle EMA-Länge, die von MACD verwendet wird.
SlowPeriod Langsame EMA-Länge, die von MACD verwendet wird.
SignalPeriod Signalleitungsglättungslänge für MACD.
TriggerLevel Der absolute MACD-Pegel ist erforderlich, um die Double-Top-/Double-Bottom-Erkennung zu aktivieren.
StopLossPips Abstand des Schutzstopps in Pips (Standard 100).
TakeProfitPips Entfernung des Take-Profits in Pips (Standard 300).
TradeVolume Basisauftragsvolumen für neue Positionen.
CandleType Für Indikatorberechnungen verwendete Kerzenserien.

Notizen

  • Stop-Loss und Take-Profit werden vor der Weitergabe von Pips in Instrumentenschritte umgewandelt StartProtection, wobei das Verhalten mit dem des ursprünglichen MQL4-Experten identisch bleibt.
  • All indicator and trading comments inside the C# source code are written in English, as required by the repository Richtlinien.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Port of the MetaTrader 4 expert advisor MacdPatternTraderv04cb.
/// Detects bearish and bullish double-top/double-bottom patterns on the MACD main line.
/// The second swing needs to be weaker than the first one before a market order is sent.
/// Fixed protective orders replicate the original 100/300 pip stop-loss and take-profit distances.
/// </summary>
public class MacdPatternTraderDoubleTopStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<decimal> _triggerLevel;
	private readonly StrategyParam<decimal> _stopLossPips;
	private readonly StrategyParam<decimal> _takeProfitPips;
	private readonly StrategyParam<decimal> _tradeVolume;
	private readonly StrategyParam<DataType> _candleType;

	private MovingAverageConvergenceDivergenceSignal _macd = null!;
	private decimal? _previousMacd;
	private decimal? _previousMacd2;
	private decimal? _firstPeak;
	private decimal? _firstTrough;
	private bool _sellPatternArmed;
	private bool _buyPatternArmed;

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public MacdPatternTraderDoubleTopStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 5)
		.SetGreaterThanZero()
		.SetDisplay("Fast EMA", "Fast moving average length used by MACD", "MACD")
		
		.SetOptimize(3, 15, 1);

		_slowPeriod = Param(nameof(SlowPeriod), 13)
		.SetGreaterThanZero()
		.SetDisplay("Slow EMA", "Slow moving average length used by MACD", "MACD")
		
		.SetOptimize(10, 30, 1);

		_signalPeriod = Param(nameof(SignalPeriod), 1)
		.SetGreaterThanZero()
		.SetDisplay("Signal EMA", "Signal smoothing period for MACD", "MACD")
		
		.SetOptimize(1, 9, 1);

		_triggerLevel = Param(nameof(TriggerLevel), 50m)
		.SetNotNegative()
		.SetDisplay("Trigger Level", "Absolute MACD level that arms the pattern logic", "MACD");

		_stopLossPips = Param(nameof(StopLossPips), 100m)
		.SetNotNegative()
		.SetDisplay("Stop-Loss (pips)", "Stop-loss distance expressed in pips", "Risk Management")
		
		.SetOptimize(50m, 200m, 10m);

		_takeProfitPips = Param(nameof(TakeProfitPips), 300m)
		.SetNotNegative()
		.SetDisplay("Take-Profit (pips)", "Take-profit distance expressed in pips", "Risk Management")
		
		.SetOptimize(150m, 500m, 10m);

		_tradeVolume = Param(nameof(TradeVolume), 0.1m)
		.SetGreaterThanZero()
		.SetDisplay("Trade Volume", "Order volume used for new entries", "Trading")
		
		.SetOptimize(0.05m, 1m, 0.05m);

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
		.SetDisplay("Candle Type", "Timeframe used for MACD calculations", "General");
	}

/// <summary>
/// Fast EMA length used by MACD.
/// </summary>
public int FastPeriod
{
	get => _fastPeriod.Value;
	set => _fastPeriod.Value = value;
}

/// <summary>
/// Slow EMA length used by MACD.
/// </summary>
public int SlowPeriod
{
	get => _slowPeriod.Value;
	set => _slowPeriod.Value = value;
}

/// <summary>
/// Signal EMA length used by MACD.
/// </summary>
public int SignalPeriod
{
	get => _signalPeriod.Value;
	set => _signalPeriod.Value = value;
}

/// <summary>
/// Absolute MACD level that enables pattern tracking.
/// </summary>
public decimal TriggerLevel
{
	get => _triggerLevel.Value;
	set => _triggerLevel.Value = value;
}

/// <summary>
/// Stop-loss distance expressed in pips.
/// </summary>
public decimal StopLossPips
{
	get => _stopLossPips.Value;
	set => _stopLossPips.Value = value;
}

/// <summary>
/// Take-profit distance expressed in pips.
/// </summary>
public decimal TakeProfitPips
{
	get => _takeProfitPips.Value;
	set => _takeProfitPips.Value = value;
}

/// <summary>
/// Trading volume used for new market orders.
/// </summary>
public decimal TradeVolume
{
	get => _tradeVolume.Value;
	set => _tradeVolume.Value = value;
}

/// <summary>
/// Candle type used for indicator calculations.
/// </summary>
public DataType CandleType
{
	get => _candleType.Value;
	set => _candleType.Value = value;
}

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

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

	_previousMacd = null;
	_previousMacd2 = null;
	_firstPeak = null;
	_firstTrough = null;
	_sellPatternArmed = false;
	_buyPatternArmed = false;
}

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

	Volume = TradeVolume;

	_macd = new MovingAverageConvergenceDivergenceSignal
	{
		Macd =
		{
			ShortMa = { Length = FastPeriod },
			LongMa = { Length = SlowPeriod },
		},
	SignalMa = { Length = SignalPeriod },
};

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

var pipSize = Security?.PriceStep ?? 0.01m;
if (pipSize <= 0m) pipSize = 0.01m;

StartProtection(
	takeProfit: TakeProfitPips > 0m ? new Unit(TakeProfitPips * pipSize, UnitTypes.Absolute) : null,
	stopLoss: StopLossPips > 0m ? new Unit(StopLossPips * pipSize, UnitTypes.Absolute) : null,
	useMarketOrders: true);
}

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

	if (!macdValue.IsFinal || macdValue is not MovingAverageConvergenceDivergenceSignalValue typed)
	return;

	if (typed.Macd is not decimal macdLine)
	return;

	var previous = _previousMacd;
	var previous2 = _previousMacd2;

	if (previous.HasValue && previous2.HasValue)
	{
		ProcessSellPattern(macdLine, previous.Value, previous2.Value);
		ProcessBuyPattern(macdLine, previous.Value, previous2.Value);
	}

_previousMacd2 = previous;
_previousMacd = macdLine;
}

private void ProcessSellPattern(decimal current, decimal previous, decimal previous2)
{
	if (current > TriggerLevel && current < previous && previous > previous2)
	{
		if (!_sellPatternArmed)
		{
			_firstPeak = previous;
			_sellPatternArmed = true;
		}
	else if (_firstPeak is decimal referencePeak && previous < referencePeak)
	{
		EnterShort();
		ResetSellPattern();
	}
}
else if (current < TriggerLevel)
{
	ResetSellPattern();
}
}

private void ProcessBuyPattern(decimal current, decimal previous, decimal previous2)
{
	var negativeTrigger = -TriggerLevel;

	if (current < negativeTrigger && current > previous && previous < previous2)
	{
		if (!_buyPatternArmed)
		{
			_firstTrough = previous;
			_buyPatternArmed = true;
		}
	else if (_firstTrough is decimal referenceTrough && previous > referenceTrough)
	{
		EnterLong();
		ResetBuyPattern();
	}
}
else if (current > negativeTrigger)
{
	ResetBuyPattern();
}
}

private void EnterShort()
{
	if (!IsFormedAndOnlineAndAllowTrading())
	return;

	var volume = Volume + Math.Max(0m, Position);
	if (volume <= 0m)
	return;

	SellMarket(volume);
}

private void EnterLong()
{
	if (!IsFormedAndOnlineAndAllowTrading())
	return;

	var volume = Volume + Math.Max(0m, -Position);
	if (volume <= 0m)
	return;

	BuyMarket(volume);
}

private void ResetSellPattern()
{
	_sellPatternArmed = false;
	_firstPeak = null;
}

private void ResetBuyPattern()
{
	_buyPatternArmed = false;
	_firstTrough = null;
}

}