Auf GitHub ansehen

Martingail-Expertenstrategie

Überblick

Martingail Expert ist eine trendfolgende Martingal-Strategie, die auf dem Stochastic-Oszillator basiert, um neue Handelssequenzen zu timen. Sobald der Indikator eine Richtung generiert, startet die Strategie eine Leiter von Marktaufträgen und verwaltet das Risiko mithilfe eines dynamischen Gewinnziels und eines geometrischen Positionsgrößenschemas.

Handelslogik

  • Berechnen Sie einen Stochastic-Oszillator für die konfigurierte Kerzenreihe. Die aktuellsten Endwerte von %K und %D werden zur Entscheidungsfindung zwischengespeichert.
  • Starten Sie eine neue lange Sequenz, wenn %K (previous) > %D (previous) und %D (previous) über dem Schwellenwert BuyLevel liegen.
  • Starten Sie eine neue kurze Sequenz, wenn %K (previous) < %D (previous) und %D (previous) unter dem Schwellenwert SellLevel liegen.
  • Nach Eingabe einer Sequenz fügt jede günstige Preisbewegung von ProfitFactor × openOrders Pips eine neue Position mit dem Basisvolumen hinzu.
  • Jede negative Bewegung von StepPoints Pips multipliziert das zuletzt gefüllte Volumen mit Multiplier und sendet eine durchschnittliche Order in die gleiche Richtung.

Ausgangsregeln

  • Schließen Sie die gesamte Position, sobald der letzte Füllpreis ein dynamisches Gewinnziel bei ProfitFactor × openOrders Pips in die günstige Richtung erreicht.
  • Setzen Sie den Martingal-Status zurück, wenn die aggregierte Positionsgröße auf Null zurückkehrt.

Risikomanagement

Die Martingal-Progression erhöht das Engagement schnell, wenn sich der Preis gegen die Position bewegt. Passen Sie Multiplier, StepPoints und ProfitFactor sorgfältig an, um sie an die Kontogröße und die Instrumentenvolatilität anzupassen.

Parameter

Name Beschreibung
Volume Basis-Market-Order-Volumen, das für den ersten Trade und alle vorteilhaften Add-Ons verwendet wird.
Multiplier Faktor, der bei der Mittelung bei ungünstigen Bewegungen auf das zuletzt ausgeführte Volumen angewendet wird.
StepPoints Entfernung in Punkten, die eine Martingal-Mittelungsreihenfolge auslöst.
ProfitFactor Gewinnziel pro offener Order, ausgedrückt in Punkten. Die tatsächliche Entfernung beträgt ProfitFactor × number_of_orders.
KPeriod Lookback-Länge für die %K-Zeile.
DPeriod Glättungslänge für die %D-Linie.
Slowing Zusätzliche Glättung wurde auf %K vor dem Vergleich mit %D angewendet.
BuyLevel Mindestwert %D erforderlich, um eine neue lange Sequenz zu ermöglichen.
SellLevel Maximaler %D-Wert erforderlich, um eine neue kurze Sequenz zu ermöglichen.
CandleType Für Berechnungen verwendete Kerzenserie (Standard: 5-Minuten-Zeitrahmen).

Notizen

  • Funktioniert am besten bei flüssigen FX-Paaren, bei denen Pip-Größe und Volumenschritt eine granulare Skalierung ermöglichen.
  • Erfordert ausreichend Spielraum, um mehreren Martingalschritten standzuhalten.
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>
/// Martingale strategy driven by stochastic oscillator crossovers.
/// Buy when K crosses above D, sell when K crosses below D.
/// Doubles down on adverse moves with martingale averaging.
/// </summary>
public class MartingailExpertSequenceStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _stepPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;
	private decimal _entryPrice;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal StepPoints { get => _stepPoints.Value; set => _stepPoints.Value = value; }
	public decimal TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MartingailExpertSequenceStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 14)
			.SetDisplay("K Period", "Stochastic K period", "Indicators");

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetDisplay("D Period", "Stochastic D period", "Indicators");

		_stepPoints = Param(nameof(StepPoints), 500m)
			.SetDisplay("Step Points", "Distance for martingale averaging", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 200m)
			.SetDisplay("Take Profit", "Take profit in price steps", "Risk");

		_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;
		_entryPrice = 0m;
	}

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

		_prevK = null;
		_prevD = null;

		var stoch = new StochasticOscillator
		{
			K = { Length = KPeriod },
			D = { Length = DPeriod }
		};

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

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

		if (!stochValue.IsFinal)
			return;

		if (stochValue is not StochasticOscillatorValue stoch)
			return;

		if (stoch.K is not decimal k || stoch.D is not decimal d)
			return;

		var step = Security?.PriceStep ?? 1m;
		if (step <= 0) step = 1m;

		// Check take profit
		if (Position > 0 && candle.ClosePrice >= _entryPrice + TakeProfitPoints * step)
		{
			SellMarket();
			_prevK = k;
			_prevD = d;
			return;
		}
		else if (Position < 0 && candle.ClosePrice <= _entryPrice - TakeProfitPoints * step)
		{
			BuyMarket();
			_prevK = k;
			_prevD = d;
			return;
		}

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

		// Stochastic crossover signals
		var bullCross = prevK <= prevD && k > d;
		var bearCross = prevK >= prevD && k < d;

		if (Position == 0)
		{
			if (bullCross)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
			}
			else if (bearCross)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
			}
		}
		else if (Position > 0 && bearCross)
		{
			SellMarket(); // Close long
			SellMarket(); // Open short
			_entryPrice = candle.ClosePrice;
		}
		else if (Position < 0 && bullCross)
		{
			BuyMarket(); // Close short
			BuyMarket(); // Open long
			_entryPrice = candle.ClosePrice;
		}

		_prevK = k;
		_prevD = d;
	}
}