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
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>
/// 4H Bollinger Breakout strategy.
/// A long opens when the close crosses above the lower band with volume above its SMA and price above the trend SMA. A short opens
/// when the close crosses below the upper band with volume above its SMA, price below the trend SMA and RSI below 85. A long closes
/// when the close crosses above the upper band and a short when it crosses below the lower band.
/// </summary>
public class BollingerBreakout2Strategy : Strategy
{
private const decimal _rsiShortLimit = 85m;
private readonly StrategyParam<int> _bollingerLength;
private readonly StrategyParam<decimal> _bollingerMultiplier;
private readonly StrategyParam<int> _volumeLength;
private readonly StrategyParam<int> _trendLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<bool> _useLongSignals;
private readonly StrategyParam<bool> _useShortSignals;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _volumeSma;
private decimal? _prevClose;
private decimal? _prevUpper;
private decimal? _prevLower;
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerLength
{
get => _bollingerLength.Value;
set => _bollingerLength.Value = value;
}
/// <summary>
/// Bollinger Bands standard deviation multiplier.
/// </summary>
public decimal BollingerMultiplier
{
get => _bollingerMultiplier.Value;
set => _bollingerMultiplier.Value = value;
}
/// <summary>
/// Period of the volume SMA.
/// </summary>
public int VolumeLength
{
get => _volumeLength.Value;
set => _volumeLength.Value = value;
}
/// <summary>
/// Period of the trend SMA.
/// </summary>
public int TrendLength
{
get => _trendLength.Value;
set => _trendLength.Value = value;
}
/// <summary>
/// Period of RSI.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// Allow long trades.
/// </summary>
public bool UseLongSignals
{
get => _useLongSignals.Value;
set => _useLongSignals.Value = value;
}
/// <summary>
/// Allow short trades.
/// </summary>
public bool UseShortSignals
{
get => _useShortSignals.Value;
set => _useShortSignals.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BollingerBreakout2Strategy()
{
_bollingerLength = Param(nameof(BollingerLength), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Length", "Bollinger Bands period", "Bollinger Bands");
_bollingerMultiplier = Param(nameof(BollingerMultiplier), 1.8m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Multiplier", "Standard deviation multiplier", "Bollinger Bands");
_volumeLength = Param(nameof(VolumeLength), 20)
.SetGreaterThanZero()
.SetDisplay("Volume Length", "Period of the volume SMA", "Filters");
_trendLength = Param(nameof(TrendLength), 80)
.SetGreaterThanZero()
.SetDisplay("Trend Length", "Period of the trend SMA", "Filters");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "Period of RSI", "Filters");
_useLongSignals = Param(nameof(UseLongSignals), true)
.SetDisplay("Use Long Signals", "Allow long trades", "General");
_useShortSignals = Param(nameof(UseShortSignals), true)
.SetDisplay("Use Short Signals", "Allow short trades", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_volumeSma = null;
_prevClose = null;
_prevUpper = null;
_prevLower = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevUpper = null;
_prevLower = null;
var bollinger = new BollingerBands { Length = BollingerLength, Width = BollingerMultiplier };
var trendSma = new SimpleMovingAverage { Length = TrendLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
_volumeSma = new SimpleMovingAverage { Length = VolumeLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, trendSma, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawIndicator(area, trendSma);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue trendValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
var volumeAverage = _volumeSma.Process(candle.TotalVolume, candle.ServerTime, true).ToDecimal();
if (!bollingerValue.IsFormed || bollingerValue is not BollingerBandsValue { UpBand: decimal upper, LowBand: decimal lower })
return;
var close = candle.ClosePrice;
var prevClose = _prevClose;
var prevUpper = _prevUpper;
var prevLower = _prevLower;
_prevClose = close;
_prevUpper = upper;
_prevLower = lower;
if (!_volumeSma.IsFormed || !trendValue.IsFormed || !rsiValue.IsFormed)
return;
if (prevClose is not decimal pc || prevUpper is not decimal pu || prevLower is not decimal pl)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var trend = trendValue.ToDecimal();
var rsi = rsiValue.ToDecimal();
var volumeHigh = candle.TotalVolume > volumeAverage;
var crossAboveLower = pc <= pl && close > lower;
var crossBelowUpper = pc >= pu && close < upper;
var crossAboveUpper = pc <= pu && close > upper;
var crossBelowLower = pc >= pl && close < lower;
var longSignal = UseLongSignals && crossAboveLower && volumeHigh && close > trend;
var shortSignal = UseShortSignals && crossBelowUpper && volumeHigh && close < trend && rsi < _rsiShortLimit;
if (longSignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && crossAboveUpper)
SellMarket(Position);
else if (Position < 0 && crossBelowLower)
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, SimpleMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
RSI_SHORT_LIMIT = 85
class bollinger_breakout2_strategy(Strategy):
"""
4H Bollinger Breakout strategy.
A long opens when the close crosses above the lower band with volume above its SMA and price above the trend SMA. A short opens
when the close crosses below the upper band with volume above its SMA, price below the trend SMA and RSI below 85. A long closes
when the close crosses above the upper band and a short when it crosses below the lower band.
"""
def __init__(self):
super(bollinger_breakout2_strategy, self).__init__()
self._bollinger_length = self.Param("BollingerLength", 20).SetGreaterThanZero().SetDisplay("Bollinger Length", "Bollinger Bands period", "Bollinger Bands")
self._bollinger_multiplier = self.Param("BollingerMultiplier", 1.8).SetGreaterThanZero().SetDisplay("Bollinger Multiplier", "Standard deviation multiplier", "Bollinger Bands")
self._volume_length = self.Param("VolumeLength", 20).SetGreaterThanZero().SetDisplay("Volume Length", "Period of the volume SMA", "Filters")
self._trend_length = self.Param("TrendLength", 80).SetGreaterThanZero().SetDisplay("Trend Length", "Period of the trend SMA", "Filters")
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "Period of RSI", "Filters")
self._use_long_signals = self.Param("UseLongSignals", True).SetDisplay("Use Long Signals", "Allow long trades", "General")
self._use_short_signals = self.Param("UseShortSignals", True).SetDisplay("Use Short Signals", "Allow short trades", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._volume_sma = None
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_close = None
self._prev_upper = None
self._prev_lower = None
def OnReseted(self):
super(bollinger_breakout2_strategy, self).OnReseted()
self._volume_sma = None
self._reset_state()
def OnStarted2(self, time):
super(bollinger_breakout2_strategy, self).OnStarted2(time)
self._reset_state()
bollinger = BollingerBands()
bollinger.Length = self._bollinger_length.Value
bollinger.Width = Decimal(self._bollinger_multiplier.Value)
trend_sma = SimpleMovingAverage()
trend_sma.Length = self._trend_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
self._volume_sma = SimpleMovingAverage()
self._volume_sma.Length = self._volume_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, trend_sma, rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawIndicator(area, trend_sma)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, bollinger_value, trend_value, rsi_value):
if candle.State != CandleStates.Finished:
return
volume_average = process_float(self._volume_sma, candle.TotalVolume, candle.ServerTime, True).GetValue[Decimal](None)
if not bollinger_value.IsFormed or bollinger_value.UpBand is None or bollinger_value.LowBand is None:
return
upper = bollinger_value.UpBand
lower = bollinger_value.LowBand
close = candle.ClosePrice
prev_close = self._prev_close
prev_upper = self._prev_upper
prev_lower = self._prev_lower
self._prev_close = close
self._prev_upper = upper
self._prev_lower = lower
if not self._volume_sma.IsFormed or not trend_value.IsFormed or not rsi_value.IsFormed:
return
if prev_close is None or prev_upper is None or prev_lower is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
trend = trend_value.GetValue[Decimal](None)
rsi = rsi_value.GetValue[Decimal](None)
volume_high = candle.TotalVolume > volume_average
cross_above_lower = prev_close <= prev_lower and close > lower
cross_below_upper = prev_close >= prev_upper and close < upper
cross_above_upper = prev_close <= prev_upper and close > upper
cross_below_lower = prev_close >= prev_lower and close < lower
long_signal = self._use_long_signals.Value and cross_above_lower and volume_high and close > trend
short_signal = self._use_short_signals.Value and cross_below_upper and volume_high and close < trend and rsi < Decimal(RSI_SHORT_LIMIT)
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and cross_above_upper:
self.SellMarket(self.Position)
elif self.Position < 0 and cross_below_lower:
self.BuyMarket(-self.Position)
def CreateClone(self):
return bollinger_breakout2_strategy()