Estratégia Bollinger Cci
Implementação da estratégia - Bollinger Bands + CCI. Compra quando o preço está abaixo da banda inferior de Bollinger e o CCI está abaixo de -100 (sobrevendido). Vende quando o preço está acima da banda superior de Bollinger e o CCI está acima de 100 (sobrecomprado).
Os testes indicam um retorno anual médio de aproximadamente 73%. Funciona melhor no mercado de criptomoedas.
As bandas de Bollinger mapeiam os limites de volatilidade, e o CCI mede a distância da média. Rompimentos além de uma banda com confirmação do CCI acionam operações.
Adequado para mercados voláteis onde as tendências se expandem rapidamente. Stops baseados em ATR são aplicados para segurança.
Detalhes
- Critérios de entrada:
- Comprado:
Close < LowerBand && CCI < CciOversold - Vendido:
Close > UpperBand && CCI > CciOverbought
- Comprado:
- Comprado/Vendido: Ambos
- Critérios de saída: O preço retorna à banda do meio
- Stops: Baseados em ATR usando
StopLoss - Valores padrão:
BollingerPeriod= 20BollingerDeviation= 2.0mCciPeriod= 20CciOversold= -100mCciOverbought= 100mStopLoss= new Unit(2, UnitTypes.Absolute)CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoria: Reversão à média
- Direção: Ambos
- Indicadores: Bollinger Bands, CCI
- Stops: Sim
- Complexidade: Intermediário
- Período: Médio prazo
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Implementation of strategy - Bollinger Bands + CCI.
/// Buy when price is below lower Bollinger Band and CCI is below -100 (oversold).
/// Sell when price is above upper Bollinger Band and CCI is above 100 (overbought).
/// </summary>
public class BollingerCciStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _cciOversold;
private readonly StrategyParam<decimal> _cciOverbought;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<Unit> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private int _cooldown;
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// CCI period.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// CCI oversold level.
/// </summary>
public decimal CciOversold
{
get => _cciOversold.Value;
set => _cciOversold.Value = value;
}
/// <summary>
/// CCI overbought level.
/// </summary>
public decimal CciOverbought
{
get => _cciOverbought.Value;
set => _cciOverbought.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Stop-loss value.
/// </summary>
public Unit StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Candle type used for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="BollingerCciStrategy"/>.
/// </summary>
public BollingerCciStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Bollinger Parameters");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Deviation", "Deviation multiplier for Bollinger Bands", "Bollinger Parameters");
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Period for Commodity Channel Index", "CCI Parameters");
_cciOversold = Param(nameof(CciOversold), -100m)
.SetDisplay("CCI Oversold", "CCI level to consider market oversold", "CCI Parameters");
_cciOverbought = Param(nameof(CciOverbought), 100m)
.SetDisplay("CCI Overbought", "CCI level to consider market overbought", "CCI Parameters");
_cooldownBars = Param(nameof(CooldownBars), 80)
.SetRange(5, 500)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_stopLoss = Param(nameof(StopLoss), new Unit(2, UnitTypes.Absolute))
.SetDisplay("Stop Loss", "Stop loss in ATR or value", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "General");
}
/// <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);
// Create indicators
var bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var cci = new CommodityChannelIndex { Length = CciPeriod };
// Setup candle subscription
var subscription = SubscribeCandles(CandleType);
// Bind indicators to candles
subscription
.BindEx(bollinger, cci, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
// Create separate area for CCI
var cciArea = CreateChartArea();
if (cciArea != null)
{
DrawIndicator(cciArea, cci);
}
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue cciValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!bollingerValue.IsFormed || !cciValue.IsFormed)
return;
// In this function we receive only the middle band value from the Bollinger Bands indicator
// We need to calculate the upper and lower bands ourselves or get them directly from the indicator
// Get Bollinger Bands values from the indicator
var bb = (BollingerBandsValue)bollingerValue;
var middleBand = bb.MovingAverage;
var upperBand = bb.UpBand;
var lowerBand = bb.LowBand;
var cciTyped = cciValue.ToDecimal();
// Current price
var price = candle.ClosePrice;
LogInfo($"Candle: {candle.OpenTime}, Close: {price}, " +
$"Upper Band: {upperBand}, Middle Band: {middleBand}, Lower Band: {lowerBand}, " +
$"CCI: {cciTyped}");
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Trading rules
var lowerTouch = price <= lowerBand * 1.002m;
var upperTouch = price >= upperBand * 0.998m;
if (lowerTouch && cciTyped < CciOversold && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
LogInfo($"Buy signal: Price below lower Bollinger Band and CCI oversold ({cciTyped} < {CciOversold}).");
}
else if (upperTouch && cciTyped > CciOverbought && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
LogInfo($"Sell signal: Price above upper Bollinger Band and CCI overbought ({cciTyped} > {CciOverbought}).");
}
// Exit conditions
else if (price > middleBand && Position > 0)
{
// Exit long position when price returns to the middle band
SellMarket();
_cooldown = CooldownBars;
LogInfo($"Exit long: Price returned to middle band. Position: {Position}");
}
else if (price < middleBand && Position < 0)
{
// Exit short position when price returns to the middle band
BuyMarket();
_cooldown = CooldownBars;
LogInfo($"Exit short: Price returned to middle band. Position: {Position}");
}
}
}
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, CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class bollinger_cci_strategy(Strategy):
"""
Bollinger Bands + CCI strategy.
Buy when price is below lower BB and CCI is oversold.
Sell when price is above upper BB and CCI is overbought.
"""
def __init__(self):
super(bollinger_cci_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Bollinger Parameters")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("Bollinger Deviation", "Deviation multiplier for Bollinger Bands", "Bollinger Parameters")
self._cci_period = self.Param("CciPeriod", 20) \
.SetDisplay("CCI Period", "Period for Commodity Channel Index", "CCI Parameters")
self._cci_oversold = self.Param("CciOversold", -100.0) \
.SetDisplay("CCI Oversold", "CCI level to consider market oversold", "CCI Parameters")
self._cci_overbought = self.Param("CciOverbought", 100.0) \
.SetDisplay("CCI Overbought", "CCI level to consider market overbought", "CCI Parameters")
self._cooldown_bars = self.Param("CooldownBars", 80) \
.SetRange(5, 500) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle type for strategy", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(bollinger_cci_strategy, self).OnStarted2(time)
self._cooldown = 0
bollinger = BollingerBands()
bollinger.Length = self._bollinger_period.Value
bollinger.Width = self._bollinger_deviation.Value
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, cci, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
cci_area = self.CreateChartArea()
if cci_area is not None:
self.DrawIndicator(cci_area, cci)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, bb_value, cci_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFormed or not cci_value.IsFormed:
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)
cci_dec = float(cci_value)
price = float(candle.ClosePrice)
if self._cooldown > 0:
self._cooldown -= 1
return
cd = self._cooldown_bars.Value
os_level = self._cci_oversold.Value
ob_level = self._cci_overbought.Value
lower_touch = price <= lower_band * 1.002
upper_touch = price >= upper_band * 0.998
if lower_touch and cci_dec < os_level and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
elif upper_touch and cci_dec > ob_level and self.Position == 0:
self.SellMarket()
self._cooldown = cd
elif price > middle_band and self.Position > 0:
self.SellMarket()
self._cooldown = cd
elif price < middle_band and self.Position < 0:
self.BuyMarket()
self._cooldown = cd
def OnReseted(self):
super(bollinger_cci_strategy, self).OnReseted()
self._cooldown = 0
def CreateClone(self):
return bollinger_cci_strategy()