Auf GitHub ansehen

Statistische euklidische metrische Strategie

Überblick

Die Strategie reproduziert das Verhalten des MetaTrader-Expertenberaters Stat_Euclidean_Metric.mq4. Es überwacht MACD Umkehrungen für ein einzelnes Instrument und einen einzelnen Zeitrahmen. Wenn die MACD-Linie einen lokalen Wendepunkt bildet, eröffnet die Strategie entweder sofort eine Position (Trainingsmodus) oder validiert das Setup mit einem K-NN-Klassifikator (k-Nearest Neighbors), der die aktuelle Marktstruktur mit historischen Merkmalsvektoren vergleicht, die in Binärdateien gespeichert sind.

Handelslogik

  1. Abonnieren Sie den konfigurierten Kerzentyp und berechnen Sie den Indikator MACD für den typischen Preis ((Hoch + Tief + Schluss) / 3).
  2. Erkennen Sie eine rückläufige Umkehr, wenn die letzten drei abgeschlossenen MACD-Werte MACD[2] <= MACD[1] und MACD[1] > MACD[0] erfüllen.
  3. Erkennen Sie eine zinsbullische Umkehr, wenn MACD[2] >= MACD[1] und MACD[1] < MACD[0].
  4. Abhängig vom gewählten Modus:
    • Trainingsmodus (TrainingMode = true) – Eröffnen Sie eine Marktorder in Richtung der Umkehrung, nachdem Sie optional die aktuelle Position geschlossen haben. Dies ahmt das ursprüngliche Verhalten von EA nach, wenn neue Stichproben erfasst werden.
    • Klassifikatormodus (TrainingMode = false) – Berechnen Sie fünf Verhältnisse einfacher gleitender Durchschnitte des typischen Preises und bewerten Sie die Erfolgswahrscheinlichkeit mit einem k-NN-Modell. Geben Sie Bestellungen nur auf, wenn die Wahrscheinlichkeit die konfigurierten Schwellenwerte überschreitet.
  5. Wenden Sie das integrierte StartProtection-Modul an, um Stop-Loss- und Take-Profit-Levels in Instrumentenschritten festzulegen.

Merkmalsvektor zur Klassifizierung

Das k-NN-Modell verwendet die folgenden Verhältnisse, die für die gerade geschlossene Kerze berechnet wurden:

  • SMA(89) / SMA(144)
  • SMA(144) / SMA(233)
  • SMA(21) / SMA(89)
  • SMA(55) / SMA(89)
  • SMA(2) / SMA(55)

Jede in den Datensatzdateien gespeicherte Stichprobe enthält sechs double-Werte: die fünf oben genannten Verhältnisse und eine Bezeichnung (0 für ein ungünstiges Ergebnis, 1 für einen erfolgreichen Handel). Während der Auswertung wählt die Strategie die nächstgelegenen NeighborCount Stichproben aus, mittelt ihre Bezeichnungen und interpretiert das Ergebnis als Erfolgswahrscheinlichkeit.

Datensatzdateien

  • BuyDatasetPath – Pfad zur Binärdatei mit Vektoren, die nach bullischen Trades gesammelt wurden.
  • SellDatasetPath – Pfad zur Binärdatei mit Vektoren, die nach rückläufigen Trades gesammelt wurden.

Wenn ein Pfad relativ ist, wird er anhand von Environment.CurrentDirectory aufgelöst. Fehlende Dateien werden im Protokoll gemeldet und als leerer Datensatz behandelt. Diese Implementierung liest Datensätze, aktualisiert jedoch nicht automatisch neue Beispiele oder hängt sie an. Der Export neuer Vektoren muss im Trainingsmodus extern erfolgen.

