Estrategia Bollinger Supertrend
Esta estrategia combina las Bandas de Bollinger con el indicador Supertrend para identificar entradas durante movimientos direccionales fuertes. Las Bandas de Bollinger miden la expansión de volatilidad mientras que la línea Supertrend sigue la tendencia general y actúa como stop dinámico.
Las pruebas indican un rendimiento anual promedio de aproximadamente 79%. Funciona mejor en el mercado de acciones.
Una operación larga se activa cuando el precio cierra por encima de la Banda de Bollinger superior y permanece por encima de la línea Supertrend, confirmando el alineamiento del momentum y la tendencia. Una operación corta ocurre cuando el precio cierra por debajo de la banda inferior mientras se mantiene bajo el nivel Supertrend. Las operaciones se cierran una vez que el precio cruza de vuelta a través del Supertrend, indicando que el momentum ha desaparecido.
Debido a que el sistema espera rupturas más allá de la volatilidad normal, es adecuado para traders que buscan capturar movimientos sostenidos en lugar de reversiones rápidas. El stop Supertrend se ajusta dinámicamente a los movimientos del mercado, ayudando a gestionar el riesgo sin intervención manual.
Detalles
- Criterios de entrada:
- Largo: Close > upper Bollinger Band && Close > Supertrend
- Corto: Close < lower Bollinger Band && Close < Supertrend
- Largo/Corto: Ambos lados.
- Criterios de salida:
- Largo: Salir cuando el precio cruza por debajo del Supertrend
- Corto: Salir cuando el precio cruza por encima del Supertrend
- Stops: Sí, vía stop dinámico Supertrend.
- Valores predeterminados:
BollingerPeriod= 20BollingerDeviation= 2.0mSupertrendPeriod= 10SupertrendMultiplier= 3.0mCandleType= TimeSpan.FromMinutes(15)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: Bollinger Bands, Supertrend
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Bollinger Bands and Supertrend indicators.
/// Enters long when price breaks above upper Bollinger Band and is above Supertrend.
/// Enters short when price breaks below lower Bollinger Band and is below Supertrend.
/// Uses Supertrend for dynamic exit.
/// </summary>
public class BollingerSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private BollingerBands _bollinger;
private AverageTrueRange _atr;
private bool _isLongTrend;
private decimal _supertrendValue;
private decimal _lastClose;
private int _cooldown;
/// <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>
/// Supertrend ATR period.
/// </summary>
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
/// <summary>
/// Supertrend ATR multiplier.
/// </summary>
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type parameter.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BollingerSupertrendStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Period for Bollinger Bands calculation", "Indicators")
.SetOptimize(10, 30, 5);
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier for Bollinger Bands", "Indicators")
.SetOptimize(1.5m, 3.0m, 0.5m);
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Supertrend Period", "ATR period for Supertrend calculation", "Indicators")
.SetOptimize(7, 14, 1);
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Supertrend Multiplier", "ATR multiplier for Supertrend calculation", "Indicators")
.SetOptimize(2.0m, 4.0m, 0.5m);
_cooldownBars = Param(nameof(CooldownBars), 60)
.SetRange(1, 200)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
_bollinger = null;
_atr = null;
_isLongTrend = default;
_supertrendValue = default;
_lastClose = default;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Initialize indicators
_bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
_atr = new AverageTrueRange
{
Length = SupertrendPeriod
};
// Create candles subscription
var subscription = SubscribeCandles(CandleType);
// Bind Bollinger indicator to candle subscription
subscription
.BindEx(_bollinger, _atr, ProcessCandle)
.Start();
// Setup chart if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bollinger);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue atrValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Extract Bollinger Band values
var bb = (BollingerBandsValue)bollingerValue;
if (bb.MovingAverage is not decimal middleBand)
return;
if (bb.UpBand is not decimal upperBand)
return;
if (bb.LowBand is not decimal lowerBand)
return;
// Calculate Supertrend
// Note: This is a simplified Supertrend implementation
decimal atrValue2 = atrValue.ToDecimal() * SupertrendMultiplier;
decimal upperBand2 = (candle.HighPrice + candle.LowPrice) / 2 + atrValue2;
decimal lowerBand2 = (candle.HighPrice + candle.LowPrice) / 2 - atrValue2;
// Determine Supertrend value and direction
if (_lastClose == 0)
{
// First candle initialization
_supertrendValue = candle.ClosePrice > (candle.HighPrice + candle.LowPrice) / 2 ?
lowerBand2 : upperBand2;
_isLongTrend = candle.ClosePrice > _supertrendValue;
}
else
{
// Calculate Supertrend
if (_isLongTrend)
{
// Previous trend was up
if (candle.ClosePrice < _supertrendValue)
{
// Trend changes to down
_isLongTrend = false;
_supertrendValue = upperBand2;
}
else
{
// Trend remains up, adjust supertrend value
_supertrendValue = Math.Max(lowerBand2, _supertrendValue);
}
}
else
{
// Previous trend was down
if (candle.ClosePrice > _supertrendValue)
{
// Trend changes to up
_isLongTrend = true;
_supertrendValue = lowerBand2;
}
else
{
// Trend remains down, adjust supertrend value
_supertrendValue = Math.Min(upperBand2, _supertrendValue);
}
}
}
_lastClose = candle.ClosePrice;
// Trading logic
bool isPriceAboveSupertrend = candle.ClosePrice > _supertrendValue;
bool isPriceAboveUpperBand = candle.ClosePrice > upperBand;
bool isPriceBelowLowerBand = candle.ClosePrice < lowerBand;
if (_cooldown > 0)
_cooldown--;
// Long signal: Price breaks above upper Bollinger Band and is above Supertrend
if (_cooldown == 0 && isPriceAboveUpperBand && isPriceAboveSupertrend)
{
if (Position <= 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
// Short signal: Price breaks below lower Bollinger Band and is below Supertrend
else if (_cooldown == 0 && isPriceBelowLowerBand && !isPriceAboveSupertrend)
{
if (Position >= 0)
{
SellMarket();
_cooldown = CooldownBars;
}
}
// Exit signals based on Supertrend
else if ((Position > 0 && !isPriceAboveSupertrend) ||
(Position < 0 && isPriceAboveSupertrend))
{
if (Position > 0)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0)
{
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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class bollinger_supertrend_strategy(Strategy):
def __init__(self):
super(bollinger_supertrend_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Period for Bollinger Bands calculation", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier for Bollinger Bands", "Indicators")
self._supertrend_period = self.Param("SupertrendPeriod", 10) \
.SetDisplay("Supertrend Period", "ATR period for Supertrend calculation", "Indicators")
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 3.0) \
.SetDisplay("Supertrend Multiplier", "ATR multiplier for Supertrend calculation", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 60) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._is_long_trend = False
self._supertrend_value = 0.0
self._last_close = 0.0
self._cooldown = 0
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def supertrend_period(self):
return self._supertrend_period.Value
@property
def supertrend_multiplier(self):
return self._supertrend_multiplier.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_supertrend_strategy, self).OnReseted()
self._is_long_trend = False
self._supertrend_value = 0.0
self._last_close = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(bollinger_supertrend_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self.bollinger_period
bollinger.Width = self.bollinger_deviation
atr = AverageTrueRange()
atr.Length = self.supertrend_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
def OnProcess(self, candle, bollinger_value, atr_value):
if candle.State != CandleStates.Finished:
return
bb = bollinger_value
if bb.MovingAverage is None or bb.UpBand is None or bb.LowBand is None:
return
middle_band = float(bb.MovingAverage)
upper_band = float(bb.UpBand)
lower_band = float(bb.LowBand)
atr_val = float(atr_value) * float(self.supertrend_multiplier)
hl2 = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
upper_band2 = hl2 + atr_val
lower_band2 = hl2 - atr_val
if self._last_close == 0:
self._supertrend_value = lower_band2 if float(candle.ClosePrice) > hl2 else upper_band2
self._is_long_trend = float(candle.ClosePrice) > self._supertrend_value
else:
if self._is_long_trend:
if float(candle.ClosePrice) < self._supertrend_value:
self._is_long_trend = False
self._supertrend_value = upper_band2
else:
self._supertrend_value = max(lower_band2, self._supertrend_value)
else:
if float(candle.ClosePrice) > self._supertrend_value:
self._is_long_trend = True
self._supertrend_value = lower_band2
else:
self._supertrend_value = min(upper_band2, self._supertrend_value)
self._last_close = float(candle.ClosePrice)
is_above_supertrend = float(candle.ClosePrice) > self._supertrend_value
is_above_upper = float(candle.ClosePrice) > upper_band
is_below_lower = float(candle.ClosePrice) < lower_band
if self._cooldown > 0:
self._cooldown -= 1
if self._cooldown == 0 and is_above_upper and is_above_supertrend:
if self.Position <= 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
elif self._cooldown == 0 and is_below_lower and not is_above_supertrend:
if self.Position >= 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
elif (self.Position > 0 and not is_above_supertrend) or (self.Position < 0 and is_above_supertrend):
if self.Position > 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
elif self.Position < 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
def CreateClone(self):
return bollinger_supertrend_strategy()