Открыть на GitHub

Стратегия ARD Order Management Stochastic

Обзор

Ard Order Management — порт MetaTrader-советника ARD_ORDER_MANAGEMENT_EA-BETA_1 на платформу StockSharp. Исходная версия была сосредоточена на дисциплине "сначала закрыть, потом открыть" и предоставляла вспомогательные процедуры для ручной корректировки стопов и тейков. Перенос сохранил эту философию и дополнил её автоматическим генератором сигналов на основе осциллятора Стохастик.

Базовая конфигурация рассчитана на работу с пятиминутными свечами по валютным парам, однако тип свечей можно выбрать любой. Расчёты выполняются только по завершённым барам, что полностью соответствует стилю оригинального эксперта.

Торговая логика

  • Используется стохастический осциллятор с настраиваемыми периодами (по умолчанию 5/3/3).
  • Если %K закрывается выше порога покупок (80), стратегия отменяет активные заявки, полностью закрывает шорт и открывает длинную позицию указанным объёмом.
  • Если %K закрывается ниже порога продаж (20), отменяются заявки, закрывается лонг и открывается новая короткая позиция.
  • Позиция удерживается до появления противоположного сигнала или срабатывания защитных механизмов.

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

  • Перед любым новым входом выполняется принудительное закрытие текущей позиции рыночным ордером — аналог ветки open_order(CLOSE) из MQL-версии.
  • Метод StartProtection автоматически выставляет стартовые стоп-лосс и тейк-профит на расстояниях, заданных параметрами StopLossPips и TakeProfitPips.
  • Опциональная trailing-логика повторяет поведение блока MODIFY: после закрытия каждой свечи пересчитываются динамические уровни стопа (ModifyStopLossPips) и плавающего тейка (ModifyTakeProfitPips). При касании любого уровня позиция немедленно закрывается, что позволяет зафиксировать прибыль или ограничить убыток.
  • Пересчёт пунктов выполняется по шагу цены инструмента (PriceStep) с поправкой на дробные пункты, благодаря чему параметры расстояний корректно переносятся между разными рынками.

Параметры

  • Volume — объём новой позиции; при развороте автоматически добавляется количество, необходимое для закрытия противоположной стороны.
  • TakeProfitPips / StopLossPips — стартовые уровни фиксации прибыли и ограничения убытка (в пунктах). Нулевое значение отключает соответствующий ордер.
  • ModifyTakeProfitPips / ModifyStopLossPips — параметры динамического обновления тейка и стопа. Нулевое значение выключает trailing.
  • StochasticPeriod / SignalPeriod / SlowingPeriod — настройки стохастика, соответствующие аргументам функции iStochastic в MQL-скрипте.
  • BuyThreshold / SellThreshold — границы перекупленности/перепроданности, активирующие вход в покупку или продажу.
  • CandleType — тип свечей, используемый для расчётов.

Каждый параметр снабжён адекватным диапазоном оптимизации, что упрощает подбор настроек в оптимизаторе StockSharp.

Рекомендации по применению

  • Наилучшие результаты достигаются на ликвидных инструментах с чётким шагом цены (основные FX-пары, индексные CFD, популярные фьючерсы).
  • Для менее волатильных рынков стоит увеличить таймфрейм, чтобы снизить количество ложных разворотов.
  • Перед запуском на реальном счёте убедитесь, что выбранный объём соответствует минимальным требованиям брокера.
  • Если trailing не нужен, оставьте параметры Modify* равными нулю — стратегия будет работать как классический вариант исходного эксперта.
  • При необходимости легко добавить фильтры по тренду, волатильности или торговым сессиям: необходимые свойства уже вынесены в публичные параметры.

Подробности конверсии

  • Исходный файл: MQL/9041/ARD_ORDER_MANAGEMENT_EA-BETA_1.mq4.
  • Воссоздана логика стохастического индикатора, упомянутая в закомментированных строках функции start().
  • Поведение по закрытию позиций и постановке защитных ордеров реализовано через высокоуровневый API StockSharp.
  • Добавлены необязательные trailing-выходы, которые отражают ручной режим MODIFY, но работают в полностью событийной модели.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Ard Order Management Stochastic: RSI overbought/oversold reversal
/// with EMA trend filter and ATR-based trailing stops.
/// </summary>
public class ArdOrderManagementStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _buyThreshold;
	private readonly StrategyParam<decimal> _sellThreshold;

	private decimal _prevRsi;

	public ArdOrderManagementStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_rsiLength = Param(nameof(RsiLength), 10)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_emaLength = Param(nameof(EmaLength), 14)
			.SetDisplay("EMA Length", "EMA trend filter period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 10)
			.SetDisplay("ATR Length", "ATR period for stops.", "Indicators");

		_buyThreshold = Param(nameof(BuyThreshold), 30m)
			.SetDisplay("Buy Threshold", "RSI oversold level for buy.", "Signals");

		_sellThreshold = Param(nameof(SellThreshold), 70m)
			.SetDisplay("Sell Threshold", "RSI overbought level for sell.", "Signals");
	}

	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 int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public decimal BuyThreshold
	{
		get => _buyThreshold.Value;
		set => _buyThreshold.Value = value;
	}

	public decimal SellThreshold
	{
		get => _sellThreshold.Value;
		set => _sellThreshold.Value = value;
	}

	/// <inheritdoc />
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevRsi = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevRsi = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, ema, atr, ProcessCandle)
			.Start();

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevRsi == 0)
		{
			_prevRsi = rsiVal;
			return;
		}

		// Entry: RSI crosses threshold
		if (Position == 0)
		{
			if (rsiVal < BuyThreshold && _prevRsi >= BuyThreshold)
			{
				BuyMarket();
			}
			else if (rsiVal > SellThreshold && _prevRsi <= SellThreshold)
			{
				SellMarket();
			}
		}

		_prevRsi = rsiVal;
	}
}