Diese Strategie reproduziert den MetaTrader-BADX-Expertenberater unter Verwendung der StockSharp High-Level-API. Sie kombiniert den Average Directional Index (ADX) mit Bollinger Bands, um Range-Bedingungen zu handeln: Wenn der ADX unter einen konfigurierbaren Schwellenwert fällt und der Preis das äußere Band berührt, faded die Strategie die Bewegung in Erwartung einer Mean Reversion. Alle Schutzorders, einschließlich Stop-Loss, Take-Profit und optionalem Trailing-Stop, werden automatisch durch StartProtection verwaltet.
Funktionsweise
Abonniert die konfigurierte Kerzenserie und fügt sowohl einen AverageDirectionalIndex als auch einen BollingerBands-Indikator über High-Level-Bindings ein.
Für jede abgeschlossene Kerze erhält der Callback den ADX-Wert sowie die obere und untere Bollinger-Hülle.
Wenn der ADX unter AdxLevel liegt, gilt der Markt als trendlos:
Wenn der Schlusskurs unterhalb des unteren Bandes liegt und keine offene Position vorhanden ist, kauft die Strategie zum Marktpreis.
Wenn der Schlusskurs oberhalb des oberen Bandes liegt und keine offene Position vorhanden ist, verkauft die Strategie zum Marktpreis.
Das Risikomanagement wandelt Pip-Abstände in absolute Preis-Offsets um. Stop-Loss, Take-Profit und Trailing-Parameter (falls aktiviert) werden unmittelbar nach Einstiegen über den Schutzmanager angewendet.
Es kann immer nur eine Position aktiv sein. Ausstiege erfolgen durch Schutzorders oder Trailing-Stop-Anpassungen.
Parameter
CandleType (DataType): Zeitrahmen für Indikatorberechnungen. Standard: 15-Minuten-Kerzen.
AdxPeriod (int): Mittelungsperiode für den ADX-Indikator. Standard: 30.
AdxLevel (decimal): Maximaler ADX-Wert, der noch als Ranging-Markt gilt. Standard: 20.
BollingerPeriod (int): Periode für den gleitenden Durchschnitt der Bollinger Bands. Standard: 10.
BollingerDeviation (decimal): Standardabweichungs-Multiplikator für die Bollinger Bands. Standard: 1.5.
StopLossPips (decimal): Stop-Loss-Abstand in Pips. Standard: 50.
TakeProfitPips (decimal): Take-Profit-Abstand in Pips. Standard: 50.
TrailingStopPips (decimal): Trailing-Stop-Abstand in Pips. Standard: 5.
TrailingStepPips (decimal): Minimale Preisverbesserung in Pips, bevor der Trailing-Stop angepasst wird. Standard: 5.
Verwendung
Die Strategie einem Wertpapier zuordnen und die Parameter nach Wunsch konfigurieren.
Strategie starten. Sie abonniert automatisch den benötigten Kerzenstrom, baut die Indikatoren auf und richtet Schutzorders ein.
Trades im Chart-Bereich überwachen: Kerzen, die Bollinger Bands und ausgeführte Orders werden visualisiert, wenn die Plattform Charting unterstützt.
Risikoparameter (Stop-Loss, Take-Profit, Trailing-Abstände) an die Instrument-Volatilität oder persönliche Präferenzen anpassen.
Hinweise
Nur abgeschlossene Kerzen werden verarbeitet, um vorzeitige Einstiege zu vermeiden.
Die Pip-Größe wird aus dem PriceStep des Instruments abgeleitet; wenn das Instrument 3 oder 5 Dezimalstellen verwendet, wird der Pip um den Faktor zehn angepasst, was den ursprünglichen Expertenberater nachahmt.
Die Strategie hält Volume standardmäßig auf 1. Die Volume-Eigenschaft der Basisklasse anpassen, um die bevorzugte Handelsgröße zu erreichen.
Alle Inline-Kommentare im Quellcode sind gemäß den Repository-Richtlinien auf Englisch verfasst.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// BADX ADX Bollinger strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class BadxAdxBollingerStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public BadxAdxBollingerStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class badx_adx_bollinger_strategy(Strategy):
def __init__(self):
super(badx_adx_bollinger_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(badx_adx_bollinger_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(badx_adx_bollinger_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return badx_adx_bollinger_strategy()