Die Bollinger RSI MA-Strategie portiert die MetaTrader-Experten BolRSIMAs auf die StockSharp-High-Level-API. Das System kombiniert a
Bollinger-Bandausbruch, ein RSI-Filter und ein exponentieller gleitender Durchschnitt mit höherem Zeitrahmen (EMA) zur Identifizierung von Pullback-Trades
die Richtung des vorherrschenden Trends. Die automatische Losgröße bleibt erhalten: Wenn sie aktiviert ist, konvertiert die Strategie das konfigurierte Risiko
Bruchteil des Portfolio-Eigenkapitals in Volumen unter Verwendung des aktuellen Preises, der Stop-Distanz Bollinger und der Kontraktgröße des Instruments.
Handelslogik
Abonnieren Sie die primäre Kerzenserie (Standard: 1 Stunde) und berechnen Sie Bollinger Bänder und RSI im selben Zeitrahmen.
Abonnieren Sie Tageskerzen und geben Sie deren Schlusskurse in einen EMA mit 200 Perioden ein, um den verwendeten Filter für höhere Zeitrahmen zu reproduzieren
im Original EA.
Generieren Sie ein Long-Setup, wenn die letzte Kerze unterhalb des unteren Bandes schließt und der RSI-Wert unter dem überverkauften Schwellenwert liegt
und der Schlusskurs bleibt über dem Tageskurs EMA. Ein Short-Setup wird durch einen Schlusskurs über dem oberen Band, RSI über dem, ausgelöst
Überkaufschwelle und Preis unter dem täglichen EMA.
Offene Positionen nur, wenn kein Exposure aktiv ist. Jeder neue Handel speichert daraus abgeleitete Stop-Loss- und Take-Profit-Werte
vorherige Bollinger-Werte: Longs verwenden lowerBand - StopLossOffset und zielen auf das mittlere Band; Shorts verwenden
upperBand + StopLossOffset und zielen Sie auch auf das mittlere Band.
Bei jeder fertigen Kerze vergleicht die Strategie die Kerzenextremwerte mit den Schutzniveaus. Wenn das Tief/Hoch das berührt
Stop oder Target, die Position wird sofort geschlossen, wobei die Schutzaufträge der MetaTrader-Version nachgeahmt werden.
Parameter
Name
Standard
Beschreibung
CandleType
1-Stunden-Kerzen
Primärer Zeitrahmen verarbeitet von Bollinger Bändern und RSI.
DailyCandleType
1-Tages-Kerzen
Höherer Zeitrahmen, der den EMA-Trendfilter speist.
BollingerPeriod
20
Anzahl der Kerzen, die zum Aufbau von Bollinger-Bändern verwendet werden.
BollingerDeviation
2
Bandbreitenmultiplikator.
RsiPeriod
13
RSI Glättungslänge.
RsiUpperLevel
70
Für Short-Trades ist ein Überkaufschwellenwert erforderlich.
RsiLowerLevel
30
Für Long-Trades ist ein Überverkaufsschwellenwert erforderlich.
MaPeriod
200
Länge des höheren Zeitrahmens EMA.
StopLossOffset
0.0238
Zusätzlicher Puffer, der außerhalb des Bandes hinzugefügt wird, bevor der Stop-Loss platziert wird.
UseAutoLot
true
Ermöglicht eine risikobasierte Positionsgrößenbestimmung.
RiskPerTrade
0.05
Anteil des Eigenkapitals, der jedem Trade zugewiesen wird, wenn Auto-Lot aktiv ist.
FixedVolume
0.1
Bestellgröße, wenn die automatische Losgrößenbestimmung deaktiviert ist.
Geldmanagement
Wenn UseAutoLot gleich true ist, entspricht das Volumen (equity * RiskPerTrade) / (StopLossOffset * price * contractSize), gerundet auf
Umtauschlimits. Dies spiegelt die MetaTrader-Autolot-Routine wider, die den Risikobetrag durch die Stoppdistanz in Bargeld und dividiert
die Vertragsgröße.
Wenn keine Aktieninformationen oder kein Preis verfügbar sind, fällt die Strategie auf FixedVolume zurück und berücksichtigt dabei weiterhin die
Beschränkungen der Instrumentenlautstärke.
Unterschiede zum MetaTrader-Experten
Stop-Loss- und Take-Profit-Orders werden durch Kerzenhochs und -tiefs anstelle von serverseitigen Orders simuliert, die dem entsprechen
Ergebnis des ursprünglichen EA, ohne auf synchrone Auftragsübermittlung angewiesen zu sein.
Der EMA-Filter verwendet die Kerzenabonnements von StockSharp; Es besteht keine Abhängigkeit von MetaTrader-spezifischen täglichen Datenabrufen.
Bei der Risikogröße werden StockSharp Sicherheitsgrenzen (MinVolume, MaxVolume, VolumeStep) berücksichtigt, um abgelehnte Aufträge an Börsen zu vermeiden.
Anwendungstipps
Passen Sie StopLossOffset an, wenn Sie Symbole mit unterschiedlichen Preisskalen handeln, sodass der Abstand den ursprünglichen EAs entspricht
2,38 % Puffer über dem Bollinger-Band.
Wenn das Instrument einen anderen täglichen Zeitrahmen verwendet (z. B. Krypto-Börsen), ändern Sie DailyCandleType entsprechend, sodass EMA
spiegelt den beabsichtigten Trendfilter wider.
Kombinieren Sie die Strategie mit externen Trailing Stops, wenn Sie dynamische Ausstiege bevorzugen, sobald das mittlere Bandziel erreicht ist.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Bollinger + RSI + MA strategy.
/// Buys when price at lower BB and RSI oversold, sells at upper BB and RSI overbought.
/// </summary>
public class BollingerRsiMaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bandPercent;
private readonly StrategyParam<int> _signalCooldownCandles;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
public decimal BandPercent { get => _bandPercent.Value; set => _bandPercent.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public BollingerRsiMaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bandPercent = Param(nameof(BandPercent), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Band Percent", "MA percentage band width", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candlesSinceTrade = SignalCooldownCandles;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ma = new SimpleMovingAverage { Length = BbPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal maValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
var close = candle.ClosePrice;
var upper = maValue * (1 + BandPercent);
var lower = maValue * (1 - BandPercent);
// Mean reversion: buy at lower band, sell at upper band
if (close < lower && rsiValue < 35 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (close > upper && rsiValue > 65 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
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 RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bollinger_rsi_ma_strategy(Strategy):
def __init__(self):
super(bollinger_rsi_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._bb_period = self.Param("BbPeriod", 20)
self._band_percent = self.Param("BandPercent", 0.01)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def BbPeriod(self):
return self._bb_period.Value
@BbPeriod.setter
def BbPeriod(self, value):
self._bb_period.Value = value
@property
def BandPercent(self):
return self._band_percent.Value
@BandPercent.setter
def BandPercent(self, value):
self._band_percent.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(bollinger_rsi_ma_strategy, self).OnReseted()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(bollinger_rsi_ma_strategy, self).OnStarted2(time)
self._candles_since_trade = self.SignalCooldownCandles
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
ma = SimpleMovingAverage()
ma.Length = self.BbPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, ma, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, ma_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
ma_val = float(ma_value)
upper = ma_val * (1.0 + self.BandPercent)
lower = ma_val * (1.0 - self.BandPercent)
if close < lower and rsi_val < 35 and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif close > upper and rsi_val > 65 and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return bollinger_rsi_ma_strategy()