Auto RXD v1.67 Strategy
Overview
Auto RXD v1.67 is a rule-based strategy that emulates the MetaTrader expert advisor of the same name. The approach uses three linear perceptrons: a supervisor that decides whether to look for bullish or bearish signals, plus a dedicated perceptron for each direction. Every perceptron operates on linear weighted moving averages (LWMAs) calculated from candle close and Robbie Ruan's "weighted price" (high + low + 2 × close) inputs. The StockSharp port executes on completed candles only and uses the high-level BindEx data flow to keep the indicator calculations synchronized with the trading loop.
Market Data and Indicators
- Candles – Default timeframe is 30-minute candles. The timeframe can be changed through the
CandleType parameter.
- Average True Range (ATR) – Provides both adaptive take profit and stop loss distances when
UseAtrTargets is enabled. ATR period is controlled by AtrPeriod.
- Relative Strength Index (RSI) – Optional filter enforcing long trades above the neutral 50 level and shorts below 50 when
UseRsiFilter is true.
- Commodity Channel Index (CCI) – Optional trend filter that requires readings above +100 for longs and below -100 for shorts when
UseCciFilter is active.
- Moving Average Convergence Divergence (MACD) – Optional momentum confirmation. Long entries require the MACD line above the signal line, while shorts need the MACD line below the signal line when
UseMacdFilter is true.
- Average Directional Index (ADX) – Optional strength filter that checks ADX is above the configured threshold and that +DI versus -DI aligns with the desired direction when
UseAdxFilter is enabled.
Trading Logic
- Perceptron Data Preparation – For each candle the strategy updates buffers with the latest close and weighted prices. The buffers feed LWMA snapshots, generating four lagged features separated by the configured
Step values for short, long, and supervisor perceptrons.
- Supervisor Decision – The supervisor perceptron evaluates the lagged deltas using the weight parameters
SupervisorX1…X4 and SupervisorThreshold. A positive score unlocks the long perceptron; a negative score unlocks the short perceptron. If the supervisor score is zero or unavailable (not enough data), the candle is skipped.
- Directional Specialists – The matching perceptron (long or short) validates its own score using the same LWMA feature set and direction-specific weights (
LongX* or ShortX*). A positive value triggers the next validation stage.
- Indicator Filters – When
UseIndicatorFilters is false the strategy trades solely on the perceptron signal. When true, each enabled filter (RSI, CCI, MACD, ADX) must agree with the proposed direction. Missing indicator data or failing conditions cancel the signal.
- Order Execution – The strategy ensures there are no active orders, flattens any opposite exposure, and enters using market orders sized by
OrderVolume. Entry prices default to the best quote when available, otherwise the candle close.
Risk Management
- Protective Orders – After filling an entry the strategy immediately computes take profit and stop loss distances through
CalculateProtectiveDistances. When UseAtrTargets is true the distances scale ATR by the configured multipliers (AtrTakeProfitFactor, AtrStopLossFactor) and by the original MQL point-based TP/SL magnitudes. If ATR targeting is disabled, fixed point distances are converted to price steps.
- Order Management – The helper
SetProtectiveOrders translates raw distances into price-step counts and registers stop-loss and take-profit orders relative to the entry price. The strategy avoids duplicate orders by checking HasActiveOrders() before submitting new trades.
- Start Protection –
StartProtection() is called once in OnStarted, enabling the framework’s built-in protection handling whenever the position becomes non-zero.
Parameters
The StockSharp implementation exposes the full MQL parameter set grouped for optimization and UI clarity. Key parameters include:
Trading
OrderVolume – Lot size for new positions.
CandleType – Candle data type used for binding.
Risk
UseAtrTargets – Toggle between ATR-based and fixed-point protective distances.
AtrPeriod, AtrTakeProfitFactor, AtrStopLossFactor – ATR configuration for adaptive targets.
LongTakeProfitPoints, LongStopLossPoints, ShortTakeProfitPoints, ShortStopLossPoints – Point-based TP/SL references reused by both ATR and fixed modes.
Indicator Filters
UseIndicatorFilters – Master switch for all filters.
UseAdxFilter, AdxPeriod, AdxThreshold – ADX confirmation settings.
UseMacdFilter, MacdFast, MacdSlow, MacdSignal – MACD confirmation settings.
UseRsiFilter, RsiPeriod – RSI confirmation settings.
UseCciFilter, CciPeriod – CCI confirmation settings.
Perceptron Specialists
ShortMaPeriod, ShortStep, ShortX1…ShortX4, ShortThreshold – Short perceptron configuration.
LongMaPeriod, LongStep, LongX1…LongX4, LongThreshold – Long perceptron configuration.
SupervisorMaPeriod, SupervisorStep, SupervisorX1…SupervisorX4, SupervisorThreshold – Supervisor perceptron configuration.
All numeric parameters mirror the MQL defaults, enabling a like-for-like behavior between the original expert advisor and this StockSharp port while exposing the configuration through the StrategyParam system for optimization campaigns.
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()