Parameter

  • TrainingMode – Wechseln Sie zwischen reinem MACD-Handel und klassifikatorgestütztem Handel.
  • BuyThreshold / SellThreshold – vom Klassifikator zurückgegebene minimale Wahrscheinlichkeit, Geschäfte in der primären Richtung zu eröffnen.
  • AllowInverseEntries – ermöglicht konträre Trades, wenn die Wahrscheinlichkeit extrem gering ist.
  • InverseBuyThreshold / InverseSellThreshold – maximale Wahrscheinlichkeit, die immer noch einen Handel in die entgegengesetzte Richtung auslöst.
  • FastLength / SlowLength / SignalLength – MACD EMA Längen.
  • TakeProfitPoints / StopLossPoints – Schutzniveaus ausgedrückt in Instrumentenschritten.
  • ClosePositionsOnSignal – Schließen Sie die aktuelle Nettoposition, bevor Sie eine neue Order senden.
  • BuyDatasetPath / SellDatasetPath – Binärdateien, die historische Vektoren speichern.
  • NeighborCount – Anzahl der Nachbarn, die bei der k-NN-Abstimmung verwendet werden.
  • CandleType – Kerzenserie, die für alle Indikatoren verwendet wird.

Nutzungsempfehlungen

  • Geben Sie absolute oder arbeitsverzeichnisrelative Pfade zu den Datensatzdateien an, bevor Sie den Klassifikatormodus aktivieren.
  • Sammeln Sie hochwertige Proben, indem Sie die Strategie im Trainingsmodus für historische Daten ausführen und Vektoren manuell exportieren.
  • Optimieren Sie die Schwellenwerte und die Anzahl der Nachbarn, um den Klassifikator an neue Märkte oder Instrumente anzupassen.
  • Halten Sie den Parameter Volume des Instruments an das Risikomodell angepasst, da die Strategie bei Bedarf immer Volume + |Position| Lots öffnet, um die Nettoposition umzukehren.

Unterschiede zur MQL4-Version

  • Die Klassifikatordatensätze werden nur gelesen; Das Original EA schreibt während der Deinitialisierung neue Samples. Hier muss der Benutzer die Dateien nach der Analyse der Handelshistorie manuell aktualisieren.
  • Alle Schutzanordnungen werden über StockSharp StartProtection anstelle manueller OrderSend-Parameter angehängt.
  • Beim Schließen einer Order im Klassifizierungsmodus wird immer die gesamte Position geschlossen, wenn ClosePositionsOnSignal aktiviert ist, während das Skript MQL4 nur profitable Orders schloss, bevor neue Signale angenommen wurden.
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 reversal strategy with moving average ratio filter.
/// Enters on MACD histogram reversals filtered by MA trend alignment.
/// </summary>
public class StatEuclideanMetricStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _trendMaLength;

	private readonly List<decimal> _macdHistory = new();

	public StatEuclideanMetricStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for analysis.", "General");

		_fastLength = Param(nameof(FastLength), 12)
			.SetDisplay("Fast Length", "Fast EMA period for MACD.", "Indicators");

		_slowLength = Param(nameof(SlowLength), 26)
			.SetDisplay("Slow Length", "Slow EMA period for MACD.", "Indicators");

		_trendMaLength = Param(nameof(TrendMaLength), 50)
			.SetDisplay("Trend MA Length", "Period for trend filter MA.", "Indicators");
	}

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

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	public int TrendMaLength
	{
		get => _trendMaLength.Value;
		set => _trendMaLength.Value = value;
	}

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

		_macdHistory.Clear();
	}

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

		var fastEma = new ExponentialMovingAverage { Length = FastLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowLength };
		var trendMa = new SimpleMovingAverage { Length = TrendMaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, trendMa, ProcessCandle)
			.Start();

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

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

		var macdLine = fastValue - slowValue;

		_macdHistory.Add(macdLine);
		if (_macdHistory.Count > 5)
			_macdHistory.RemoveAt(0);

		if (_macdHistory.Count < 3)
			return;

		var close = candle.ClosePrice;
		var macd1 = _macdHistory[^1];
		var macd2 = _macdHistory[^2];
		var macd3 = _macdHistory[^3];

		// MACD reversal patterns
		var buyReversal = macd3 >= macd2 && macd2 < macd1; // V-shape bottom
		var sellReversal = macd3 <= macd2 && macd2 > macd1; // inverted V top

		// Exit conditions
		if (Position > 0 && sellReversal)
		{
			SellMarket();
		}
		else if (Position < 0 && buyReversal)
		{
			BuyMarket();
		}

		// Entry conditions with trend filter
		if (Position == 0)
		{
			if (buyReversal && close > trendValue)
			{
				BuyMarket();
			}
			else if (sellReversal && close < trendValue)
			{
				SellMarket();
			}
		}
	}
}