Bollinger Stochastic Strategie
Bollinger Stochastic kombiniert Bollinger Bänder mit dem Stochastik-Oszillator, um überdehnte Bewegungen zu identifizieren. Wenn der Preis die äußere Bande berührt, während sich der Oszillator in einer Extremzone befindet, deutet dies auf einen möglichen Rückprall hin.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 133%. Die Strategie funktioniert am besten auf dem Kryptomarkt.
Das System handelt gegen diese Extreme: Long, wenn der Preis die untere Bande mit überverkauftem Stochastik berührt, und Short an der oberen Bande mit überkauftem Stochastik.
Ein prozentualer Stop begrenzt das Risiko, falls die Mean Reversion ausbleibt.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: Bollinger Bands, Stochastic
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- 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>
/// Strategy combining Bollinger Bands and Stochastic oscillator for mean-reversion.
/// Buys when price touches lower band with oversold stochastic, sells at upper band with overbought.
/// </summary>
public class BollingerStochasticStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<decimal> _stochOversold;
private readonly StrategyParam<decimal> _stochOverbought;
private readonly StrategyParam<int> _cooldownBars;
private decimal _stochK;
private int _cooldown;
/// <summary>
/// Data type for candles.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Period for Bollinger Bands calculation.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier for Bollinger Bands.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Stochastic oversold level.
/// </summary>
public decimal StochOversold
{
get => _stochOversold.Value;
set => _stochOversold.Value = value;
}
/// <summary>
/// Stochastic overbought level.
/// </summary>
public decimal StochOverbought
{
get => _stochOverbought.Value;
set => _stochOverbought.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="BollingerStochasticStrategy"/>.
/// </summary>
public BollingerStochasticStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetRange(10, 50)
.SetDisplay("BB Period", "Period for Bollinger Bands", "Bollinger Settings");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetDisplay("BB Deviation", "Standard deviation multiplier", "Bollinger Settings");
_stochOversold = Param(nameof(StochOversold), 20m)
.SetDisplay("Oversold Level", "Stochastic oversold level", "Stochastic Settings");
_stochOverbought = Param(nameof(StochOverbought), 80m)
.SetDisplay("Overbought Level", "Stochastic overbought level", "Stochastic Settings");
_cooldownBars = Param(nameof(CooldownBars), 50)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_stochK = 50;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var stochastic = new StochasticOscillator();
var subscription = SubscribeCandles(CandleType);
// Bind stochastic with BindEx
subscription.BindEx(stochastic, OnStochastic);
// Bind bollinger bands with BindEx
subscription
.BindEx(bollinger, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
var stochArea = CreateChartArea();
if (stochArea != null)
DrawIndicator(stochArea, stochastic);
}
}
private void OnStochastic(ICandleMessage candle, IIndicatorValue stochValue)
{
var stoch = (IStochasticOscillatorValue)stochValue;
if (stoch.K is decimal k)
_stochK = k;
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bb = (BollingerBandsValue)bbValue;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
var close = candle.ClosePrice;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Buy: price at lower band + stochastic oversold
if (close <= lower && _stochK < StochOversold && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Sell: price at upper band + stochastic overbought
else if (close >= upper && _stochK > StochOverbought && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long at middle band
if (Position > 0 && close > middle)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short at middle band
else if (Position < 0 && close < middle)
{
BuyMarket();
_cooldown = 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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class bollinger_stochastic_strategy(Strategy):
def __init__(self):
super(bollinger_stochastic_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("BB Period", "Period for Bollinger Bands", "Bollinger Settings")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("BB Deviation", "Standard deviation multiplier", "Bollinger Settings")
self._stoch_oversold = self.Param("StochOversold", 20.0) \
.SetDisplay("Oversold Level", "Stochastic oversold level", "Stochastic Settings")
self._stoch_overbought = self.Param("StochOverbought", 80.0) \
.SetDisplay("Overbought Level", "Stochastic overbought level", "Stochastic Settings")
self._cooldown_bars = self.Param("CooldownBars", 50) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._stoch_k = 50.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def stoch_oversold(self):
return self._stoch_oversold.Value
@property
def stoch_overbought(self):
return self._stoch_overbought.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnReseted(self):
super(bollinger_stochastic_strategy, self).OnReseted()
self._stoch_k = 50.0
self._cooldown = 0
def OnStarted2(self, time):
super(bollinger_stochastic_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self.bollinger_period
bollinger.Width = self.bollinger_deviation
stochastic = StochasticOscillator()
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stochastic, self._on_stochastic)
subscription.BindEx(bollinger, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
stoch_area = self.CreateChartArea()
if stoch_area is not None:
self.DrawIndicator(stoch_area, stochastic)
def _on_stochastic(self, candle, stoch_value):
if stoch_value.K is not None:
self._stoch_k = float(stoch_value.K)
def OnProcess(self, candle, bb_value):
if candle.State != CandleStates.Finished:
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 self._cooldown > 0:
self._cooldown -= 1
return
if close <= lower and self._stoch_k < self.stoch_oversold and self.Position == 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
elif close >= upper and self._stoch_k > self.stoch_overbought and self.Position == 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
if self.Position > 0 and close > middle:
self.SellMarket()
self._cooldown = self.cooldown_bars
elif self.Position < 0 and close < middle:
self.BuyMarket()
self._cooldown = self.cooldown_bars
def CreateClone(self):
return bollinger_stochastic_strategy()