Estrategia de Rompimiento Bollinger 4H
La estrategia de Rompimiento Bollinger 4H opera rompimientos de Bandas de Bollinger en el gráfico de cuatro horas. Las posiciones largas se abren cuando el precio cruza por encima de la banda inferior con confirmación de volumen y tendencia. Las posiciones cortas se abren cuando el precio cruza por debajo de la banda superior y el RSI está por debajo de un umbral.
Detalles
- Criterios de entrada:
- Largo: El cierre cruza por encima de la banda inferior, volumen por encima de su SMA y precio por encima de la SMA de tendencia.
- Corto: El cierre cruza por debajo de la banda superior, volumen por encima de su SMA, precio por debajo de la SMA de tendencia, RSI < 85.
- Largo/Corto: Ambos lados.
- Criterios de salida:
- Largo: El cierre cruza por encima de la banda superior.
- Corto: El cierre cruza por debajo de la banda inferior.
- Stops: Ninguno.
- Valores predeterminados:
BollingerLength= 20BollingerMultiplier= 1.8VolumeLength= 20TrendLength= 80RsiLength= 14UseLongSignals= TrueUseShortSignals= True
- Filtros:
- Categoría: Ruptura de tendencia
- Dirección: Ambos
- Indicadores: Bollinger Bands, SMA de volumen, SMA de tendencia, RSI
- Stops: Ninguno
- Complejidad: Moderado
- Marco temporal: 4H
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Bollinger Breakout Strategy - trades Bollinger Band breakouts with trend and RSI filters.
/// Buys when close crosses above lower band with uptrend.
/// Sells when close crosses below upper band with downtrend.
/// </summary>
public class BollingerBreakout2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerLength;
private readonly StrategyParam<decimal> _bollingerMultiplier;
private readonly StrategyParam<int> _trendLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevClose;
private decimal _prevUpper;
private decimal _prevLower;
private bool _isInitial;
private int _cooldownRemaining;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int BollingerLength { get => _bollingerLength.Value; set => _bollingerLength.Value = value; }
public decimal BollingerMultiplier { get => _bollingerMultiplier.Value; set => _bollingerMultiplier.Value = value; }
public int TrendLength { get => _trendLength.Value; set => _trendLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public BollingerBreakout2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_bollingerLength = Param(nameof(BollingerLength), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Length", "Bollinger Bands period", "Bollinger Bands");
_bollingerMultiplier = Param(nameof(BollingerMultiplier), 1.8m)
.SetGreaterThanZero()
.SetDisplay("StdDev Multiplier", "Standard deviation multiplier", "Bollinger Bands");
_trendLength = Param(nameof(TrendLength), 50)
.SetGreaterThanZero()
.SetDisplay("Trend MA Length", "Length for trend moving average", "Filters");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI calculation length", "Filters");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevUpper = 0;
_prevLower = 0;
_isInitial = true;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var trendSma = new SimpleMovingAverage { Length = TrendLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var bollinger = new BollingerBands { Length = BollingerLength, Width = BollingerMultiplier };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, trendSma, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue trendValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (bollingerValue is not BollingerBandsValue bb)
return;
if (bb.UpBand is not decimal upperBand ||
bb.LowBand is not decimal lowerBand ||
bb.MovingAverage is not decimal middleBand)
return;
var trend = trendValue.ToDecimal();
var rsi = rsiValue.ToDecimal();
var close = candle.ClosePrice;
if (_isInitial)
{
_prevClose = close;
_prevUpper = upperBand;
_prevLower = lowerBand;
_isInitial = false;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevClose = close;
_prevUpper = upperBand;
_prevLower = lowerBand;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = close;
_prevUpper = upperBand;
_prevLower = lowerBand;
return;
}
var trendConditionLong = close > trend;
var trendConditionShort = close < trend;
// Long entry: close breaks above upper band + uptrend
if (close > upperBand && _prevClose <= _prevUpper && Position <= 0 && trendConditionLong)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Short entry: close breaks below lower band + downtrend
else if (close < lowerBand && _prevClose >= _prevLower && Position >= 0 && trendConditionShort)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: close drops below middle band
else if (Position > 0 && close < middleBand)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: close rises above middle band
else if (Position < 0 && close > middleBand)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevClose = close;
_prevUpper = upperBand;
_prevLower = lowerBand;
}
}
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, SimpleMovingAverage, RelativeStrengthIndex, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class bollinger_breakout2_strategy(Strategy):
"""Bollinger Breakout Strategy."""
def __init__(self):
super(bollinger_breakout2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bollinger_length = self.Param("BollingerLength", 20) \
.SetDisplay("Bollinger Length", "Bollinger Bands period", "Bollinger Bands")
self._bollinger_multiplier = self.Param("BollingerMultiplier", 1.8) \
.SetDisplay("StdDev Multiplier", "Standard deviation multiplier", "Bollinger Bands")
self._trend_length = self.Param("TrendLength", 50) \
.SetDisplay("Trend MA Length", "Length for trend moving average", "Filters")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI calculation length", "Filters")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._prev_close = 0.0
self._prev_upper = 0.0
self._prev_lower = 0.0
self._is_initial = True
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_breakout2_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_upper = 0.0
self._prev_lower = 0.0
self._is_initial = True
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(bollinger_breakout2_strategy, self).OnStarted2(time)
trend_sma = SimpleMovingAverage()
trend_sma.Length = int(self._trend_length.Value)
rsi = RelativeStrengthIndex()
rsi.Length = int(self._rsi_length.Value)
bb = BollingerBands()
bb.Length = int(self._bollinger_length.Value)
bb.Width = self._bollinger_multiplier.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, trend_sma, rsi, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def _on_process(self, candle, bb_value, trend_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if bb_value.IsEmpty or trend_value.IsEmpty or rsi_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper_band = float(bb_value.UpBand)
lower_band = float(bb_value.LowBand)
middle_band = float(bb_value.MovingAverage)
trend = float(IndicatorHelper.ToDecimal(trend_value))
close = float(candle.ClosePrice)
if self._is_initial:
self._prev_close = close
self._prev_upper = upper_band
self._prev_lower = lower_band
self._is_initial = False
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_close = close
self._prev_upper = upper_band
self._prev_lower = lower_band
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_upper = upper_band
self._prev_lower = lower_band
return
cooldown = int(self._cooldown_bars.Value)
trend_long = close > trend
trend_short = close < trend
if close > upper_band and self._prev_close <= self._prev_upper and self.Position <= 0 and trend_long:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif close < lower_band and self._prev_close >= self._prev_lower and self.Position >= 0 and trend_short:
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_band:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and close > middle_band:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_close = close
self._prev_upper = upper_band
self._prev_lower = lower_band
def CreateClone(self):
return bollinger_breakout2_strategy()