Auf GitHub ansehen

DoubleUp2 Martingale Strategie

Überblick

Die DoubleUp2 Martingale-Strategie reproduziert den ursprünglichen MetaTrader-Experten, indem sie den Commodity Channel Index (CCI) und den MACD-Oszillator kombiniert. Trades werden nur eröffnet, wenn beide Indikatoren extreme Niveaus in die gleiche Richtung erreichen. Die Positionsgröße folgt einem Martingal-Schema, bei dem sich das Volumen nach einem Verlusthandel verdoppelt. Profitable Geschäfte werden teilweise gesperrt, indem die Position geschlossen wird, sobald der Preis eine konfigurierbare Distanz zugunsten der Position überschreitet.

Wie es funktioniert

  1. Abonnieren Sie eine einzelne Kerzenserie (Standard 1 Minute) und berechnen Sie CCI und MACD für jeden abgeschlossenen Balken.
  2. Extreme Dynamik erkennen:
    • Geben Sie short ein, wenn sowohl CCI als auch MACD den positiven Schwellenwert überschreiten.
    • Geben Sie long ein, wenn beide Werte unter den negativen Schwellenwert fallen.
  3. Vor der Umkehrung wird die aktuelle Position geschlossen und der Martingalschritt basierend auf dem simulierten Gewinn des letzten Handels aktualisiert.
  4. Das Handelsvolumen entspricht dem Basisvolumen, das sich aus dem Kontokapital ergibt, dividiert durch einen Saldodivisor, multipliziert mit dem Martingalfaktor, erhöht auf die aktuelle Stufe.
  5. Sichern Sie sich Gewinne, indem Sie alle offenen Positionen schließen, sobald der Preis seit dem letzten Eintrag um eine vordefinierte Anzahl von Punkten gestiegen ist. Gewinnende Exits erhöhen den Martingalschritt um zwei, um dem ursprünglichen EA-Verhalten zu entsprechen.

Parameter

Name Beschreibung Standard
CciPeriod Lookback-Zeitraum für den Indikator CCI. 8
MacdFastPeriod Schnelle EMA-Länge für MACD. 13
MacdSlowPeriod Langsame EMA-Länge für MACD. 33
MacdSignalPeriod Signallänge von EMA für die Glättung von MACD. 2
Threshold Absoluter Indikatorschwellenwert, der überschritten werden muss, um Einträge auszulösen. 230
ExitDistancePoints Gewinndistanz in Punkten, die die Schließung einer Position auslöst. 120
BalanceDivisor Der Divisor wird auf das Portfolioeigenkapital angewendet, um das Basisvolumen zu erhalten. 50001
MinimumVolume Untergrenze für das berechnete Handelsvolumen. 0,1
MartingaleMultiplier Der Multiplikator wird nach jedem verlorenen Schlusskurs auf die Positionsgröße angewendet. 2
CandleType Für alle Berechnungen verwendeter Kerzenzeitrahmen. 1 Minute

Notizen

  • Die Martingal-Logik erhöht die Positionsgröße nach Verlusten und setzt sie nach profitablen Umkehrungen zurück und spiegelt die Quelllogik MQL wider.
  • Preisschrittinformationen werden verwendet, um die Ausstiegsentfernung (Punkte) in absolute Preiseinheiten umzurechnen. Bietet das Instrument keinen Preisschritt, wird ein Wert von 1 verwendet.
  • Die Strategie erwartet ein einzelnes Instrument und platziert keine gleichzeitigen Long- und Short-Positionen.
using System;

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

namespace StockSharp.Samples.Strategies;

public class DoubleUp2MartingaleStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public DoubleUp2MartingaleStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevFast = fast;
		_prevSlow = slow;
	}
}