Открыть на GitHub

Стратегия Triple SMA Crossover

Обзор

Стратегия Triple SMA Crossover повторяет оригинального советника MQL 3sma.mq4. Система анализирует три простых скользящих средних (SMA), рассчитанных по цене закрытия, и открывает сделки, когда краткосрочный тренд согласуется со среднесрочным и долгосрочным. Конвертация сохраняет торговые правила исходника и переносит их на высокоуровневый API StockSharp.

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

  1. Рассчитываются три SMA с настраиваемыми периодами.
  2. Выход из длинной позиции, когда быстрая SMA опускается ниже средней SMA.
  3. Выход из короткой позиции, когда быстрая SMA поднимается выше средней SMA.
  4. Открытие новой длинной позиции, если:
    • Быстрая SMA выше средней хотя бы на заданное количество шагов цены.
    • Средняя SMA выше медленной хотя бы на заданное количество шагов цены.
    • Длинная позиция отсутствует.
  5. Открытие новой короткой позиции, если:
    • Быстрая SMA ниже средней хотя бы на заданное количество шагов цены.
    • Средняя SMA ниже медленной хотя бы на заданное количество шагов цены.
    • Короткая позиция отсутствует.

Параметры

  • Candle Type – Таймфрейм свечей, по которым строятся средние.
  • Fast SMA Length – Период быстрой SMA (параметр MQL SMA1).
  • Medium SMA Length – Период средней SMA (параметр MQL SMA2).
  • Slow SMA Length – Период медленной SMA (параметр MQL SMA3).
  • SMA Spread Steps – Фильтр, требующий расхождения средних на заданное число шагов цены (параметр MQL SMAspread).
  • Trade Volume – Объем заявки при открытии позиции (параметр MQL lots).

Примечания

  • Стоп-лосс из MQL-версии не используется, поскольку в исходнике он был отключен.
  • Закрытие позиций выполняется рыночными ордерами, как и в оригинальном советнике.
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>
/// Triple SMA crossover strategy.
/// Goes long when fast > medium > slow, short when fast less than medium less than slow.
/// Exits when fast crosses medium in opposite direction.
/// </summary>
public class TripleSmaCrossoverStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _mediumPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevMed;
	private bool _hasPrev;

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

	public TripleSmaCrossoverStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");

		_mediumPeriod = Param(nameof(MediumPeriod), 10)
			.SetDisplay("Medium SMA", "Medium SMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 20)
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0m;
		_prevMed = 0m;
		_hasPrev = false;
	}

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

		_hasPrev = false;

		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var medium = new SimpleMovingAverage { Length = MediumPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, medium, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fast;
			_prevMed = med;
			_hasPrev = true;
			return;
		}

		// Bullish alignment: fast > medium > slow
		if (fast > med && med > slow && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Bearish alignment: fast < medium < slow
		else if (fast < med && med < slow && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
		// Exit long when fast crosses below medium
		else if (Position > 0 && _prevFast >= _prevMed && fast < med)
		{
			SellMarket();
		}
		// Exit short when fast crosses above medium
		else if (Position < 0 && _prevFast <= _prevMed && fast > med)
		{
			BuyMarket();
		}

		_prevFast = fast;
		_prevMed = med;
	}
}