Bollinger Winner Pro-Strategie
Bollinger Winner Pro erweitert die Lite-Version durch modulare Filter und Risikokontrollen. Es sucht weiterhin nach Preisen, die außerhalb der Bollinger Bands schließen, aber Trades werden nur ausgeführt, wenn optionale Bestätigungen übereinstimmen.
Trader können RSI-, Aroon- und Moving-Average-Filter aktivieren, um Momentum und Trendrichtung zu bestätigen. Ein integrierter Stop-Loss kann ebenfalls aktiviert werden, um das Risiko zu begrenzen. Diese Flexibilität ermöglicht es der Strategie, sich an verschiedene Märkte oder Testanforderungen anzupassen.
Der Ansatz zielt auf Mean Reversion: Sobald der Preis wieder in die Bands eintritt oder die gegenüberliegende Seite berührt, wird die Position geschlossen oder der Stop ausgelöst. Da mehrere Filter gestapelt werden können, sind Signale seltener, aber von höherer Qualität.
Details
- Daten: Kurskerzen.
- Einstiegskriterien: Kerze schließt außerhalb eines Bandes und alle aktivierten Filter stimmen zu.
- Ausstiegskriterien: Rückkehr zum mittleren/gegenüberliegenden Band oder Stop-Loss wenn
UseSLwahr ist. - Stops: Optionaler Stop-Loss, gesteuert durch
UseSL. - Standardwerte:
UseRSI= TrueUseAroon= FalseUseMA= TrueUseSL= True
- Filter:
- Kategorie: Mean Reversion mit Bestätigungen
- Richtung: Long/Short
- Indikatoren: Bollinger Bands, RSI, Aroon, Moving Average
- Komplexität: Fortgeschritten
- Risikolevel: Mittel
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>
/// Bollinger Bands Winner PRO Strategy with RSI and MA filters.
/// Buys when price touches lower BB, RSI confirms oversold, and price above MA.
/// Sells when price touches upper BB, RSI confirms overbought, and price below MA.
/// </summary>
public class BollingerWinnerProStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleTypeParam;
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbMultiplier;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<int> _cooldownBars;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BBLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
/// <summary>
/// Bollinger Bands standard deviation multiplier.
/// </summary>
public decimal BBMultiplier
{
get => _bbMultiplier.Value;
set => _bbMultiplier.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RSILength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RSIOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RSIOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// Moving average period.
/// </summary>
public int MALength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
private BollingerBands _bollinger;
private RelativeStrengthIndex _rsi;
private ExponentialMovingAverage _ma;
private int _cooldownRemaining;
public BollingerWinnerProStrategy()
{
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
_bbLength = Param(nameof(BBLength), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Bollinger Bands");
_bbMultiplier = Param(nameof(BBMultiplier), 1.5m)
.SetDisplay("BB StdDev", "Bollinger Bands standard deviation multiplier", "Bollinger Bands");
_rsiLength = Param(nameof(RSILength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI Filter");
_rsiOversold = Param(nameof(RSIOversold), 40m)
.SetDisplay("RSI Oversold", "RSI oversold threshold", "RSI Filter");
_rsiOverbought = Param(nameof(RSIOverbought), 60m)
.SetDisplay("RSI Overbought", "RSI overbought threshold", "RSI Filter");
_maLength = Param(nameof(MALength), 50)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Moving average period", "Moving Average");
_cooldownBars = Param(nameof(CooldownBars), 20)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bollinger = null;
_rsi = null;
_ma = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bollinger = new BollingerBands
{
Length = BBLength,
Width = BBMultiplier
};
_rsi = new RelativeStrengthIndex { Length = RSILength };
_ma = new ExponentialMovingAverage { Length = MALength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_bollinger, _rsi, _ma, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bollinger);
DrawIndicator(area, _ma);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle,
IIndicatorValue bollingerValue, IIndicatorValue rsiValue, IIndicatorValue maValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bollinger.IsFormed || !_rsi.IsFormed || !_ma.IsFormed)
return;
var bb = (BollingerBandsValue)bollingerValue;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
if (rsiValue.IsEmpty || maValue.IsEmpty)
return;
var rsi = rsiValue.ToDecimal();
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var close = candle.ClosePrice;
// Buy: price at/below lower BB + RSI oversold
if (close <= lower && rsi < RSIOversold && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: price at/above upper BB + RSI overbought
else if (close >= upper && rsi > RSIOverbought && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long at middle band
else if (Position > 0 && close >= middle)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short at middle band
else if (Position < 0 && close <= middle)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, RelativeStrengthIndex, ExponentialMovingAverage, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class bollinger_winner_pro_strategy(Strategy):
"""Bollinger Bands Winner PRO Strategy with RSI and MA filters."""
def __init__(self):
super(bollinger_winner_pro_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General")
self._bb_length = self.Param("BBLength", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Bollinger Bands")
self._bb_multiplier = self.Param("BBMultiplier", 1.5) \
.SetDisplay("BB StdDev", "Bollinger Bands standard deviation multiplier", "Bollinger Bands")
self._rsi_length = self.Param("RSILength", 14) \
.SetDisplay("RSI Length", "RSI period", "RSI Filter")
self._rsi_oversold = self.Param("RSIOversold", 40.0) \
.SetDisplay("RSI Oversold", "RSI oversold threshold", "RSI Filter")
self._rsi_overbought = self.Param("RSIOverbought", 60.0) \
.SetDisplay("RSI Overbought", "RSI overbought threshold", "RSI Filter")
self._ma_length = self.Param("MALength", 50) \
.SetDisplay("MA Length", "Moving average period", "Moving Average")
self._cooldown_bars = self.Param("CooldownBars", 20) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._bollinger = None
self._rsi = None
self._ma = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_winner_pro_strategy, self).OnReseted()
self._bollinger = None
self._rsi = None
self._ma = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(bollinger_winner_pro_strategy, self).OnStarted2(time)
self._bollinger = BollingerBands()
self._bollinger.Length = int(self._bb_length.Value)
self._bollinger.Width = float(self._bb_multiplier.Value)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = int(self._rsi_length.Value)
self._ma = ExponentialMovingAverage()
self._ma.Length = int(self._ma_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._bollinger, self._rsi, self._ma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._bollinger)
self.DrawIndicator(area, self._ma)
self.DrawOwnTrades(area)
def _on_process(self, candle, bb_value, rsi_value, ma_value):
if candle.State != CandleStates.Finished:
return
if not self._bollinger.IsFormed or not self._rsi.IsFormed or not self._ma.IsFormed:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
if rsi_value.IsEmpty or ma_value.IsEmpty:
return
rsi = float(IndicatorHelper.ToDecimal(rsi_value))
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
close = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
if close <= lower and rsi < float(self._rsi_oversold.Value) and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif close >= upper and rsi > float(self._rsi_overbought.Value) and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and close >= middle:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and close <= middle:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
def CreateClone(self):
return bollinger_winner_pro_strategy()