Estrategia automática RXD v1.67
Descripción general
Auto RXD v1.67 es una estrategia basada en reglas que emula al asesor experto MetaTrader del mismo nombre. El enfoque utiliza tres perceptrones lineales: un supervisor que decide si buscar señales alcistas o bajistas, además de un perceptrón dedicado para cada dirección. Cada perceptrón opera con promedios móviles ponderados lineales (LWMA) calculados a partir del cierre de la vela y las entradas de "precio ponderado" de Robbie Ruan (alto + mínimo + 2 × cierre). El puerto StockSharp se ejecuta solo en velas completadas y utiliza el flujo de datos de alto nivel BindEx para mantener los cálculos del indicador sincronizados con el ciclo comercial.
Datos e indicadores del mercado
- Velas: el período de tiempo predeterminado es velas de 30 minutos. El plazo se puede cambiar a través del parámetro
CandleType.
- Rango verdadero promedio (ATR): proporciona distancias de toma de ganancias y de parada de pérdidas adaptables cuando
UseAtrTargets está habilitado. El período ATR está controlado por AtrPeriod.
- Índice de fuerza relativa (RSI): filtro opcional que aplica operaciones largas por encima del nivel neutral 50 y ventas cortas por debajo de 50 cuando
UseRsiFilter es verdadero.
- Índice de canales de productos básicos (CCI): filtro de tendencias opcional que requiere lecturas superiores a +100 para posiciones largas y inferiores a -100 para posiciones cortas cuando
UseCciFilter está activo.
- Divergencia de convergencia de media móvil (MACD): confirmación de impulso opcional. Las entradas largas requieren la línea MACD encima de la línea de señal, mientras que las cortas necesitan la línea MACD debajo de la línea de señal cuando
UseMacdFilter es verdadero.
- Índice direccional promedio (ADX): filtro de intensidad opcional que verifica que ADX esté por encima del umbral configurado y que +DI versus -DI se alinee con la dirección deseada cuando
UseAdxFilter está habilitado.
Lógica de trading
- Preparación de datos de Perceptron: para cada vela, la estrategia actualiza los buffers con los últimos precios de cierre y ponderados. Los buffers alimentan instantáneas LWMA, generando cuatro características retrasadas separadas por los valores
Step configurados para perceptrones cortos, largos y supervisores.
- Decisión del supervisor: el perceptrón supervisor evalúa los deltas rezagados utilizando los parámetros de peso
SupervisorX1…X4 y SupervisorThreshold. Una puntuación positiva desbloquea el perceptrón largo; una puntuación negativa desbloquea el perceptrón corto. Si la puntuación del supervisor es cero o no está disponible (no hay suficientes datos), se omite la vela.
- Especialistas direccionales: el perceptrón correspondiente (largo o corto) valida su propia puntuación utilizando el mismo conjunto de funciones LWMA y pesos específicos de dirección (
LongX* o ShortX*). Un valor positivo desencadena la siguiente etapa de validación.
- Filtros de indicador: cuando
UseIndicatorFilters es falso, la estrategia opera únicamente con la señal del perceptrón. Cuando es verdadero, cada filtro habilitado (RSI, CCI, MACD, ADX) debe coincidir con la dirección propuesta. Los datos faltantes del indicador o las condiciones fallidas cancelan la señal.
- Ejecución de órdenes: la estrategia garantiza que no haya órdenes activas, aplana cualquier exposición opuesta e ingresa utilizando órdenes de mercado de tamaño
OrderVolume. Los precios de entrada se establecen por defecto en la mejor cotización cuando esté disponible; de lo contrario, la vela se cierra.
Gestión del riesgo
- Órdenes de protección: después de completar una entrada, la estrategia calcula inmediatamente las distancias de obtención de ganancias y parada de pérdidas hasta
CalculateProtectiveDistances. Cuando UseAtrTargets es verdadero, las distancias escalan ATR según los multiplicadores configurados (AtrTakeProfitFactor, AtrStopLossFactor) y según las magnitudes TP/SL originales MQL basadas en puntos. Si la segmentación ATR está deshabilitada, las distancias de puntos fijos se convierten en incrementos de precios.
- Gestión de órdenes: el asistente
SetProtectiveOrders traduce distancias brutas en conteos de pasos de precio y registra órdenes de stop-loss y take-profit en relación con el precio de entrada. La estrategia evita pedidos duplicados marcando HasActiveOrders() antes de enviar nuevas operaciones.
- Iniciar protección:
StartProtection() se llama una vez en OnStarted, lo que permite el manejo de protección integrado del marco siempre que la posición sea distinta de cero.
Parámetros
La implementación de StockSharp expone el conjunto completo de parámetros MQL agrupados para optimización y claridad de la interfaz de usuario. Los parámetros clave incluyen:
Comercio
OrderVolume – Tamaño del lote para nuevas posiciones.
CandleType: tipo de datos de vela utilizado para el enlace.
Riesgo
UseAtrTargets: alterna entre distancias de protección basadas en ATR y de punto fijo.
AtrPeriod, AtrTakeProfitFactor, AtrStopLossFactor – ATR configuración para objetivos adaptables.
LongTakeProfitPoints, LongStopLossPoints, ShortTakeProfitPoints, ShortStopLossPoints: referencias TP/SL basadas en puntos reutilizadas tanto por ATR como por modos fijos.
Filtros de indicador
UseIndicatorFilters – Interruptor maestro para todos los filtros.
UseAdxFilter, AdxPeriod, AdxThreshold – ADX configuración de confirmación.
UseMacdFilter, MacdFast, MacdSlow, MacdSignal – MACD configuración de confirmación.
UseRsiFilter, RsiPeriod – RSI configuración de confirmación.
UseCciFilter, CciPeriod – CCI configuración de confirmación.
Especialistas en perceptrones
ShortMaPeriod, ShortStep, ShortX1…ShortX4, ShortThreshold – Configuración corta del perceptrón.
LongMaPeriod, LongStep, LongX1…LongX4, LongThreshold – Configuración de perceptrón largo.
SupervisorMaPeriod, SupervisorStep, SupervisorX1…SupervisorX4, SupervisorThreshold – Configuración del perceptrón supervisor.
Todos los parámetros numéricos reflejan los valores predeterminados de MQL, lo que permite un comportamiento similar entre el asesor experto original y este puerto StockSharp al tiempo que expone la configuración a través del sistema StrategyParam para campañas de optimización.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Auto RXD V1.67: RSI + CCI momentum with EMA trend filter.
/// </summary>
public class AutoRXDV167Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _cciLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevRsi;
private decimal _entryPrice;
public AutoRXDV167Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_cciLength = Param(nameof(CciLength), 14)
.SetDisplay("CCI Length", "CCI period.", "Indicators");
_emaLength = Param(nameof(EmaLength), 50)
.SetDisplay("EMA Length", "EMA trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period for stops.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int CciLength
{
get => _cciLength.Value;
set => _cciLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = 0;
_entryPrice = 0;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var cci = new CommodityChannelIndex { Length = CciLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, cci, ema, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal cciVal, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevRsi == 0 || atrVal <= 0)
{
_prevRsi = rsiVal;
return;
}
var close = candle.ClosePrice;
if (Position > 0)
{
if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 3m || (rsiVal > 70 && cciVal > 100))
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (close >= _entryPrice + atrVal * 2m || close <= _entryPrice - atrVal * 3m || (rsiVal < 30 && cciVal < -100))
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (rsiVal > 50 && cciVal > 0 && close > emaVal && _prevRsi <= 50)
{
_entryPrice = close;
BuyMarket();
}
else if (rsiVal < 50 && cciVal < 0 && close < emaVal && _prevRsi >= 50)
{
_entryPrice = close;
SellMarket();
}
}
_prevRsi = rsiVal;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex, CommodityChannelIndex, ExponentialMovingAverage, AverageTrueRange
class auto_rxdv167_strategy(Strategy):
def __init__(self):
super(auto_rxdv167_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._cci_length = self.Param("CciLength", 14) \
.SetDisplay("CCI Length", "CCI period.", "Indicators")
self._ema_length = self.Param("EmaLength", 50) \
.SetDisplay("EMA Length", "EMA trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period for stops.", "Indicators")
self._prev_rsi = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def CciLength(self):
return self._cci_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(auto_rxdv167_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
self._cci = CommodityChannelIndex()
self._cci.Length = self.CciLength
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._cci, self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, cci_val, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
cv = float(cci_val)
ev = float(ema_val)
av = float(atr_val)
if self._prev_rsi == 0 or av <= 0:
self._prev_rsi = rv
return
close = float(candle.ClosePrice)
if self.Position > 0:
if close <= self._entry_price - av * 2.0 or close >= self._entry_price + av * 3.0 or (rv > 70 and cv > 100):
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close >= self._entry_price + av * 2.0 or close <= self._entry_price - av * 3.0 or (rv < 30 and cv < -100):
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
if self.Position == 0:
if rv > 50 and cv > 0 and close > ev and self._prev_rsi <= 50:
self._entry_price = close
self.BuyMarket()
elif rv < 50 and cv < 0 and close < ev and self._prev_rsi >= 50:
self._entry_price = close
self.SellMarket()
self._prev_rsi = rv
def OnReseted(self):
super(auto_rxdv167_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._entry_price = 0.0
def CreateClone(self):
return auto_rxdv167_strategy()