Auf GitHub ansehen

Exp Iin MA Signal MMRec Strategie

Ein StockSharp-Port des MetaTrader-Experten "Exp_Iin_MA_Signal_MMRec". Die Strategie hört auf die Kreuzungssignale, die von einem Paar konfigurierbarer gleitender Durchschnitte (der ursprüngliche Iin_MA_Signal-Indikator) erzeugt werden, und wendet ein adaptives Positionsgrößenschema mit verlustbasierter Reduzierung an.

Überblick

  • Signalgenerierung: die schnellen und langsamen gleitenden Durchschnitte werden auf dem ausgewählten Kerzentyp und dem angewandten Preis ausgewertet. Ein Kaufsignal wird erzeugt, wenn der schnelle Durchschnitt über den langsamen kreuzt, während ein Verkaufssignal beim umgekehrten Kreuzung erzeugt wird. Der Parameter SignalBar verschiebt die Ausführung um die angegebene Anzahl vollständig geschlossener Balken und reproduziert so die Indikatorpuffer-Verzögerung der MQL-Version.
  • Positionsverwaltung: BuyPosOpen und SellPosOpen aktivieren oder deaktivieren Long- und Short-Einstiege. Wenn ein entgegengesetztes Signal erscheint und das entsprechende BuyPosClose- oder SellPosClose-Flag aktiviert ist, schließt die Strategie entweder das aktuelle Exposure oder dreht direkt in die neue Richtung um.
  • Risikokontrolle: StopLossPoints und TakeProfitPoints werden mithilfe von Security.PriceStep in Preisabstände umgerechnet und gegen die Kerzenextreme geprüft, bevor neue Signale verarbeitet werden.
  • Geldmanagement: die letzten Trades werden separat für Longs und Shorts verfolgt. Wenn die Anzahl der Verlust-Trades innerhalb des BuyTotalTrigger/SellTotalTrigger-Fensters den jeweiligen Verlustschwellenwert erreicht, wechselt die Strategie von NormalVolume zu ReducedVolume. Der Parameter MoneyMode definiert, wie der Volumenwert interpretiert wird (feste Lots, Saldoprozentsatz oder stop-basierter Risikoprozentsatz).

Parameter

  • FastPeriod, SlowPeriod – Längen der schnellen und langsamen gleitenden Durchschnitte.
  • FastType, SlowType – Typen der gleitenden Durchschnitte (Simple, Exponential, Smoothed, Weighted, VolumeWeighted).
  • FastPrice, SlowPrice – angewandter Preis für jeden Durchschnitt (Close, Open, High, Low, Median, Typical, Weighted).
  • SignalBar – Anzahl der geschlossenen Balken zwischen einem erkannten Signal und der Auftragsübermittlung.
  • BuyPosOpen, SellPosOpen – Schalter für das Öffnen von Long/Short-Positionen.
  • BuyPosClose, SellPosClose – Schalter für das Schließen oder Umkehren einer bestehenden Position beim entgegengesetzten Signal.
  • BuyTotalTrigger, SellTotalTrigger – wie viele aktuelle Trades für den Verlustzähler untersucht werden.
  • BuyLossTrigger, SellLossTrigger – Mindestanzahl von Verlusten innerhalb des untersuchten Fensters, die das reduzierte Volumen aktiviert.
  • NormalVolume, ReducedVolume – primäres und Fallback-Volumen (oder Risikofaktor, abhängig von MoneyMode).
  • StopLossPoints, TakeProfitPoints – Stop-Loss- und Take-Profit-Abstände in Instrument-Punkten.
  • MoneyMode – Interpretation der Volumenwerte (Lot, Balance, FreeMargin, BalanceRisk, FreeMarginRisk). Saldobasierte Modi verwenden Portfolio.CurrentValue, während risikobasierte Modi den Risikobetrag durch den berechneten Stop-Abstand dividieren.
  • CandleType – Kerzenserie für Indikatorberechnungen.

Signallogik

  1. Jede fertige Kerze füttert die gleitenden Durchschnitte mit dem gewählten angewandten Preis.
  2. Die Differenz zwischen aktuellen und vorherigen Werten der gleitenden Durchschnitte definiert ein Kreuzungsereignis.
  3. Signale werden in die Warteschlange gestellt, und der älteste Eintrag wird ausgeführt, sobald die Warteschlangengröße SignalBar überschreitet.
  4. Wenn ein Kaufsignal ausgeführt wird:
    • Wenn eine Short-Position besteht und SellPosClose aktiviert ist, berechnet die Strategie den realisierten PnL für diesen Short-Trade. Dann dreht sie entweder in einen Long um (wenn BuyPosOpen aktiviert ist) oder schließt einfach das Exposure.
    • Wenn keine Position offen ist und BuyPosOpen aktiviert ist, wird ein neuer Long mit dem berechneten Volumen eröffnet.
  5. Verkaufssignale spiegeln den Kauf-Workflow.

Geldmanagement-Details

  • Der Trade-Verlauf wird als rollende FIFO-Warteschlange gespeichert, begrenzt durch BuyTotalTrigger / SellTotalTrigger.
  • Ein Verlust-Trade (negativer PnL) erhöht den Verlustzähler. Wenn der Zähler BuyLossTrigger oder SellLossTrigger erreicht, verwendet die nächste Position ReducedVolume.
  • MoneyMode = Lot behandelt Volumenwerte als Rohmengen.
  • MoneyMode = Balance und FreeMargin multiplizieren den konfigurierten Wert mit Portfolio.CurrentValue und dividieren durch den aktuellen Schlusskurs, um die Menge zu erhalten.
  • MoneyMode = BalanceRisk und FreeMarginRisk multiplizieren den konfigurierten Wert mit Portfolio.CurrentValue und dividieren durch den Stop-Loss-Abstand. Wenn der Stop-Abstand null ist, ist der Fallback identisch mit der Saldoprozentsatz-Berechnung.
  • Wenn Portfolio-Informationen nicht verfügbar sind, fällt das berechnete Volumen auf null zurück, um versehentliche Aufträge zu vermeiden.

Risikobehandlung

  • Stop-Loss- und Take-Profit-Level werden auf jeder Kerze mit dem Einstandspreis und dem Punktwert neu berechnet. Wenn ein Level innerhalb des Kerzenbereichs berührt wird, wird die Position geschlossen, bevor neue Signale verarbeitet werden.
  • Schließungsaktionen zeichnen immer das Trade-Ergebnis auf, um sicherzustellen, dass die Geldmanagement-Warteschlangen mit tatsächlichen Exits synchronisiert bleiben.

Hinweise

  • Stellen Sie sicher, dass StopLossPoints und TakeProfitPoints mit der Instrument-Tick-Größe kompatibel sind; die Strategie multipliziert sie mit Security.PriceStep.
  • Wenn MoneyMode auf Portfolio-Daten angewiesen ist, erwartet die Strategie, dass das Portfolio-Objekt CurrentValue exponiert.
  • Der Algorithmus arbeitet auf Nettopositonsbasis: gleichzeitige Long- und Short-Holdings werden nicht unterstützt.
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>
/// Exp Iin MA Signal MMRec strategy. Uses SMA crossover.
/// </summary>
public class ExpIinMaSignalMmrecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast;
	private decimal? _prevSlow;

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

	public ExpIinMaSignalMmrecStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal f, decimal s)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevFast == null || _prevSlow == null) { _prevFast = f; _prevSlow = s; return; }
		var pa = _prevFast.Value > _prevSlow.Value; var ca = f > s;
		_prevFast = f; _prevSlow = s;
		if (!pa && ca && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (pa && !ca && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}