Estrategia que utiliza rupturas de las Bandas de Bollinger con confirmación de volumen.
Entra en posiciones cuando el precio rompe por encima/debajo de las Bandas de Bollinger con mayor volumen.
Las pruebas indican un retorno anual promedio de aproximadamente 178%. Funciona mejor en el mercado de acciones.
Las bandas de Bollinger muestran la expansión de la volatilidad y el volumen confirma la ruptura. Las posiciones se toman cuando el precio cierra fuera de una banda con fuerte actividad.
Adecuado para operadores de rupturas que esperan continuación. Un stop basado en ATR mantiene las pérdidas manejables.
Detalles
Criterios de entrada:
Largo: Close > UpperBand && Volume > AvgVolume * VolumeMultiplier
Corto: Close < LowerBand && Volume > AvgVolume * VolumeMultiplier
Largo/Corto: Ambos
Criterios de salida:
El precio regresa a la banda media
Stops: Basado en ATR usando StopLossAtr
Valores predeterminados:
BollingerPeriod = 20
BollingerDeviation = 2.0m
VolumePeriod = 20
VolumeMultiplier = 1.5m
StopLossAtr = 2.0m
AtrPeriod = 14
CandleType = TimeSpan.FromMinutes(5).TimeFrame()
Filtros:
Categoría: Reversión a la media
Dirección: Ambos
Indicadores: Bollinger Bands, Volume
Stops: Sí
Complejidad: Intermedio
Marco temporal: Medio plazo
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>
/// Strategy that uses Bollinger Bands for mean reversion.
/// Enters when price touches/breaks bands, exits at middle band.
/// </summary>
public class BollingerVolumeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands standard deviation multiplier.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public BollingerVolumeStrategy()
{
_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("Bollinger Period", "Period of the Bollinger Bands", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 100)
.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();
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bb = (BollingerBandsValue)bollingerValue;
if (bb.UpBand is not decimal upperBand ||
bb.LowBand is not decimal lowerBand ||
bb.MovingAverage is not decimal middleBand)
return;
var close = candle.ClosePrice;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Long: price below lower band (mean reversion buy)
if (close < lowerBand && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Short: price above upper band (mean reversion sell)
else if (close > upperBand && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long: price returns to middle band
if (Position > 0 && close > middleBand)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short: price returns to middle band
else if (Position < 0 && close < middleBand)
{
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
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class bollinger_volume_strategy(Strategy):
"""
Strategy that uses Bollinger Bands for mean reversion.
Enters when price touches/breaks bands, exits at middle band.
"""
def __init__(self):
super(bollinger_volume_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetRange(10, 50) \
.SetDisplay("Bollinger Period", "Period of the Bollinger Bands", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 100) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General") \
.SetRange(5, 500)
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnStarted2(self, time):
super(bollinger_volume_strategy, self).OnStarted2(time)
self._cooldown = 0
bollinger = BollingerBands()
bollinger.Length = self.bollinger_period
bollinger.Width = self.bollinger_deviation
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
def ProcessCandle(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_band = float(bb_value.UpBand)
lower_band = float(bb_value.LowBand)
middle_band = float(bb_value.MovingAverage)
close = float(candle.ClosePrice)
if self._cooldown > 0:
self._cooldown -= 1
return
# Long: price below lower band (mean reversion buy)
if close < lower_band and self.Position == 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
# Short: price above upper band (mean reversion sell)
elif close > upper_band and self.Position == 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
# Exit long: price returns to middle band
if self.Position > 0 and close > middle_band:
self.SellMarket()
self._cooldown = self.cooldown_bars
# Exit short: price returns to middle band
elif self.Position < 0 and close < middle_band:
self.BuyMarket()
self._cooldown = self.cooldown_bars
def OnReseted(self):
super(bollinger_volume_strategy, self).OnReseted()
self._cooldown = 0
def CreateClone(self):
return bollinger_volume_strategy()