Открыть на GitHub

Стратегия Crossing Moving Average

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

  • Конвертация советника MetaTrader 5 "Crossing Moving Average (barabashkakvn's edition)" из исходника MQL/21515.
  • Логика реализована на высокоуровневом API StockSharp с подпиской на свечи и связкой индикаторов.
  • Подходит для инструментов, где пересечение скользящих средних и импульс отражают смену тренда.
  • В комплект входит только версия на C#; Python-реализация намеренно не создавалась по требованию.

Ключевая идея

Стратегия отслеживает две настраиваемые скользящие средние (быструю и медленную) с опциональными смещениями и подтверждает пересечения фильтром Momentum. Сделка открывается лишь тогда, когда одновременно выполняются условия:

  1. Быстрая средняя пересекает медленную и превышает минимально допустимую дистанцию (в пунктах) на двух последних завершённых барах.
  2. Значение Momentum превышает (для покупок) или опускается ниже (для продаж) заданного порога и улучшается в направлении сделки.
  3. Тип цены для расчёта индикаторов выбирается из набора Open, High, Low, Close, Median, Typical или Weighted, что позволяет повторить режимы MetaTrader.

Управление позицией и рисками

  • Объём заявки фиксируется параметром и используется как при открытии новой позиции, так и при развороте из противоположной.
  • Стоп-лосс и тейк-профит задаются в пунктах и автоматически переводятся в цену через Security.PriceStep. Для инструментов с 3 или 5 знаками после запятой шаг умножается на 10, как в MetaTrader.
  • Трейлинг-стоп активируется, когда цена проходит расстояние TrailingStop + TrailingStep пунктов от точки входа. После активации стоп переносится на текущая цена - TrailingStop (для покупок) или текущая цена + TrailingStop (для продаж), но только если улучшение не меньше TrailingStep пунктов.
  • На каждом завершённом баре диапазон свечи проверяется на касание защитных уровней. При достижении стопа или тейка позиция закрывается рыночной заявкой, что имитирует исполнение заявок в MetaTrader.

Индикаторы

  • Быстрая скользящая средняя — настраиваемый период, сдвиг и тип сглаживания (SMA, EMA, SMMA, WMA).
  • Медленная скользящая средняя — те же параметры, что и у быстрой.
  • Momentum — период и тип цены совпадают с выбранным для скользящих. Стратегия автоматически определяет, выдаёт ли индикатор значения около 0 или около 100, и корректирует фильтр.

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

  1. Дождаться, когда все индикаторы полностью сформируются. История последних значений хранится локально для корректной оценки смещённых пересечений, как в оригинальном советнике.
  2. Вычислить расстояние между быстрым и медленным средними на двух предыдущих барах с учётом смещений. Быстрая линия должна пересечь медленную и превысить минимальную дистанцию.
  3. Получить значения Momentum на тех же барах. Для покупок текущее значение должно быть выше порога и предыдущего, для продаж — ниже отрицательного порога и предыдущего.
  4. При появлении противоположного сигнала открытая позиция закрывается и сразу открывается новая в направлении сигнала с заданным объёмом.

Таблица параметров

Параметр Назначение Значение по умолчанию
OrderVolume Базовый объём каждой рыночной заявки. 1
StopLossPips Дистанция стоп-лосса в пунктах (0 — отключить). 50
TakeProfitPips Дистанция тейк-профита в пунктах (0 — отключить). 50
TrailingStopPips Размер трейлинг-стопа в пунктах (0 — отключить). 5
TrailingStepPips Минимальное улучшение в пунктах для переноса трейлинг-стопа. 5
MinDistancePips Минимальное расстояние между средними для подтверждения сигнала. 0
MomentumFilter Минимальный импульс для входа. 0.1
FastPeriod / FastShift Период и сдвиг быстрой средней (в барах). 13 / 1
SlowPeriod / SlowShift Период и сдвиг медленной средней (в барах). 34 / 3
MaMethod Тип сглаживания (Simple, Exponential, Smoothed, Weighted). Exponential
AppliedPrice Цена свечи для расчёта индикаторов. Close
MomentumPeriod Количество баров в расчёте Momentum. 14
CandleType Тип свечей, используемых стратегией. TimeFrame(1m)

Практические рекомендации

  • Убедитесь, что Security.PriceStep задан для инструмента, иначе расчёт пунктов будет выполняться в абсолютных ценах.
  • Для корректной работы трейлинга при включённом TrailingStopPips необходимо задать положительное TrailingStepPips, что повторяет проверку оригинального эксперта.
  • Проверка срабатывания стопов и тейков выполняется по диапазону свечи. Чем меньше таймфрейм, тем точнее моделируется тиковое исполнение.
  • В коде оставлены информационные сообщения о входах и переносах стопов, что упрощает отладку и подбор параметров.

Структура файлов

API/2938_Crossing_Moving_Average/
├── CS/CrossingMovingAverageStrategy.cs
├── README.md
├── README_zh.md
└── README_ru.md
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>
/// Moving average crossover strategy.
/// Enters long when fast EMA crosses above slow EMA, enters short on the opposite crossover.
/// </summary>
public class CrossingMovingAverageStrategy : 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 CrossingMovingAverageStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(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 fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fastEma);
			DrawIndicator(area, slowEma);
			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;
		}

		// Crossover detection
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;

		_prevFast = fast;
		_prevSlow = slow;

		// Golden cross: fast crosses above slow
		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// Death cross: fast crosses below slow
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}