A estratégia Bollinger Aroon busca retrocessos dentro de uma forte tendência de alta.
Quando o preço se estende abaixo da banda inferior de Bollinger, mas o valor do
Aroon Up permanece elevado, o sistema assume que a tendência está intacta e busca
uma reversão à média. Opera apenas comprado, buscando capturar o rebote após
uma queda temporária.
A configuração é acionada após uma vela concluída fechar abaixo da banda inferior
enquanto Aroon Up supera o nível de confirmação. A posição permanece aberta até
que a leitura do Aroon caia abaixo de um limite de stop ou o preço suba até a
banda superior. A largura das bandas se adapta à volatilidade, permitindo que a
estratégia opere em mercados calmos e ativos igualmente.
Backtests em grandes pares de cripto mostram que a abordagem se destaca durante
tendências fortes com sacudidas ocasionais. Como as entradas exigem tanto expansão
de volatilidade quanto uma leitura persistente de Aroon Up, os sinais falsos são
reduzidos em comparação com uma reversão simples de Bollinger.
Detalhes
Dados: Velas de preço.
Critérios de entrada:
Comprado: Fechamento abaixo da banda inferior E Aroon Up > nível de confirmação.
Vendido: não utilizado.
Critérios de saída:
Fechamento toca a banda superior OU Aroon Up < nível de stop.
Stops: Baseado em indicador; sem stop fixo por padrão.
Valores padrão:
BBLength = 20
BBMultiplier = 2.0
AroonLength = 288
AroonConfirmation = 90
AroonStop = 70
Filtros:
Categoria: Reversão à média dentro da tendência
Direção: Somente comprado
Indicadores: Bollinger Bands, Aroon
Complexidade: Moderado
Nível de risco: Médio
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>
/// Bollinger Bands + Aroon Strategy.
/// Buys when price touches lower Bollinger Band with Aroon Up confirming uptrend.
/// Exits when price reaches upper Bollinger Band or Aroon signals weakness.
/// </summary>
public class BollingerAroonStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleTypeParam;
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbMultiplier;
private readonly StrategyParam<int> _aroonLength;
private readonly StrategyParam<decimal> _aroonConfirmation;
private readonly StrategyParam<decimal> _aroonStop;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BBLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
/// <summary>
/// Bollinger Bands standard deviation multiplier.
/// </summary>
public decimal BBMultiplier
{
get => _bbMultiplier.Value;
set => _bbMultiplier.Value = value;
}
/// <summary>
/// Aroon indicator period.
/// </summary>
public int AroonLength
{
get => _aroonLength.Value;
set => _aroonLength.Value = value;
}
/// <summary>
/// Aroon confirmation level.
/// </summary>
public decimal AroonConfirmation
{
get => _aroonConfirmation.Value;
set => _aroonConfirmation.Value = value;
}
/// <summary>
/// Aroon stop level.
/// </summary>
public decimal AroonStop
{
get => _aroonStop.Value;
set => _aroonStop.Value = value;
}
private BollingerBands _bollinger;
private Aroon _aroon;
private int _cooldownRemaining;
public BollingerAroonStrategy()
{
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
_bbLength = Param(nameof(BBLength), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Bollinger Bands");
_bbMultiplier = Param(nameof(BBMultiplier), 2.0m)
.SetDisplay("BB StdDev", "Bollinger Bands standard deviation multiplier", "Bollinger Bands");
_aroonLength = Param(nameof(AroonLength), 14)
.SetGreaterThanZero()
.SetDisplay("Aroon Period", "Aroon indicator period", "Aroon");
_aroonConfirmation = Param(nameof(AroonConfirmation), 60m)
.SetDisplay("Aroon Confirmation", "Aroon confirmation level", "Aroon");
_aroonStop = Param(nameof(AroonStop), 40m)
.SetDisplay("Aroon Stop", "Aroon stop level", "Aroon");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bollinger = null;
_aroon = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bollinger = new BollingerBands
{
Length = BBLength,
Width = BBMultiplier
};
_aroon = new Aroon { Length = AroonLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_bollinger, _aroon, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bollinger);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle,
IIndicatorValue bollingerValue, IIndicatorValue aroonValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bollinger.IsFormed || !_aroon.IsFormed)
return;
var bb = (BollingerBandsValue)bollingerValue;
if (bb.LowBand is not decimal lowerBand ||
bb.UpBand is not decimal upperBand ||
bb.MovingAverage is not decimal middleBand)
return;
var aa = (AroonValue)aroonValue;
if (aa.Up is not decimal aroonUp)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var close = candle.ClosePrice;
// Long entry: price at/below lower BB + Aroon Up confirming uptrend
if (close <= lowerBand && aroonUp > AroonConfirmation && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = 12;
}
// Short entry: price at/above upper BB + Aroon Up weak
else if (close >= upperBand && aroonUp < AroonStop && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = 12;
}
// Exit long: price reaches upper band or Aroon signals weakness
else if (Position > 0 && (close >= upperBand || aroonUp < AroonStop))
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = 12;
}
// Exit short: price reaches lower band or Aroon signals strength
else if (Position < 0 && (close <= lowerBand || aroonUp > AroonConfirmation))
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = 12;
}
}
}
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, Aroon
from StockSharp.Algo.Strategies import Strategy
class bollinger_aroon_strategy(Strategy):
"""Bollinger Bands + Aroon Strategy.
Buys when price touches lower BB with Aroon Up confirming uptrend.
Exits when price reaches upper BB or Aroon signals weakness."""
def __init__(self):
super(bollinger_aroon_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General")
self._bb_length = self.Param("BBLength", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Bollinger Bands")
self._bb_multiplier = self.Param("BBMultiplier", 2.0) \
.SetDisplay("BB StdDev", "Bollinger Bands standard deviation multiplier", "Bollinger Bands")
self._aroon_length = self.Param("AroonLength", 14) \
.SetDisplay("Aroon Period", "Aroon indicator period", "Aroon")
self._aroon_confirmation = self.Param("AroonConfirmation", 60.0) \
.SetDisplay("Aroon Confirmation", "Aroon confirmation level", "Aroon")
self._aroon_stop = self.Param("AroonStop", 40.0) \
.SetDisplay("Aroon Stop", "Aroon stop level", "Aroon")
self._bollinger = None
self._aroon = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_aroon_strategy, self).OnReseted()
self._bollinger = None
self._aroon = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(bollinger_aroon_strategy, self).OnStarted2(time)
self._bollinger = BollingerBands()
self._bollinger.Length = int(self._bb_length.Value)
self._bollinger.Width = float(self._bb_multiplier.Value)
self._aroon = Aroon()
self._aroon.Length = int(self._aroon_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._bollinger, self._aroon, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._bollinger)
self.DrawOwnTrades(area)
def _on_process(self, candle, bb_value, aroon_value):
if candle.State != CandleStates.Finished:
return
if not self._bollinger.IsFormed or not self._aroon.IsFormed:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
if aroon_value.Up is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
lower_band = float(bb_value.LowBand)
upper_band = float(bb_value.UpBand)
aroon_up = float(aroon_value.Up)
close = float(candle.ClosePrice)
aroon_confirm = float(self._aroon_confirmation.Value)
aroon_stop = float(self._aroon_stop.Value)
if close <= lower_band and aroon_up > aroon_confirm and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = 12
elif close >= upper_band and aroon_up < aroon_stop and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = 12
elif self.Position > 0 and (close >= upper_band or aroon_up < aroon_stop):
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = 12
elif self.Position < 0 and (close <= lower_band or aroon_up > aroon_confirm):
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = 12
def CreateClone(self):
return bollinger_aroon_strategy()