Dieses Beispiel wandelt den ursprünglichen Expertenberater MQL „Bb_0_1“ in den hochrangigen StockSharp API um. Die Strategie überwacht ein Kerzenabonnement und verwendet Bollinger-Bänder, um den aktuellen Preis zu klammern. Wenn der Markt zwischen dem oberen und dem unteren Band liegt, platziert der Algorithmus dreischichtige Kauf-Stopp-Orders über dem Preis und dreischichtige Verkaufs-Stopp-Orders unter dem Preis. Jede Ebene ist mit individuellen Take-Profit-Abständen konfiguriert und nutzt dabei die gleiche Stopp-Referenz, die vom gegenüberliegenden Band übernommen wird.
Handelslogik
Abonnieren Sie den konfigurierten Zeitrahmen und berechnen Sie Bollinger Bänder mit dem gewünschten Zeitraum und der gewünschten Abweichung.
Geben Sie innerhalb des Handelsfensters (StartHour < Stunde < EndHour) und während der Preis zwischen den Bändern bleibt, ausstehende Aufträge auf:
Drei Kaufstopps auf dem aktuellen oberen Bandniveau mit um FirstTakeProfit, SecondTakeProfit und ThirdTakeProfit Preisschritten über dem Einstiegspunkt verschobenen Take-Profits.
Drei Verkaufsstopps auf dem aktuellen unteren Bandniveau mit gespiegelten Take-Profits unterhalb des Einstiegs.
Alle Einträge übernehmen das entgegengesetzte Band als anfänglichen Schutzstopp.
Ausstehende Aufträge werden automatisch neu registriert, wenn sich die Bänder dem Preis nähern, sodass die Aufträge den Indikatorumschlägen folgen.
Sobald eine Stop-Order ausgeführt wird, registriert die Strategie explizite Stop-Loss- und Take-Profit-Orders für das ausgeführte Volumen.
Der Trailing-Schutz ist optional: UseBandTrailingStop wählt das entgegengesetzte Band für das Trailing aus, andernfalls wird das mittlere Band (EMA) verwendet. Stopps fallen nur dann nach, wenn der Schlusskurs über den Einstiegspreis hinausgeht und der Indikatorwert ein besseres Niveau bietet.
Parameter
Name
Beschreibung
CandleType
Zeitrahmen, der für die Bollinger-Bandberechnungen verwendet wird.
Take-Profit-Abstände, ausgedrückt in Preisschritten für jede Ebene.
UseBandTrailingStop
Wählen Sie die nachgestellte Referenz aus: gegenüberliegendes Band (true) oder Bollinger Mittellinie (false).
Hinweise zur Implementierung
Das Bestellvolumen spiegelt den ursprünglichen Expert Advisor wider, indem eine statische Größe (Volume) verwendet wird. Die risikobasierte Positionsgrößenbestimmung aus dem Code MQL ist nicht implementiert, da die Beispielumgebung StockSharp keinen Kontoverlauf bereitstellt.
Indikatorverschiebungsparameter aus dem MQL-Skript werden nicht angezeigt, da die hohe Ebene API bereits ausgerichtete Werte für die aktuelle Kerze liefert.
Schutzaufträge sind normale Stop- und Limit-Aufträge, die immer dann aktualisiert werden, wenn die bandbasierten Trailing-Bedingungen das Stop-Level verbessern.
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>
/// Bollinger Band breakout strategy.
/// Buys when price closes above upper band, sells when price closes below lower band.
/// Exits at middle band.
/// </summary>
public class BollingerBandPendingStopsStrategy : Strategy
{
private readonly StrategyParam<int> _bandPeriod;
private readonly StrategyParam<decimal> _bandWidth;
private readonly StrategyParam<DataType> _candleType;
public int BandPeriod { get => _bandPeriod.Value; set => _bandPeriod.Value = value; }
public decimal BandWidth { get => _bandWidth.Value; set => _bandWidth.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BollingerBandPendingStopsStrategy()
{
_bandPeriod = Param(nameof(BandPeriod), 20)
.SetDisplay("Band Period", "Bollinger bands period", "Indicators");
_bandWidth = Param(nameof(BandWidth), 1m)
.SetDisplay("Band Width", "Bollinger bands deviation", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BandPeriod, Width = BandWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!value.IsFinal || value.IsEmpty)
return;
var bbVal = value.IsEmpty ? null : value as BollingerBandsValue;
if (bbVal == null)
return;
var upper = bbVal.UpBand;
var lower = bbVal.LowBand;
var middle = bbVal.MovingAverage;
if (upper == null || lower == null || middle == null)
return;
var close = candle.ClosePrice;
// Breakout above upper band - buy
if (close > upper.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakout below lower band - sell
else if (close < lower.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit at middle band
else if (Position > 0 && close < middle.Value)
{
SellMarket();
}
else if (Position < 0 && close > middle.Value)
{
BuyMarket();
}
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class bollinger_band_pending_stops_strategy(Strategy):
def __init__(self):
super(bollinger_band_pending_stops_strategy, self).__init__()
self._band_period = self.Param("BandPeriod", 20) \
.SetDisplay("Band Period", "Bollinger bands period", "Indicators")
self._band_width = self.Param("BandWidth", 1.0) \
.SetDisplay("Band Width", "Bollinger bands deviation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def band_period(self):
return self._band_period.Value
@property
def band_width(self):
return self._band_width.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_band_pending_stops_strategy, self).OnReseted()
def OnStarted2(self, time):
super(bollinger_band_pending_stops_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.band_period
bb.Width = self.band_width
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.process_candle).Start()
def process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFinal or bb_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
close = float(candle.ClosePrice)
if close > upper and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < lower and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif self.Position > 0 and close < middle:
self.SellMarket()
elif self.Position < 0 and close > middle:
self.BuyMarket()
def CreateClone(self):
return bollinger_band_pending_stops_strategy()