Открыть на GitHub

Стратегия пересечения скользящих средних

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

Стратегия повторяет оригинального советника MQL, основанного на пересечении скользящих средних. Она использует высокоуровневый API StockSharp, чтобы контролировать две простые скользящие средние на выбранной серии свечей. Сигналы появляются при пересечении быстрой средней и медленной, а при необходимости активная позиция может быть закрыта при появлении противоположного сигнала.

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

  • Подписка на заданный тип свечей и расчёт значений быстрой и медленной SMA на каждой завершённой свече.
  • Бычий сигнал фиксируется, когда быстрая SMA переходит из области ниже медленной в область выше. При отсутствии позиции открывается покупка выбранным объёмом.
  • Медвежий сигнал возникает, когда быстрая SMA переходит из области выше медленной в область ниже. При отсутствии позиции открывается продажа выбранным объёмом.
  • Если опция «Закрывать по противоположному сигналу» активна, текущая позиция закрывается сразу после появления обратного пересечения.

Управление рисками

  • Для каждой позиции рассчитывается фиксированный стоп-лосс и тейк-профит в пунктах инструмента.
  • После достижения заданной прибыли стоп переносится в зону безубыточности с дополнительным запасом прибыли.
  • Когда прибыль достигает заданного порога, включается трейлинг-стоп, который сопровождает цену и никогда не сдвигается в сторону убытка.

Параметры

  • Fast MA Period – период быстрой SMA.
  • Slow MA Period – период медленной SMA.
  • Trade Volume – торговый объём (лоты).
  • Stop Loss (points) – размер стоп-лосса в пунктах.
  • Take Profit (points) – размер тейк-профита в пунктах.
  • Break-even Trigger – прибыль в пунктах, необходимая для перевода стопа в безубыток.
  • Break-even Offset – дополнительный запас прибыли при переносе стопа в безубыток.
  • Trailing Start – прибыль, при которой активируется трейлинг-стоп.
  • Trailing Distance – расстояние между ценой и трейлинг-стопом.
  • Close On Opposite – закрытие позиции при появлении обратного сигнала.
  • Candle Type – тип свечей, по которым выполняются расчёты.

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

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

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Moving Averages Crossover strategy: EMA crossover.
/// Buys when fast EMA crosses above slow EMA. Sells on cross below.
/// </summary>
public class MovingAveragesCrossoverStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	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 MovingAveragesCrossoverStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

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

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

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		decimal? prevFast = null;
		decimal? prevSlow = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, fastVal, slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevSlow.HasValue)
				{
					var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
					var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;

					if (crossUp && Position <= 0)
						BuyMarket();
					else if (crossDown && Position >= 0)
						SellMarket();
				}

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

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