Открыть на GitHub

Стратегия Exp MA Rounding Candle MMRec

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

Exp MA Rounding Candle MMRec — порт эксперта MQL5 Exp_MA_Rounding_Candle_MMRec на платформу StockSharp. Исходный советник использует пользовательский индикатор «MA Rounding Candle», который преобразует каждую рыночную свечу в сглаженную синтетическую свечу и анализирует смену её цвета. C# реализация воссоздаёт эту логику на стороне стратегии, формируя индикатор «на лету» и реагируя на поток цветов.

Построение MA Rounding Candle

  1. Каждая входящая свеча прогоняется через четыре одинаковых скользящих средних (для Open, High, Low, Close). Доступны типы сглаживания: Simple, Exponential, Smoothed (RMA/SMMA) и Weighted.
  2. Полученные значения проходят «округляющий» фильтр. Новое значение принимается только если отличается от предыдущего более чем на RoundingFactor * PriceStep. В противном случае сохраняется прежний результат, что полностью повторяет поведение оригинального индикатора.
  3. Если реальная свеча имеет очень маленькое тело (|Open−Close| < GapSize * PriceStep), округлённое значение Open принудительно устанавливается равным предыдущему округлённому Close — маленькие дожи не меняют цвет синтетической свечи.
  4. Цвет свечи задаётся следующим образом:
    • 2 — бычья свеча (Open < Close)
    • 0 — медвежья свеча (Open > Close)
    • 1 — нейтральная свеча (Open = Close)

Стратегия хранит только небольшой буфер цветов (достаточный для учёта SignalBar), без длинной истории, как и исходный эксперт.

Логика сигналов

Оценка сигналов выполняется на завершённых свечах с использованием смещения SignalBar:

  • SignalBar задаёт, какую закрытую свечу считать сигнальной (0 — текущая закрытая, 1 — предыдущая и т. д.).
  • Дополнительно анализируется цвет свечи с индексом SignalBar + 1.
  • Переход бычья → не бычья (color[SignalBar + 1] = 2, color[SignalBar] != 2) приводит к:
    • закрытию коротких позиций при включённом EnableShortExits,
    • открытию длинной позиции при включённом EnableLongEntries.
  • Переход медвежья → не медвежья (color[SignalBar + 1] = 0, color[SignalBar] != 0) приводит к:
    • закрытию длинных позиций при включённом EnableLongExits,
    • открытию короткой позиции при включённом EnableShortEntries.

Сначала выполняется закрытие, затем — открытие. При развороте объём заявки увеличивается на абсолютную величину текущей позиции, чтобы чистая позиция совпала с желаемым направлением — так же, как в MQL5 версии.

Параметры

Параметр Значение по умолчанию Описание
CandleType часовые свечи Серия свечей, с которой работает стратегия.
SmoothingMethod Simple Тип скользящей средней для всех четырёх ценовых серий.
MaLength 12 Длина выбранной скользящей средней.
RoundingFactor 50 Множитель к PriceStep, определяющий порог округления (чем больше, тем реже обновление).
GapSize 10 Множитель к PriceStep для фильтра малых свечей; при малом теле Open приравнивается к предыдущему Close.
SignalBar 1 Смещение по истории для поиска сигналов.
TradeVolume 1 Базовый объём новой позиции; синхронизируется со свойством Strategy.Volume.
EnableLongEntries / EnableShortEntries true Разрешение на открытие длинных / коротких позиций.
EnableLongExits / EnableShortExits true Разрешение на закрытие длинных / коротких позиций.

Особенности реализации

  • Оставлены только те методы сглаживания, которые доступны в StockSharp; специфические варианты MQL5 (JJMA, JurX, VIDYA, AMA и др.) не поддерживаются.
  • Сложная система мани-менеджмента из оригинала заменена фиксированным параметром TradeVolume, что делает стратегию предсказуемой и удобной для оптимизации.
  • Все пороги (RoundingFactor, GapSize) интерпретируются в шагах цены, то есть автоматически масштабируются под инструмент через Security.PriceStep.
  • Используется высокоуровневый API SubscribeCandles, стратегия работает только с полностью сформированными свечами — аналогично ожиданию IsNewBar в MQL5.
  • Защитные механизмы (стоп-лосс, тейк-профит) не реализованы, поскольку их не было в исходном советнике.

Порядок работы

  1. Подключите стратегию к нужному инструменту и задайте подходящий CandleType (например, TimeSpan.FromHours(1).TimeFrame()).
  2. Настройте тип сглаживания, длину скользящей, коэффициенты округления и gap-фильтра в соответствии с оригиналом или собственными оптимизациями.
  3. Установите TradeVolume — желаемый торговый объём. Значение автоматически передаётся в Strategy.Volume.
  4. Включите или отключите флаги открытия/закрытия длинных и коротких позиций.
  5. Запустите стратегию. Сделки будут появляться при смене цвета индикатора MA Rounding Candle согласно описанным условиям.

Данная документация соответствует реализации из файла CS/ExpMaRoundingCandleMmrecStrategy.cs и предназначена для использования стратегии внутри StockSharp.

using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Exp MA Rounding Candle MMRec strategy. Uses SMA crossover (7/21).
/// </summary>
public class ExpMaRoundingCandleMmrecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast;
	private decimal? _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public ExpMaRoundingCandleMmrecStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 7).SetGreaterThanZero().SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}