Estrategia Auto ADX
Descripción general
La Estrategia Auto ADX es un port directo del asesor experto de MetaTrader Auto ADX.mq5 a la API de alto nivel de StockSharp. La estrategia evalúa la fortaleza del Índice Direccional Promedio (ADX) y la relación entre los componentes +DI y -DI para determinar la dirección del trade. Reproduce los controles de riesgo originales, incluyendo stop-loss, take-profit, señales reversibles y trailing stops basados en pips, mientras adopta conceptos de StockSharp como suscripciones de velas y vínculos de indicadores.
Lógica de Trading
- Fuente de Velas – La estrategia se suscribe a un tipo de vela configurable (predeterminado: marco temporal de 1 hora) y procesa solo las velas terminadas para evitar el ruido intrabarra.
- Cálculo ADX – Un único indicador
AverageDirectionalIndex se vincula a través de BindEx, dando acceso al valor ADX suavizado así como a las líneas +DI y -DI.
- Entrada Larga – Activada cuando:
- +DI es mayor que -DI (momentum direccional positivo),
- ADX está por encima del nivel ADX configurable, y
- ADX está subiendo comparado con la vela anterior.
- Entrada Corta – Activada cuando:
- -DI es mayor que +DI (momentum direccional negativo),
- ADX está por debajo del nivel configurado, y
- ADX está bajando versus la vela anterior.
- Modo Inverso – Cuando
ReverseSignals está habilitado (comportamiento predeterminado), las posiciones abiertas se cierran si:
- Una posición larga ve a +DI caer por debajo de -DI o el ADX decrece,
- Una posición corta ve a +DI subir por encima de -DI o el ADX sube.
- Dimensionamiento de Posición – Las órdenes se emiten con el
Volume de la estrategia. El manejo de reversión depende de ClosePosition() para salir de toda la exposición antes de que se considere una nueva señal.
Gestión de Riesgo
- Stop-Loss / Take-Profit – Convertidos de entradas en pips a distancias de precio absolutas usando el
PriceStep del instrumento. El ayudante StartProtection de StockSharp coloca las órdenes protectoras con ejecución de mercado opcional.
- Trailing Stop – La lógica original de trailing basada en pips se replica:
- El trailing se activa solo después de que la ganancia no realizada supera la distancia de trailing.
- El nivel de stop se mueve en pasos de tamaño pip (
TrailingStepPips).
- Una posición larga sale si el precio imprime por debajo del trailing stop; una corta sale cuando el precio sube por encima del trailing stop.
- Conversión de Pip – Para imitar la implementación MQL, el tamaño del pip es igual a
PriceStep, multiplicado por 10 cuando el instrumento usa precios de 3 o 5 decimales. Esto mantiene el comportamiento consistente entre símbolos forex.
Parámetros
| Nombre |
Predeterminado |
Descripción |
StopLossPips |
50 |
Distancia del stop protector en pips. Establecer en cero para deshabilitar el stop-loss. |
TakeProfitPips |
50 |
Distancia del objetivo de ganancia en pips. Establecer en cero para deshabilitar el take-profit. |
TrailingStopPips |
5 |
Tamaño del trailing stop en pips. Establecer en cero para deshabilitar el trailing. |
TrailingStepPips |
5 |
Ganancia incremental mínima (en pips) antes de desplazar el trailing stop. Debe ser positivo cuando el trailing está habilitado. |
AdxPeriod |
14 |
Período de promedio para el indicador ADX. |
AdxLevel |
30 |
Umbral de fortaleza ADX que filtra las entradas. |
ReverseSignals |
true |
Habilita el cierre de posiciones existentes cuando la relación DI o la pendiente ADX cambia. |
CandleType |
1 hora |
Tipo de vela usado para análisis y trading. |
Notas de Implementación
BindEx se usa para acceder al AverageDirectionalIndexValue completo, asegurando que nunca dependemos de la recuperación manual de valores de indicadores.
- La lógica de trailing lleva registro del último nivel de stop y lo mueve solo cuando el precio progresa por al menos
TrailingStepPips a favor de la posición, replicando el comportamiento de paso de trailing MQL.
- Todos los comentarios en línea en el código fuente C# están en inglés para satisfacer las pautas del repositorio.
- La estrategia es autónoma dentro de
API/2908_Auto_ADX/CS/AutoAdxStrategy.cs; no hay contraparte Python según los requisitos.
Consejos de Uso
- Adjuntar la estrategia a un instrumento con metadatos
PriceStep correctos para que la conversión de pips siga siendo precisa.
- Ajustar
AdxLevel para que coincida con el perfil de volatilidad del instrumento negociado — umbrales más altos reducen la frecuencia de señales.
- Cuando el trailing está deshabilitado (
TrailingStopPips = 0), TrailingStepPips se ignora, reproduciendo el comportamiento del asesor experto original.
- Hacer backtesting en múltiples mercados para validar las distancias de protección basadas en pips y confirmar que el filtrado de pendiente ADX coincide con las expectativas.
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>
/// Auto ADX strategy (simplified). Uses RSI for trend strength detection
/// combined with EMA for direction, mimicking ADX directional movement logic.
/// </summary>
public class AutoAdxStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _rsiHigh;
private readonly StrategyParam<decimal> _rsiLow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public decimal RsiHigh
{
get => _rsiHigh.Value;
set => _rsiHigh.Value = value;
}
public decimal RsiLow
{
get => _rsiLow.Value;
set => _rsiLow.Value = value;
}
public AutoAdxStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period for direction", "Indicators");
_rsiHigh = Param(nameof(RsiHigh), 60m)
.SetDisplay("RSI High", "RSI threshold for bullish strength", "Logic");
_rsiLow = Param(nameof(RsiLow), 40m)
.SetDisplay("RSI Low", "RSI threshold for bearish weakness", "Logic");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ema, (ICandleMessage candle, decimal rsiVal, decimal emaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
// Strong trend up: RSI above threshold and price above EMA
if (rsiVal > RsiHigh && close > emaVal && Position <= 0)
BuyMarket();
// Weak trend / bearish: RSI below threshold and price below EMA
else if (rsiVal < RsiLow && close < emaVal && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
var rsiArea = CreateChartArea();
if (rsiArea != null)
DrawIndicator(rsiArea, rsi);
}
}
}
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 RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class auto_adx_strategy(Strategy):
def __init__(self):
super(auto_adx_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period for direction", "Indicators")
self._rsi_high = self.Param("RsiHigh", 60.0) \
.SetDisplay("RSI High", "RSI threshold for bullish strength", "Logic")
self._rsi_low = self.Param("RsiLow", 40.0) \
.SetDisplay("RSI Low", "RSI threshold for bearish weakness", "Logic")
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def RsiHigh(self):
return self._rsi_high.Value
@property
def RsiLow(self):
return self._rsi_low.Value
def OnStarted2(self, time):
super(auto_adx_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, rsi_value, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
rv = float(rsi_value)
ev = float(ema_value)
if rv > self.RsiHigh and close > ev and self.Position <= 0:
self.BuyMarket()
elif rv < self.RsiLow and close < ev and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return auto_adx_strategy()