ADX Slope Estratégia de Reversão à Média
A estratégia ADX Slope de Reversão à Média concentra-se em leituras extremas do ADX para explorar a reversão. Desvios amplos do nível médio raramente persistem.
As operações são acionadas quando o indicador se afasta muito de sua média e então começa a reverter. Tanto as configurações compradas quanto as vendidas incluem um stop de proteção.
Adequada para traders de swing que esperam oscilações, a estratégia encerra a posição assim que o ADX retorna ao equilíbrio. Parâmetro inicial AdxPeriod = 14.
Detalhes
- Critérios de entrada: O indicador cruza de volta em direção à média.
- Comprado/Vendido: Ambas as direções.
- Critérios de saída: O indicador reverte para a média.
- Stops: Sim.
- Valores padrão:
AdxPeriod= 14LookbackPeriod= 20DeviationMultiplier= 1.0mStopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoria: Reversão à média
- Direção: Ambos
- Indicadores: ADX
- Stops: Sim
- Complexidade: Intermediário
- Período: Curto prazo
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- 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>
/// ADX slope mean reversion.
/// Buys when the ADX slope is far below its average and starts turning up, sells when it is far above
/// and starts turning down. Exits when the slope returns to its average.
/// </summary>
public class AdxSlopeMeanReversionStrategy : Strategy
{
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<decimal> _deviationMultiplier;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _slopeAverage;
private StandardDeviation _slopeStdDev;
private decimal? _prevAdx;
private decimal? _prevSlope;
/// <summary>
/// ADX period.
/// </summary>
public int AdxPeriod
{
get => _adxPeriod.Value;
set => _adxPeriod.Value = value;
}
/// <summary>
/// Lookback period for slope statistics.
/// </summary>
public int LookbackPeriod
{
get => _lookbackPeriod.Value;
set => _lookbackPeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier for extreme slope.
/// </summary>
public decimal DeviationMultiplier
{
get => _deviationMultiplier.Value;
set => _deviationMultiplier.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="AdxSlopeMeanReversionStrategy"/>.
/// </summary>
public AdxSlopeMeanReversionStrategy()
{
_adxPeriod = Param(nameof(AdxPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Period of ADX", "Indicators");
_lookbackPeriod = Param(nameof(LookbackPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Lookback Period", "Period for slope statistics", "Strategy");
_deviationMultiplier = Param(nameof(DeviationMultiplier), 1.0m)
.SetGreaterThanZero()
.SetDisplay("Deviation Multiplier", "Standard deviation multiplier for extreme slope", "Strategy");
_stopLossPercent = Param(nameof(StopLossPercent), 2.0m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop-loss percentage", "Risk Management");
_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();
_slopeAverage = null;
_slopeStdDev = null;
_prevAdx = null;
_prevSlope = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var adx = new AverageDirectionalIndex { Length = AdxPeriod };
_slopeAverage = new SimpleMovingAverage { Length = LookbackPeriod };
_slopeStdDev = new StandardDeviation { Length = LookbackPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(adx, ProcessCandle)
.Start();
StartProtection(
takeProfit: null,
stopLoss: StopLossPercent > 0 ? new Unit(StopLossPercent, UnitTypes.Percent) : null
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var adxArea = CreateChartArea();
if (adxArea != null)
DrawIndicator(adxArea, adx);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!adxValue.IsFormed)
return;
if (((AverageDirectionalIndexValue)adxValue).MovingAverage is not decimal adx)
return;
if (_prevAdx is not decimal prevAdx)
{
_prevAdx = adx;
return;
}
_prevAdx = adx;
var slope = adx - prevAdx;
var avgSlope = _slopeAverage.Process(slope, candle.ServerTime, true).ToDecimal();
var stdSlope = _slopeStdDev.Process(slope, candle.ServerTime, true).ToDecimal();
var prevSlope = _prevSlope;
_prevSlope = slope;
if (!_slopeAverage.IsFormed || !_slopeStdDev.IsFormed || prevSlope is not decimal prev)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Extreme reading that has started to turn back toward the average.
if (slope < avgSlope - DeviationMultiplier * stdSlope && slope > prev && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (slope > avgSlope + DeviationMultiplier * stdSlope && slope < prev && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
else if (Position > 0 && slope >= avgSlope)
{
SellMarket(Position);
}
else if (Position < 0 && slope <= avgSlope)
{
BuyMarket(-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, Unit, UnitTypes
from StockSharp.Algo.Indicators import AverageDirectionalIndex, SimpleMovingAverage, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class adx_slope_mean_reversion_strategy(Strategy):
"""
ADX slope mean reversion.
Buys when the ADX slope is far below its average and starts turning up, sells when it is far above
and starts turning down. Exits when the slope returns to its average.
"""
def __init__(self):
super(adx_slope_mean_reversion_strategy, self).__init__()
self._adx_period = self.Param("AdxPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("ADX Period", "Period of ADX", "Indicators")
self._lookback_period = self.Param("LookbackPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Lookback Period", "Period for slope statistics", "Strategy")
self._deviation_multiplier = self.Param("DeviationMultiplier", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Deviation Multiplier", "Standard deviation multiplier for extreme slope", "Strategy")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetNotNegative() \
.SetDisplay("Stop Loss %", "Stop-loss percentage", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._slope_average = None
self._slope_std_dev = None
self._prev_adx = None
self._prev_slope = None
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(adx_slope_mean_reversion_strategy, self).OnReseted()
self._slope_average = None
self._slope_std_dev = None
self._prev_adx = None
self._prev_slope = None
def OnStarted2(self, time):
super(adx_slope_mean_reversion_strategy, self).OnStarted2(time)
adx = AverageDirectionalIndex()
adx.Length = self._adx_period.Value
self._slope_average = SimpleMovingAverage()
self._slope_average.Length = self._lookback_period.Value
self._slope_std_dev = StandardDeviation()
self._slope_std_dev.Length = self._lookback_period.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(adx, self._process_candle).Start()
stop = float(self._stop_loss_percent.Value)
self.StartProtection(None, Unit(stop, UnitTypes.Percent) if stop > 0 else None)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
adx_area = self.CreateChartArea()
if adx_area is not None:
self.DrawIndicator(adx_area, adx)
def _process_candle(self, candle, adx_value):
if candle.State != CandleStates.Finished:
return
if not adx_value.IsFormed:
return
adx_ma = adx_value.MovingAverage
if adx_ma is None:
return
adx = float(adx_ma)
if self._prev_adx is None:
self._prev_adx = adx
return
slope = adx - self._prev_adx
self._prev_adx = adx
avg_slope = float(process_float(self._slope_average, slope, candle.ServerTime, True))
std_slope = float(process_float(self._slope_std_dev, slope, candle.ServerTime, True))
prev = self._prev_slope
self._prev_slope = slope
if not self._slope_average.IsFormed or not self._slope_std_dev.IsFormed or prev is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
k = float(self._deviation_multiplier.Value)
# Extreme reading that has started to turn back toward the average.
if slope < avg_slope - k * std_slope and slope > prev and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif slope > avg_slope + k * std_slope and slope < prev and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and slope >= avg_slope:
self.SellMarket(self.Position)
elif self.Position < 0 and slope <= avg_slope:
self.BuyMarket(-self.Position)
def CreateClone(self):
return adx_slope_mean_reversion_strategy()