Открыть на GitHub

Стратегия Smoothed MA Directional

Эта стратегия представляет собой перенос на высокоуровневый API StockSharp советника MetaTrader 4 oc08_vy_m0moqesu15 из каталога MQL/8615. Оригинальный советник синхронизирует позицию с одной сглаженной скользящей средней (SMMA) и прикрепляет к каждой сделке фиксированные уровни стоп-лосса и тейк-профита. Версия на C# сохраняет ту же направленную идею, используя стандартные компоненты StockSharp.

Торговая идея

  • Направление: Закрытие цены выше сглаженной скользящей средней трактуется как восходящий тренд, ниже — как нисходящий.
  • Выравнивание позиции: Стратегия поддерживает только одну позицию и при смене сигнала мгновенно переворачивается в новое направление.
  • Управление рисками: Для каждой позиции задаются стоп-лосс и тейк-профит в шагах цены. Функция StartProtection заменяет ручную установку SL/TP из MQ4.
  • Исполнение: Заявки отправляются по рынку после закрытия свечи, что повторяет логику OrdersTotal()==0 в исходном эксперте.

Как работает стратегия

  1. При старте происходит подписка на свечи выбранного таймфрейма и привязка индикатора SmoothedMovingAverage с заданным периодом.
  2. После закрытия свечи значение индикатора сравнивается с ценой закрытия.
  3. Если закрытие выше SMMA и стратегия находится в шорте либо вне рынка, отправляется рыночная покупка, перекрывающая шорт (если был) и открывающая лонг.
  4. Если закрытие ниже SMMA и стратегия в лонге либо вне рынка, отправляется рыночная продажа, перекрывающая лонг (если был) и открывающая шорт.
  5. Расстояния стоп-лосса и тейк-профита рассчитываются один раз при запуске на основе PriceStep инструмента. Значение 0 отключает соответствующий уровень.
  6. При наличии области графика автоматически выводятся свечи, значение индикатора и сделки стратегии.

Параметры

Параметр Значение по умолчанию Описание
StopLossPoints 100 Расстояние стоп-лосса в шагах цены. 0 — стоп отключён.
TakeProfitPoints 100 Расстояние тейк-профита в шагах цены. 0 — тейк отключён.
MaPeriod 12 Период сглаженной скользящей средней для определения направления тренда.
TradeVolume 1 Объём рыночной заявки. При старте значение копируется в свойство Strategy.Volume.
CandleType Таймфрейм 15 минут Тип свечей (таймфрейм), по которым строятся индикатор и сигналы.

Все параметры настраиваются в StockSharp Designer/Runner и снабжены диапазонами для оптимизации.

Отличия от версии MetaTrader

  • Расчёт объёма через свободную маржу (Lots/Prots) заменён на фиксированный параметр TradeVolume, что обеспечивает предсказуемость и совместимость с портфелями StockSharp.
  • Стоп-лосс и тейк-профит управляются через StartProtection, что воспроизводит исходные смещения, но использует стандартные механизмы StockSharp.
  • Стратегия игнорирует незавершённые свечи, повторяя логику флага New_Bar из MQ4 и предотвращая досрочные сделки.

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

  • Убедитесь, что инструмент предоставляет корректный PriceStep. Если шаг не задан, стратегия использует значение 1 при вычислении защитных расстояний.
  • Период скользящей средней синхронизируется с текущим параметром на каждой свече, поэтому изменения настроек применяются без перезапуска.
  • Для полного соответствия оригиналу используйте тот же таймфрейм графика и задайте объём заявки согласно желаемому торговому лоту.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Smoothed MA directional strategy. Goes long when price is above the MA, short when below.
/// </summary>
public class SmoothedMaDirectionalStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;

	public SmoothedMaDirectionalStrategy()
	{
		_maPeriod = Param(nameof(MaPeriod), 12)
			.SetDisplay("MA Period", "Number of bars for the moving average.", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Time frame used for price analysis.", "General");
	}

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ma = new SimpleMovingAverage { Length = MaPeriod };

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

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

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

		var closePrice = candle.ClosePrice;

		if (closePrice > maValue && Position <= 0)
		{
			// Price above MA - go long
			if (Position < 0)
				BuyMarket(); // Close short
			BuyMarket(); // Open long
		}
		else if (closePrice < maValue && Position >= 0)
		{
			// Price below MA - go short
			if (Position > 0)
				SellMarket(); // Close long
			SellMarket(); // Open short
		}
	}
}