Auf GitHub ansehen

Ang Zad C Time MM Recovery-Strategie

Überblick

Die Ang Zad C Time MM Recovery-Strategie ist ein C#-Port des MetaTrader 5-Expertenberaters Exp_Ang_Zad_C_Tm_MMRec. Die Strategie kombiniert den benutzerdefinierten Ang_Zad_C-Kanal-Indikator mit einem konfigurierbaren Handelssitzungsfilter und einem adaptiven Positionsgrößenmodell, das das Risiko nach einer konfigurierbaren Anzahl von Verlust-Trades reduziert.

Indikatorlogik

Der Ang_Zad_C-Indikator baut zwei adaptive Hüllen um den Preis auf. Jede Hülle wird aktualisiert, indem der gewählte angewendete Preis der aktuellen und vorherigen Kerze verglichen wird und sich mit dem Glättungsfaktor Ki in Richtung des neuen Preises bewegt. Die obere und untere Linie werden auf historischen Balken ausgewertet, die durch Signal Bar definiert sind, um nicht auf unfertigen Kerzen zu handeln.

Trading-Regeln

  • Long-Einstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken über der unteren Linie war und auf dem aktuellsten Referenzbalken darunter kreuzt oder die untere Linie berührt. Wenn dies passiert, wird jede offene Short-Position geschlossen, bevor eine neue Long-Position geöffnet wird (wenn aktiviert).
  • Short-Einstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken unter der unteren Linie war und auf dem aktuellsten Referenzbalken darüber kreuzt oder die untere Linie berührt. Jede offene Long-Position wird geschlossen, bevor eine neue Short-Position geöffnet wird (wenn aktiviert).
  • Long-Ausstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken unter der unteren Linie liegt. Der Ausstieg kann über Enable Long Exit deaktiviert werden.
  • Short-Ausstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken über der unteren Linie liegt. Der Ausstieg kann über Enable Short Exit deaktiviert werden.

Money-Management und Schutzmaßnahmen

  • Handel ist nur innerhalb des konfigurierten Zeitfensters erlaubt, wenn Use Time Filter aktiviert ist. Zuvor geöffnete Positionen werden geschlossen, sobald die Sitzung endet.
  • Das Trade-Volumen wird zwischen Normal Volume und Small Volume ausgewählt, abhängig davon, wie viele Verlust-Trades für jede Seite aufgetreten sind. Nach Buy Loss Trigger verlierenden Long-Trades (oder Sell Loss Trigger verlierenden Short-Trades) wird das reduzierte Volumen verwendet, bis ein profitabler Trade den Zähler zurücksetzt.
  • Optionale Stop-Loss- und Take-Profit-Levels werden mit Preisschrittabständen registriert, die durch Stop Loss Steps und Take Profit Steps definiert werden.

Parameter

Name Beschreibung
Candle Type Zeitrahmen der vom Indikator und Signalen verwendeten Kerzen.
Ki Glättungskoeffizient der Ang_Zad_C-Hüllen.
Applied Price Welcher Kerzenkurs in den Indikator eingespeist wird.
Signal Bar Wie viele Balken zurück für die Signalauswertung verwendet werden (1 = vorheriger geschlossener Balken).
Use Time Filter / Trade Start / Trade End Sitzungsbasiertes Trading aktivieren und Start- und Endzeit der Sitzung festlegen.
Enable Long/Short Entry Öffnung neuer Long- oder Short-Trades erlauben.
Enable Long/Short Exit Der Strategie erlauben, Positionen bei Indikatorumkehr zu schließen.
Buy/Sell Loss Trigger Anzahl der Verlust-Trades, bevor das reduzierte Volumen angewendet wird.
Small Volume / Normal Volume Ordergrößen für reduziertes und normales Risiko.
Stop Loss Steps / Take Profit Steps Abstand für Schutzorders ausgedrückt in Preisschritten.

Konvertierungshinweise

  • Die Logik folgt dem ursprünglichen MQL5-Code, einschließlich der direktionalen Kreuzprüfungen und des Zeitfensterverhaltens.
  • Das adaptive Money-Management wird implementiert, indem realisierter Gewinn und Verlust pro Richtung verfolgt und nach der konfigurierten Anzahl von Verlusten auf das reduzierte Volumen umgeschaltet wird.
  • Indikatorberechnungen vermeiden jeden direkten Pufferzugriff und werden auf fertigen Kerzen unter Verwendung der StockSharp-API auf hoher Ebene verarbeitet.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Ang_Zad_C adaptive channel strategy.
/// Trades when the upper/lower lines cross, indicating trend reversal.
/// </summary>
public class AngZadCTimeMMRecoveryStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _ki;

	private bool _hasState;
	private decimal _upperLine;
	private decimal _lowerLine;
	private decimal _previousPrice;
	private decimal? _prevUp;
	private decimal? _prevDn;

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

	public decimal Ki
	{
		get => _ki.Value;
		set => _ki.Value = value;
	}

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

		_ki = Param(nameof(Ki), 4.000001m)
			.SetDisplay("Ki", "Smoothing coefficient", "Indicator")
			.SetGreaterThanZero();
	}

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

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

		_hasState = false;
		_upperLine = 0m;
		_lowerLine = 0m;
		_previousPrice = 0m;
		_prevUp = null;
		_prevDn = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasState = false;
		_prevUp = null;
		_prevDn = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var price = candle.ClosePrice;
		var (upper, lower) = UpdateIndicator(price);

		if (_prevUp == null || _prevDn == null)
		{
			_prevUp = upper;
			_prevDn = lower;
			return;
		}

		var prevUp = _prevUp.Value;
		var prevDn = _prevDn.Value;

		// Buy signal: previous upper was below lower, now crossing above
		if (prevUp <= prevDn && upper > lower)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// Sell signal: previous upper was above lower, now crossing below
		else if (prevUp >= prevDn && upper < lower)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}

		_prevUp = upper;
		_prevDn = lower;
	}

	private (decimal Up, decimal Down) UpdateIndicator(decimal price)
	{
		if (!_hasState)
		{
			_upperLine = price;
			_lowerLine = price;
			_previousPrice = price;
			_hasState = true;
			return (_upperLine, _lowerLine);
		}

		var ki = Ki;

		if (price > _upperLine && price > _previousPrice)
			_upperLine += (price - _upperLine) / ki;

		if (price < _upperLine && price < _previousPrice)
			_upperLine += (price - _upperLine) / ki;

		if (price > _lowerLine && price < _previousPrice)
			_lowerLine += (price - _lowerLine) / ki;

		if (price < _lowerLine && price > _previousPrice)
			_lowerLine += (price - _lowerLine) / ki;

		_previousPrice = price;

		return (_upperLine, _lowerLine);
	}
}