Auf GitHub ansehen

Exp Fine-Tuning-MA-Kerzen-Strategie

Überblick

  • Konvertierung des MetaTrader 5-Experten Exp_FineTuningMACandle.mq5, der auf Basis der Farbe des Fine Tuning MA Candle-Indikators handelt.
  • Entwickelt für StockSharp's High-Level-API: abonniert eine einzelne Kerzenserie, leitet Indikatorwerte über BindEx ab und leitet alle Orders über die Strategy-Hilfsmethoden weiter.
  • Implementiert dieselben Einstiegsberechtigungen und bedingten Schließungen wie der ursprüngliche Experte unter Beachtung des asynchronen Ausführungsmodells von StockSharp.

Fine Tuning MA Candle-Indikator

  • Der Indikator erstellt synthetische OHLC-Kerzen durch ein dreistufiges Gewichtungsschema der letzten Length Kerzen der Preisserie.
    • Rank1, Rank2 und Rank3 steuern die Krümmung der Gewichtungsrampen, während Shift1, Shift2 und Shift3 die Rampen mit einer flachen Komponente mischen.
    • Die Gewichtung ist symmetrisch: die erste Hälfte des Fensters beschleunigt sich zur Mitte, die zweite Hälfte verlangsamt sich von ihr weg.
    • Nach der Normalisierung produzieren die vier gewichteten Summen geglättete Eröffnungs-, Hoch-, Tief- und Schlusskurse.
  • Wenn sich geglättete Eröffnung und Schluss um weniger als GapPoints (in den Preisschritt des Instruments umgerechnet) unterscheiden, wird die Eröffnung durch den vorherigen synthetischen Schluss ersetzt, um Preislücken zu entfernen.
  • Die Kerze wird 2 (bullish) eingefärbt wenn Open < Close, 0 (bearish) wenn Open > Close, und 1 wenn sie gleich sind. Nur der Farbstrom wird für Handelsentscheidungen verwendet.
  • PriceShiftPoints verschiebt jede synthetische Kerze vertikal um eine konfigurierbare Anzahl von Preisschritten.

Handelsregeln

  • Signale werden nur bei abgeschlossenen Kerzen erzeugt. Die Strategie speichert die Indikatorfarben und bewertet die Kerze, die SignalBar Schritte hinter der letzten abgeschlossenen liegt.
  • Bullische Rotation (Farbe wechselt zu 2):
    • Bestehende Short-Positionen werden geschlossen, wenn SellPosClose aktiviert ist.
    • Sobald die Position flat ist und BuyPosOpen erlaubt ist, wird eine Long-Marktorder für Volume Lots gesendet. Musste zuvor ein Short geschlossen werden, wird der Long-Einstieg in die Warteschlange gestellt und ausgeführt, sobald die Position auf null zurückkehrt.
  • Bearische Rotation (Farbe wechselt zu 0):
    • Bestehende Long-Positionen werden geschlossen, wenn BuyPosClose aktiviert ist.
    • Sobald flat und SellPosOpen erlaubt, wird eine Short-Marktorder für Volume Lots gesendet. Ausstehende Einstiege werden genauso behandelt wie bei Long-Signalen.
  • Neutrale Farbe (1) löst keine Aktion aus.
  • Orders werden nicht gestapelt: die Strategie öffnet höchstens eine Position gleichzeitig und wartet auf das Schließen aktiver Positionen, bevor sie umkehrt.

Risikomanagement

  • StopLossPoints und TakeProfitPoints stellen Abstände in Preisschritten dar. Nach dem Füllen einer neuen Position registriert die Strategie schützende Stop- und Zielorders unter Verwendung des tatsächlichen Füllpreises aus OnNewMyTrade.
  • Schutzorders werden automatisch storniert, wenn die Position auf null zurückkehrt oder wenn eine neue Order in die Warteschlange gestellt wird.

Parameter

Name Beschreibung
CandleType Kerzendatentyp/Zeitrahmen für Indikatorberechnungen.
Length Anzahl der vom gewichteten Fenster des Indikators verarbeiteten Kerzen.
Rank1, Rank2, Rank3 Potenzkoeffizienten, die die drei Gewichtungsstufen formen.
Shift1, Shift2, Shift3 Mischfaktoren (0–1), die die Gewichtungsstufen mit einer flachen Komponente kombinieren.
GapPoints Maximale Differenz zwischen synthetischer Eröffnung und synthetischem Schluss, die durch Kopieren des vorherigen Schlusses unterdrückt wird. Angegeben in Preisschritten.
SignalBar Wie viele geschlossene Kerzen übersprungen werden, bevor die Indikatorfarbe gelesen wird. 1 bedeutet "letzte abgeschlossene Kerze verwenden".
BuyPosOpen / SellPosOpen Öffnen von Long/Short-Positionen erlauben.
BuyPosClose / SellPosClose Schließen von Long/Short-Positionen bei entgegengesetzter Farbe erlauben.
StopLossPoints Abstand vom Füllpreis zum Schutz-Stop. Auf 0 setzen zum Deaktivieren.
TakeProfitPoints Abstand vom Füllpreis zum Gewinnziel. Auf 0 setzen zum Deaktivieren.
PriceShiftPoints Vertikale Verschiebung der synthetischen Kerzen in Preisschritten.

Implementierungshinweise

  • Verwendet BindEx, weil der benutzerdefinierte Indikator ein komplexes Wertobjekt zurückgibt, das synthetisches OHLC und Farbe gleichzeitig bereitstellt.
  • Speichert nur eine kleine Historie von Farbwerten (SignalBar + 2 Einträge), um Farbwechsel zu erkennen, ohne große Puffer zu speichern.
  • Einstiegsumkehrungen beachten das asynchrone Ausführungsmodell, indem sie warten, bis die Position flat ist, bevor die Gegenorder gesendet wird.
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>
/// Fine Tuning MA Candle strategy using WMA crossover with EMA trend filter.
/// Buys when fast WMA crosses above slow WMA with price above EMA.
/// Sells on reverse conditions.
/// </summary>
public class ExpFineTuningMaCandleStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private WeightedMovingAverage _fast;
	private WeightedMovingAverage _slow;
	private ExponentialMovingAverage _ema;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Fast WMA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow WMA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// EMA trend filter period.
	/// </summary>
	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="ExpFineTuningMaCandleStrategy"/> class.
	/// </summary>
	public ExpFineTuningMaCandleStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast WMA period", "Indicator");

		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow WMA period", "Indicator");

		_emaPeriod = Param(nameof(EmaPeriod), 200)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

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

		_fast = null;
		_slow = null;
		_ema = null;
		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

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

		_fast = new WeightedMovingAverage { Length = FastPeriod };
		_slow = new WeightedMovingAverage { Length = SlowPeriod };
		_ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, _ema, ProcessCandle);
		subscription.Start();
	}

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

		if (!_fast.IsFormed || !_slow.IsFormed || !_ema.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}

		// WMA crossover with EMA trend filter
		if (_prevFast <= _prevSlow && fastValue > slowValue && close > emaValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 80;
		}
		else if (_prevFast >= _prevSlow && fastValue < slowValue && close < emaValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 80;
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}