Auf GitHub ansehen

Avalanche AV Strategie

Avalanche AV ist eine randomisierte Martingal-Strategie, die mit gleicher Wahrscheinlichkeit zwischen Long- und Short-Einstiegen abwechselt. Trades werden nur nach einer konfigurierbaren Anzahl abgeschlossener Kerzen geöffnet, und jede Position erbt feste Stop-Loss- und Take-Profit-Levels in Pips. Wenn ein Trade mit Verlust schließt, wird die Positionsgröße mit dem Martingal-Koeffizienten multipliziert, um die Erholung anzustreben; profitable Trades setzen die Größe zurück auf das Startvolumen, sobald der Kontosaldo ein neues Kapital-Hoch verzeichnet. Die Strategie erzwingt auch einen maximalen schwebenden Drawdown als Prozentsatz des Kontosaldos und schließt jede Position, die diese Schwelle überschreitet.

Die ursprüngliche MQL-Version öffnete Trades auf Ticks. Der StockSharp-Port behält dasselbe probabilistische Verhalten bei, arbeitet aber auf Kerzen-Updates, was sie sowohl für Backtesting als auch für Live-Trading mit Balkendaten geeignet macht.

Handelsregeln

  • Entscheidungsintervall: warten Sie auf die angegebene Anzahl abgeschlossener Kerzen, bevor Sie ein neues Signal bewerten. Wenn eine Position noch offen ist, zählt das Intervall weiter, aber kein neuer Trade wird eingegangen.
  • Einstiegsrichtung: generieren Sie eine Zufallszahl; Werte über 16384 lösen einen Long-Einstieg aus, andernfalls ein Short-Einstieg. Positionen werden nur geöffnet, wenn kein aktiver Trade vorhanden ist.
  • Ordergröße: starten Sie mit InitialVolume. Nach jedem Verlust-Trade wird die nächste Ordergröße zu PreviousVolume * MartingaleMultiplier (normalisiert auf den Volumen-Schritt des Instruments). Gewinn-Trades setzen die Größe auf InitialVolume zurück, sobald das realisierte Guthaben ein neues Hoch verzeichnet; andernfalls setzt sich die Martingal-Expansion fort.
  • Stops und Ziele: Stop-Loss und Take-Profit werden in Pips vom Einstiegspreis berechnet. Ein Pip entspricht dem Preis-Schritt des Instruments.
  • Schwebender Drawdown: während eine Position aktiv ist, überwacht die Strategie das unrealisierte PnL. Wenn der Verlust MaxDrawdownPercent des realisierten Kontosaldos (Anfangsguthaben + realisiertes PnL) überschreitet, wird die Position sofort geschlossen.

Parameter

Parameter Standard Beschreibung
InitialVolume 0.1 Starthandelsvolumen.
StopLossPips 15 Stop-Abstand in Pips (0 deaktiviert den Stop).
TakeProfitPips 30 Take-Profit-Abstand in Pips (0 deaktiviert das Ziel).
MaxDrawdownPercent 75 Maximal tolerierter schwebender Verlust als Prozent des Guthabens.
MartingaleMultiplier 1.6 Volumen-Multiplikator nach einem Verlust.
DecisionInterval 9 Anzahl abgeschlossener Kerzen zwischen neuen Trade-Entscheidungen.
CandleType 1-Minuten-Zeitrahmen Kerzentyp für die Strategie.

Hinweise

  • Volumen wird automatisch an die VolumeStep-, MinVolume- und MaxVolume-Grenzen des Instruments normalisiert. Wenn die Normalisierung fehlschlägt, wird die Größe auf das Anfangsvolumen zurückgesetzt.
  • Stop-Loss- und Take-Profit-Levels basieren auf dem PriceStep des Instruments als ein Pip; überprüfen Sie den Schritt für exotische Symbole.
  • Der Drawdown-Schutz erfordert, dass sowohl PriceStep als auch StepPrice definiert sind; andernfalls wird die Sicherheitsprüfung übersprungen.
  • Da die Strategie auf Zufälligkeit beruht, variieren die Ergebnisse zwischen Läufen auch bei identischen Marktdaten, sofern der Zufalls-Seed nicht extern kontrolliert wird.
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>
/// Avalanche strategy using channel breakout with Highest/Lowest.
/// </summary>
public class AvalancheAvStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal? _prevHigh;
	private decimal? _prevLow;

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

	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

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

		_period = Param(nameof(Period), 14)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Channel period", "Indicators");
	}

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

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

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

		_prevHigh = null;
		_prevLow = null;

		var highest = new Highest { Length = Period };
		var lowest = new Lowest { Length = Period };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		var close = candle.ClosePrice;

		if (_prevHigh == null || _prevLow == null)
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		if (close > _prevHigh.Value && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (close < _prevLow.Value && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevHigh = high;
		_prevLow = low;
	}
}