Открыть на GitHub

Стратегия MA Mirror

Обзор

MA Mirror — это портирование эксперта MetaTrader MA_MirrorEA. Стратегия сравнивает две простые скользящие средние одинаковой длины, но построенные по разным ценам: по закрытиям и по открытиям свечей. Когда среднее по закрытиям выше среднего по открытиям, система стремится находиться в длинной позиции; когда оно ниже — в короткой. Параметр MovingShift позволяет брать значения скользящих из прошлых свечей, что воспроизводит визуальный сдвиг индикатора в MetaTrader.

Реализация на StockSharp сохраняет «зеркальную» логику оригинала: одновременно держится только одна позиция, а смена сигнала сначала закрывает текущую позицию и затем открывает новую в противоположном направлении. Как и в MQL-версии, стратегия стартует с виртуального короткого сигнала, поэтому первая реальная сделка появится только после того, как среднее по закрытиям поднимется выше среднего по открытиям.

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

  1. Подписаться на свечи типа CandleType и обрабатывать только завершённые свечи, чтобы исключить решения по незакрытым барам.
  2. Прокармливать две простые скользящие средние ценами закрытия и открытия соответственно. Обе используют период MovingPeriod, поэтому их значения сопоставимы напрямую.
  3. Сохранять последние значения индикаторов в кольцевых буферах. Это позволяет получить значение MovingShift свечей назад и не обращаться к запрещённым методам индикаторов.
  4. Если сдвинутое среднее по закрытиям выше среднего по открытиям — формируется покупка; если ниже — продажа. При равных значениях сигнал не меняется.
  5. Если это первый сигнал и он не бычий, стратегия остаётся без позиции. В остальных случаях при смене сигнала закрывается текущее плечо и открывается новая рыночная позиция объёмом TradeVolume в нужном направлении.
  6. Обновляется запомненный сигнал, чтобы на последующих свечах не дублировать заявки, пока направление позиции не изменилось.

Параметры

Имя Тип Значение по умолчанию Описание
CandleType DataType таймфрейм 1 минута Основной поток свечей, используемых стратегией.
MovingPeriod int 20 Длина простых скользящих по закрытиям и открытиям.
MovingShift int 0 Количество завершённых свечей, на которое сдвигаются значения скользящих.
TradeVolume decimal 1 Объём каждой рыночной заявки.

Отличия от оригинального эксперта MetaTrader

  • Функции управления рисками из MQL-библиотеки (стоп-лосс, тейк-профит, трейлинг) не переносились. Версия для StockSharp всегда торгует фиксированным объёмом TradeVolume, а дополнительные ограничения при необходимости настраиваются отдельно.
  • MetaTrader ведёт учёт отдельных ордеров, тогда как StockSharp оперирует чистой позицией. Перед разворотом позиция закрывается, чтобы конечная экспозиция совпадала с поведением EA.
  • Индикаторы обрабатываются через подписку на свечи StockSharp и индикаторы SimpleMovingAverage с внутренними буферами вместо прямого вызова iMA.

Рекомендации по использованию

  • Перед запуском задайте TradeVolume в соответствии с минимальным шагом инструмента. Конструктор также присваивает это значение свойству Strategy.Volume, поэтому вспомогательные методы выставляют заявки нужного размера.
  • Увеличивайте MovingShift, если требуется анализировать более старые значения скользящих и повторить визуальный сдвиг MetaTrader.
  • Добавьте стратегию на график, чтобы видеть свечи, обе скользящие и собственные сделки — это помогает убедиться, что развороты происходят точно в моменты пересечения средних.

Используемые индикаторы

  • Две простые скользящие средние одинаковой длины (по ценам закрытия и открытия) с возможностью обратного сдвига.
namespace StockSharp.Samples.Strategies;

using System;
using System.Collections.Generic;

using Ecng.Common;

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

public class MaMirrorStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _movingPeriod;

	private SimpleMovingAverage _sma;
	private decimal? _prevDiff;

	public MaMirrorStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle type", "Timeframe processed by the strategy.", "General");

		_movingPeriod = Param(nameof(MovingPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Moving period", "Length of the SMA.", "Indicator");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int MovingPeriod
	{
		get => _movingPeriod.Value;
		set => _movingPeriod.Value = value;
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevDiff = null;
		_sma = null;
	}

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

		_prevDiff = null;

		_sma = new SimpleMovingAverage { Length = MovingPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_sma, ProcessCandle)
			.Start();
	}

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

		if (!_sma.IsFormed)
			return;

		// Mirror: compare close vs SMA (of close). When close crosses above SMA = buy, below = sell.
		var diff = candle.ClosePrice - smaValue;

		if (_prevDiff is not null)
		{
			if (_prevDiff.Value <= 0 && diff > 0 && Position <= 0)
			{
				BuyMarket();
			}
			else if (_prevDiff.Value >= 0 && diff < 0 && Position >= 0)
			{
				SellMarket();
			}
		}

		_prevDiff = diff;
	}
}