Estrategia Adx Bollinger
Estrategia basada en los indicadores ADX y Bandas de Bollinger. Entra largo cuando ADX > 25 y el precio rompe por encima de la banda superior de Bollinger. Entra corto cuando ADX > 25 y el precio rompe por debajo de la banda inferior de Bollinger.
Las pruebas indican un retorno anual promedio de aproximadamente 115%. Funciona mejor en el mercado de acciones.
Las rupturas de las bandas de Bollinger filtradas con ADX garantizan que el precio esté rompiendo con fuerza. El sistema opera en la dirección de la ruptura.
Adecuado para entornos de alta volatilidad. Un stop basado en ATR reduce el riesgo a la baja.
Detalles
- Criterios de entrada:
- Largo:
Close < LowerBand && ADX > 25 - Corto:
Close > UpperBand && ADX > 25
- Largo:
- Largo/Corto: Ambos
- Criterios de salida: El precio regresa a la banda media
- Stops: Basado en ATR usando
AtrMultiplier - Valores predeterminados:
AdxPeriod= 14BollingerPeriod= 20BollingerDeviation= 2.0mAtrPeriod= 14AtrMultiplier= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Reversión a la media
- Dirección: Ambos
- Indicadores: ADX, Bollinger Bands
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Medio plazo
- 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 ADX and Bollinger Bands indicators.
/// Enters long when ADX > 25 and price breaks above upper Bollinger band
/// Enters short when ADX > 25 and price breaks below lower Bollinger band
/// </summary>
public class AdxBollingerStrategy : Strategy
{
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// ADX period
/// </summary>
public int AdxPeriod
{
get => _adxPeriod.Value;
set => _adxPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands period
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands deviation
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// ATR period for stop-loss calculation
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// ATR multiplier for stop-loss
/// </summary>
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
/// <summary>
/// Candle type for strategy calculation
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor
/// </summary>
public AdxBollingerStrategy()
{
_adxPeriod = Param(nameof(AdxPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Period for ADX indicator", "Indicators")
.SetOptimize(10, 20, 2);
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Indicators")
.SetOptimize(15, 30, 5);
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Deviation", "Deviation multiplier for Bollinger Bands", "Indicators")
.SetOptimize(1.5m, 2.5m, 0.5m);
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Period for ATR indicator for stop-loss", "Risk Management")
.SetOptimize(10, 20, 2);
_atrMultiplier = Param(nameof(AtrMultiplier), 2.0m)
.SetGreaterThanZero()
.SetDisplay("ATR Multiplier", "Multiplier for ATR-based stop-loss", "Risk Management")
.SetOptimize(1.5m, 3.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var adx = new AverageDirectionalIndex { Length = AdxPeriod };
var bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var atr = new AverageTrueRange { Length = AtrPeriod };
// Subscribe to candles and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(adx, bollinger, atr, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
// Create a separate area for ADX
var adxArea = CreateChartArea();
if (adxArea != null)
{
DrawIndicator(adxArea, adx);
}
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue adxValue, IIndicatorValue bollingerValue, IIndicatorValue atrValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Get additional values from Bollinger Bands
var bollingerValueTyped = (BollingerBandsValue)bollingerValue;
var upperBand = bollingerValueTyped.UpBand;
var lowerBand = bollingerValueTyped.LowBand;
var middleBand = (upperBand - lowerBand) / 2 + lowerBand;
// Current price (close of the candle)
var price = candle.ClosePrice;
// Stop-loss size based on ATR
var stopSize = atrValue.ToDecimal() * AtrMultiplier;
var adxValueTyped = (AverageDirectionalIndexValue)adxValue;
// Trading logic
if (adxValueTyped.MovingAverage > 25) // Strong trend
{
if (price > upperBand && Position <= 0)
{
// Buy signal: price above upper Bollinger band with strong trend
BuyMarket(Volume + Math.Abs(Position));
// Set stop-loss
var stopPrice = price - stopSize;
RegisterOrder(CreateOrder(Sides.Sell, stopPrice, Math.Abs(Position + Volume).Max(Volume)));
}
else if (price < lowerBand && Position >= 0)
{
// Sell signal: price below lower Bollinger band with strong trend
SellMarket(Volume + Math.Abs(Position));
// Set stop-loss
var stopPrice = price + stopSize;
RegisterOrder(CreateOrder(Sides.Buy, stopPrice, Math.Abs(Position + Volume).Max(Volume)));
}
}
// Exit conditions
else if (adxValueTyped.MovingAverage < 20)
{
// Trend is weakening - close any position
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
BuyMarket(Math.Abs(Position));
}
// Also exit when price returns to middle band
else if (price < middleBand && Position > 0)
{
// Exit long position when price returns to middle band
SellMarket(Position);
}
else if (price > middleBand && Position < 0)
{
// Exit short position when price returns to middle band
BuyMarket(Math.Abs(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, Math
from StockSharp.Messages import DataType, CandleStates, Sides
from StockSharp.Algo.Indicators import AverageDirectionalIndex, BollingerBands, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class adx_bollinger_strategy(Strategy):
"""
Strategy based on ADX and Bollinger Bands indicators.
Enters long when ADX > 25 and price breaks above upper Bollinger band
Enters short when ADX > 25 and price breaks below lower Bollinger band
"""
def __init__(self):
super(adx_bollinger_strategy, self).__init__()
self._adx_period = self.Param("AdxPeriod", 14) \
.SetDisplay("ADX Period", "Period for ADX indicator", "Indicators")
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("Bollinger Deviation", "Deviation multiplier for Bollinger Bands", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "Period for ATR indicator for stop-loss", "Risk Management")
self._atr_multiplier = self.Param("AtrMultiplier", 2.0) \
.SetDisplay("ATR Multiplier", "Multiplier for ATR-based stop-loss", "Risk Management")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Timeframe for strategy", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(adx_bollinger_strategy, self).OnReseted()
def OnStarted2(self, time):
super(adx_bollinger_strategy, self).OnStarted2(time)
adx = AverageDirectionalIndex()
adx.Length = self._adx_period.Value
bollinger = BollingerBands()
bollinger.Length = self._bollinger_period.Value
bollinger.Width = self._bollinger_deviation.Value
atr = AverageTrueRange()
atr.Length = self._atr_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(adx, bollinger, atr, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
adx_area = self.CreateChartArea()
if adx_area is not None:
self.DrawIndicator(adx_area, adx)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, adx_value, bollinger_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if bollinger_value.UpBand is None or bollinger_value.LowBand is None:
return
adx_ma = adx_value.MovingAverage
if adx_ma is None:
return
adx_ma_f = float(adx_ma)
upper_band = float(bollinger_value.UpBand)
lower_band = float(bollinger_value.LowBand)
middle_band = (upper_band - lower_band) / 2.0 + lower_band
price = float(candle.ClosePrice)
stop_size = float(atr_value) * float(self._atr_multiplier.Value)
# Trading logic
if adx_ma_f > 25: # Strong trend
if price > upper_band and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
stop_price = price - stop_size
stop_vol = max(abs(self.Position + self.Volume), self.Volume)
self.RegisterOrder(self.CreateOrder(Sides.Sell, stop_price, stop_vol))
elif price < lower_band and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
stop_price = price + stop_size
stop_vol = max(abs(self.Position + self.Volume), self.Volume)
self.RegisterOrder(self.CreateOrder(Sides.Buy, stop_price, stop_vol))
elif adx_ma_f < 20:
if self.Position > 0:
self.SellMarket(self.Position)
elif self.Position < 0:
self.BuyMarket(abs(self.Position))
elif price < middle_band and self.Position > 0:
self.SellMarket(self.Position)
elif price > middle_band and self.Position < 0:
self.BuyMarket(abs(self.Position))
def CreateClone(self):
return adx_bollinger_strategy()