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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class avalanche_av_strategy(Strategy):
def __init__(self):
super(avalanche_av_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 14) \
.SetDisplay("Period", "Channel period", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(avalanche_av_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(avalanche_av_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
close = float(candle.ClosePrice)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return avalanche_av_strategy()