Die Bollinger Aroon-Strategie sucht nach Rücksetzern innerhalb eines starken Aufwärtstrends.
Wenn der Preis unter das untere Bollinger Band fällt, der Aroon Up-Wert jedoch
erhöht bleibt, geht das System davon aus, dass der Trend intakt ist, und sucht
nach einer Rückkehr zum Mittelwert. Es handelt nur Long und versucht, den
Rückprall nach einem temporären Rücksetzer zu nutzen.
Das Setup wird ausgelöst, nachdem eine abgeschlossene Kerze unterhalb des unteren
Bandes schließt, während Aroon Up den Bestätigungslevel überschreitet. Die Position
bleibt offen, bis der Aroon-Wert unter einen Stop-Schwellenwert fällt oder der Preis
bis zum oberen Band steigt. Die Bandbreite passt sich der Volatilität an, wodurch
die Strategie sowohl in ruhigen als auch in aktiven Märkten handeln kann.
Backtests an wichtigen Krypto-Paaren zeigen, dass der Ansatz während starker Trends
mit gelegentlichen Ausschüttelern hervorragend abschneidet. Da Einstiege sowohl
eine Volatilitätserweiterung als auch einen anhaltenden Aroon Up-Wert erfordern,
werden Fehlsignale im Vergleich zu einer einfachen Bollinger-Umkehr reduziert.
Details
Daten: Kurskerzen.
Einstiegskriterien:
Long: Schlusskurs unter unterem Band UND Aroon Up > Bestätigungslevel.
Short: nicht verwendet.
Ausstiegskriterien:
Schlusskurs berührt oberes Band ODER Aroon Up < Stop-Level.
Stops: Indikatorbasiert; kein fester Stop standardmäßig.
Standardwerte:
BBLength = 20
BBMultiplier = 2.0
AroonLength = 288
AroonConfirmation = 90
AroonStop = 70
Filter:
Kategorie: Mean Reversion innerhalb des Trends
Richtung: Nur Long
Indikatoren: Bollinger Bands, Aroon
Komplexität: Moderat
Risikolevel: Mittel
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()