Die 1H Bollinger Bands-Strategie adaptiert den MetaTrader-Experten "1H Bolinger Bands" an die High-Level-API von StockSharp. Die Idee ist, Bounces von den täglichen Bollinger Bands zu handeln, während der stündliche Trend ausgerichtet ist und der langfristige monatliche MACD die Richtung bestätigt. Die Strategie arbeitet standardmäßig auf dem H1-Zeitrahmen und stützt sich auf zusätzliche höhere Zeitrahmen-Datenströme zur Bestätigung.
Trading-Logik
Trendfilter: Zwei lineare gewichtete gleitende Durchschnitte (LWMA 250 und 500) auf dem Basiszeitrahmen stellen sicher, dass nur Trades zugelassen werden, die mit der dominierenden Richtung übereinstimmen.
Auslösemuster: Auf dem höheren Zeitrahmen (standardmäßig täglich) beobachtet die Strategie eine Kerze, deren Tief unter das untere Bollinger Band fällt und die nächste Kerze darüber öffnet (umgekehrt für Shorts mit dem oberen Band). Dies repliziert die ursprüngliche Bounce-Bedingung.
Momentum-Bestätigung: Momentum (Periode 14) wird auf dem höheren Zeitrahmen berechnet. Mindestens eine der drei jüngsten Momentum-Abweichungen von 100 muss den konfigurierten Schwellenwert (Standard 0.3) überschreiten.
MACD-Filter: Ein monatlicher MACD (12/26/9) muss dem Signal zustimmen. Bei Long-Trades muss die MACD-Linie über der Signallinie liegen, bei Shorts darunter.
Einstieg: Wenn alle Filter übereinstimmen, öffnet die Strategie eine Marktorder. Wenn eine entgegengesetzte Position offen ist, neutralisiert das angeforderte Volumen die bestehende Exposition und dreht die Richtung um.
Positionsverwaltung
Das Risikomanagement wird direkt in der Strategie mit Pip-Abständen implementiert, die über Security.PriceStep konvertiert werden:
Stop Loss: Schließt die Position, sobald der Preis um die konfigurierte Pip-Anzahl gegen den Einstieg läuft.
Take Profit: Sichert Gewinne, wenn der Preis das konfigurierte Pip-Ziel erreicht.
Trailing Stop (optional): Wenn aktiviert und der Kurs die Trailing-Distanz überschreitet, folgt ein internes Trailing-Niveau dem Preis. Eine Kerze, die dieses Niveau durchbricht, schließt den Trade.
Break-Even (optional): Nachdem der Preis um die Auslösedistanz vorgerückt ist, wird das Stop-Niveau auf den Einstiegspreis plus dem konfigurierten Offset verschoben (minus für Shorts). Ein Rückzug auf dieses Niveau beendet die Position.
Die geldbasierte Gewinnverwaltung des ursprünglichen Experten wird nicht nachgebildet; die StockSharp-Version konzentriert sich auf preisbasierte Kontrollen, um börsenunabhängig zu bleiben.
Parameter
Parameter
Beschreibung
Standard
CandleType
Basiszeitrahmen für die Signalauswertung.
1-Stunden-Kerzen
HigherTimeFrame
Zeitrahmen für Bollinger Bands und Momentum.
1-Tages-Kerzen
MacdTimeFrame
Zeitrahmen für den bestätigenden MACD.
30-Tages-Kerzen
FastMaPeriod / SlowMaPeriod
Schnelle/langsame LWMA-Längen auf dem Basiszeitrahmen.
6 / 85
TrendFastPeriod / TrendSlowPeriod
Langfristige LWMA-Trendfilter.
250 / 500
MomentumPeriod
Momentum-Lookback auf dem höheren Zeitrahmen.
14
MomentumThreshold
Minimale absolute Abweichung von 100 für Momentum.
Alle numerischen Parameter werden über StrategyParam<T> bereitgestellt und können in Designer/Runner optimiert werden.
Implementierungshinweise
Die Strategie abonniert gleichzeitig drei Kerzenströme: Basiszeitrahmen, höherer Zeitrahmen für Bollinger/Momentum und MACD-Zeitrahmen.
Momentum verwendet den Standard-StockSharp-Momentum-Indikator und speichert die letzten drei Abweichungen, um die MQL-Logik nachzubilden.
Tradingvolumen und Pip-Abstände gehen davon aus, dass Security.PriceStep korrekt gefüllt ist; andernfalls wird die Schutzlogik nicht ausgelöst.
StockSharp pflegt eine einzelne Nettoposition. Das "Max_Trades"-Skalierungsverhalten des ursprünglichen Skripts wird auf eine einzelne aggregierte Position in diesem Port vereinfacht.
Equity-basierte Stop-outs und Geld-Trailing-Funktionen der MQL-Version werden absichtlich weggelassen, um die Implementierung börsenunabhängig zu halten.
Verwendung
Hängen Sie die Strategie an ein Instrument an, das stündliche, tägliche und monatliche Kerzen bereitstellt (oder passen Sie die Parameter entsprechend an).
Stellen Sie sicher, dass das Instrument PriceStep bereitstellt, damit Pip-Abstände in Preis-Offsets übersetzt werden.
Konfigurieren Sie das gewünschte Volumen und die Risikoparameter in der UI oder im Code, bevor Sie die Strategie starten.
Starten Sie die Strategie; sie abonniert automatisch die erforderlichen Daten, wertet Signale auf geschlossenen Kerzen aus und verwaltet die Position mit den konfigurierten Schutzregeln.
Bekannte Unterschiede zum MQL-Experten
Geldbasiertes Trailing und Gesamt-Equity-Stop sind nicht implementiert; nur preisbasierte Kontrollen bleiben erhalten.
Alerts, E-Mails und Push-Benachrichtigungen aus dem MQL-Code werden weggelassen.
Order-Stacking wird durch das Single-Net-Position-Modell von StockSharp ersetzt.
Diese Anpassungen halten die Strategie idiomatisch für StockSharp, während die Kern-Trading-Idee des ursprünglichen Experten erhalten bleibt.
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;
public class OneHBollingerBandsStrategy : 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 OneHBollingerBandsStrategy()
{
_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 one_h_bollinger_bands_strategy(Strategy):
def __init__(self):
super(one_h_bollinger_bands_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(one_h_bollinger_bands_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(one_h_bollinger_bands_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 one_h_bollinger_bands_strategy()