Открыть на GitHub

Стратегия Auto RXD v1.67

Общее описание

Auto RXD v1.67 — это порт MetaTrader-советника, построенного на трёх линейных перцептронах. Один перцептрон выступает в роли "надзирателя" и решает, стоит ли искать сделки на покупку или продажу, а ещё два специализируются на каждой стороне. Каждый перцептрон работает с линейно взвешенными скользящими средними (LWMA), рассчитанными по цене закрытия и взвешенной цене Robbie Ruan (high + low + 2 × close). Реализация для StockSharp обрабатывает только завершённые свечи и использует высокоуровневый BindEx, чтобы поддерживать синхронизацию индикаторов и торговой логики.

Рыночные данные и индикаторы

  • Свечи – По умолчанию используется таймфрейм 30 минут, который настраивается параметром CandleType.
  • Average True Range (ATR) – При включённом UseAtrTargets определяет адаптивные тейк-профиты и стоп-лоссы. Период задаётся параметром AtrPeriod.
  • Relative Strength Index (RSI) – Дополнительный фильтр, требующий значение выше 50 для покупок и ниже 50 для продаж, если UseRsiFilter равен true.
  • Commodity Channel Index (CCI) – Фильтр тренда, требующий показателя выше +100 для лонгов и ниже -100 для шортов при активном UseCciFilter.
  • Moving Average Convergence Divergence (MACD) – Фильтр импульса. Лонги допускаются, если линия MACD выше сигнальной, шорты — если ниже, при включённом UseMacdFilter.
  • Average Directional Index (ADX) – Фильтр силы тренда, проверяющий превышение порога AdxThreshold и согласованность направлений +DI и -DI при включённом UseAdxFilter.

Логика торговли

  1. Подготовка данных – На каждой свече стратегия обновляет буферы закрытия и взвешенных цен. Буферы питают LWMA-срезы и формируют четыре лаговых признака с шагом Step для короткого, длинного и надзирательного перцептронов.
  2. Решение надзирателя – Надзиратель оценивает дельты с помощью весов SupervisorX1…X4 и смещения SupervisorThreshold. Положительное значение активирует длинный перцептрон, отрицательное — короткий. Нулевое либо отсутствующее значение приводит к пропуску свечи.
  3. Специалисты по направлениям – Активированный перцептрон (лонг или шорт) проверяет собственный результат с теми же признаками и весами (LongX* или ShortX*). Положительное значение переводит логику к фильтрам.
  4. Индикаторные фильтры – Если UseIndicatorFilters = false, сделки открываются только по сигналу перцептрона. При true каждый включённый фильтр (RSI, CCI, MACD, ADX) должен подтвердить направление. Отсутствие данных или несоблюдение условий отменяет сигнал.
  5. Исполнение ордеров – Стратегия проверяет отсутствие активных заявок, закрывает противоположную позицию и выставляет рыночный ордер объёмом OrderVolume. Цена входа определяется лучшей котировкой или ценой закрытия свечи.

Управление рисками

  • Защитные ордера – После входа вычисляются дистанции тейк-профита и стоп-лосса методом CalculateProtectiveDistances. При UseAtrTargets = true они масштабируются по ATR с учётом множителей AtrTakeProfitFactor и AtrStopLossFactor, а также исходных точечных значений TP/SL. Если ATR выключен, используются фиксированные расстояния в шагах цены.
  • Обработка заявок – Метод SetProtectiveOrders переводит дистанции в количество шагов цены и регистрирует стоп-лосс/тейк-профит относительно входной цены. Дублирующие заявки предотвращаются проверкой HasActiveOrders().
  • StartProtection – Метод StartProtection() вызывается в OnStarted один раз и включает встроенный контроль StockSharp при появлении позиции.

Параметры

Порт открывает весь набор параметров MQL и группирует их для удобной оптимизации.

Торговля

  • OrderVolume – Объём новой позиции.
  • CandleType – Тип свечей для подписки.

Риск

  • UseAtrTargets – Переключатель между ATR- и фиксированными целями.
  • AtrPeriod, AtrTakeProfitFactor, AtrStopLossFactor – Настройки ATR.
  • LongTakeProfitPoints, LongStopLossPoints, ShortTakeProfitPoints, ShortStopLossPoints – Базовые значения TP/SL в пунктах.

Индикаторные фильтры

  • UseIndicatorFilters – Главный переключатель фильтров.
  • UseAdxFilter, AdxPeriod, AdxThreshold – Настройки фильтра ADX.
  • UseMacdFilter, MacdFast, MacdSlow, MacdSignal – Настройки фильтра MACD.
  • UseRsiFilter, RsiPeriod – Настройки фильтра RSI.
  • UseCciFilter, CciPeriod – Настройки фильтра CCI.

Перцептроны

  • ShortMaPeriod, ShortStep, ShortX1…ShortX4, ShortThreshold – Конфигурация короткого перцептрона.
  • LongMaPeriod, LongStep, LongX1…LongX4, LongThreshold – Конфигурация длинного перцептрона.
  • SupervisorMaPeriod, SupervisorStep, SupervisorX1…SupervisorX4, SupervisorThreshold – Конфигурация надзирателя.

Все числовые значения совпадают с исходным советником, поэтому результаты портирования сопоставимы с оригиналом, а система StrategyParam облегчает оптимизацию и подбор параметров.

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;
	}
}