Auf GitHub ansehen

Macd Stochastic Trailing-Strategie

MACD Stochastic Nachlaufende Strategie

Überblick

  • Konvertiert vom MetaTrader 4 Expert Advisor MQL/7637/3_lccfpgubwykd__www_forex-instruments_info.mq4.
  • Verwendet einen Workflow mit drei Zeitrahmen: Stündliche Kerzen steuern beide MACD-Filter, 15-Minuten-Kerzen liefern Stochastic-Oszillatoren und 1-Minuten-Kerzen bestätigen Preisausbrüche und verwalten Trailing-Exits.
  • Implementiert eine übergeordnete StockSharp-Strategie mit SubscribeCandles(...).Bind(...) / BindEx(...) ohne manuelle Datenabfrage.
  • Positionen werden mit Marktaufträgen eröffnet und vollständig innerhalb der Strategie verwaltet (es waren keine externen Test-Änderungen erforderlich).

Indikatoren und Parameter

Name Typ Standard Beschreibung
LongStopLoss decimal 17 Anfänglicher Stoppabstand für Long-Trades, ausgedrückt in Instrumentenpunkten.
ShortStopLoss decimal 40 Anfängliche Stoppdistanz für Short-Trades (Punkte).
LongTrailingStop decimal 88 Nachlaufdistanz für Long-Positionen.
ShortTrailingStop decimal 76 Nachlaufdistanz für Short-Positionen.
OrderVolume decimal 0.1 Basishandelsvolumen (Lots), gespiegelt aus der Eingabe MQL.
MacdCandleType DataType H1 Zeitrahmen für die bullischen und bärischen MACD-Filter (22/27/9 und 19/77/9).
StochasticCandleType DataType M15 Zeitrahmen, der für beide Stochastic-Oszillatoren (5/3/11 und 9/3/19) verwendet wird.
EntryCandleType DataType M1 Zeitrahmen, der eine Ausbruchsbestätigung und eine abschließende Logik bereitstellt.

Alle punktbasierten Einstellungen werden durch das Instrument PriceStep in absolute Preise umgewandelt, wodurch der Multiplikator MetaTrader Point originalgetreu reproduziert wird.

Handelsregeln

Langer Eintrag

  1. Die stündliche Hauptlinie MACD(22,27,9) überschreitet ihren vorherigen Wert, bleibt aber unter Null.
  2. M15 Stochastic(%K=5,%D=3,slowing=11) liegt unter 26 und steigt im Vergleich zum vorherigen Wert.
  3. Der aktuelle M1-Schluss durchbricht das vorherige M1-Hoch.
  4. Wenn alle Bedingungen übereinstimmen und keine Position offen ist, kauft die Strategie OrderVolume plus die Menge, die zum Umtausch eines bestehenden Short erforderlich ist.

Kurzer Eintrag

  1. Die stündliche MACD(19,77,9) Hauptlinie fällt unter ihren vorherigen Wert, wobei der vorherige Wert über Null liegt.
  2. M15 Stochastic(%K=9,%D=3,slowing=19) liegt über 70.
  3. Der aktuelle M1-Schlusskurs bricht unter das vorherige M1-Tief.
  4. Ein Short wird mit der gleichen Positions-Flip-Logik wie der ursprüngliche EA eröffnet.

Exit und Trailing

  • Die anfänglichen Stopps spiegeln die Entfernungen von MQL StopLoss in Punkten wider.
  • Trailing-Stops werden aktiviert, sobald sich der Preis um mehr als die angegebene Trailing-Distanz zugunsten der Position bewegt, und werden bei jeder beendeten M1-Kerze neu berechnet.
  • Wenn der Preis das aktive Stop-Level (Anfangs- oder Trailed-Stop-Level) berührt, wird die Position mit einer Marktorder geschlossen.

Implementierungshinweise

  • Kerzenabonnements werden nach Zeitrahmen aufgeteilt, sodass Indikatoraktualisierungen unabhängig bleiben und genau dem Verhalten von EA in mehreren Zeitrahmen entsprechen.
  • Die nachgestellten Vergleiche MQL Bid/Ask werden durch die fertigen M1-Kerzenhöchst-/-tiefs angenähert, was die nächstliegende Darstellung innerhalb des kerzenbasierten Hochniveaus API darstellt.
  • Der Code folgt den Repository-Richtlinien: Tab-Einrückung, Namespace StockSharp.Samples.Strategies, englische Kommentare und Parameterdeklarationen innerhalb des Konstruktors über Param(...).
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD + Stochastic trailing strategy.
/// Enters long when MACD histogram is positive and Stochastic K crosses above D from oversold.
/// Enters short when MACD histogram is negative and Stochastic K crosses below D from overbought.
/// </summary>
public class MacdStochasticTrailingStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;

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

	public MacdStochasticTrailingStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevK = null;
		_prevD = null;
	}

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

		_prevK = null;
		_prevD = null;

		var macd = new MovingAverageConvergenceDivergenceSignal();
		var stoch = new StochasticOscillator();

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, stoch, ProcessCandle)
			.Start();
	}

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

		if (!macdValue.IsFinal || !stochValue.IsFinal)
			return;

		var macdVal = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
		var stochVal = (StochasticOscillatorValue)stochValue;

		if (macdVal.Macd is not decimal macd || macdVal.Signal is not decimal signal)
			return;
		if (stochVal.K is not decimal k || stochVal.D is not decimal d)
			return;

		if (_prevK is not decimal prevK || _prevD is not decimal prevD)
		{
			_prevK = k;
			_prevD = d;
			return;
		}

		var histogram = macd - signal;
		var kCrossUp = prevK <= prevD && k > d;
		var kCrossDown = prevK >= prevD && k < d;

		// Buy: MACD histogram positive + stochastic K crosses above D
		if (histogram > 0 && kCrossUp && k < 50 && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Sell: MACD histogram negative + stochastic K crosses below D
		else if (histogram < 0 && kCrossDown && k > 50 && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevK = k;
		_prevD = d;
	}
}