Открыть на GitHub

Стратегия пересечения EMA 5/8

Описание

Стратегия пересечения EMA 5/8 повторяет работу советника MetaTrader 5_8macrossv2.mq4, сопоставляя две настраиваемые скользящие средние по одному инструменту. Бычье пересечение быстрой скользящей над медленной открывает длинную позицию, медвежье пересечение открывает короткую. Перенос использует высокоуровневый API StockSharp и добавляет управление рисками (тейк-профит, стоп-лосс, трейлинг-стоп).

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

  • На выбранном таймфрейме рассчитываются две скользящие средние. По умолчанию используется 5-периодная экспоненциальная средняя по ценам закрытия и 8-периодная экспоненциальная средняя по ценам открытия.
  • Когда быстрая средняя пересекает медленную снизу вверх на последней завершённой свече, стратегия открывает или разворачивает длинную позицию. Если открыта короткая позиция, её объём добавляется к рыночному ордеру на покупку для разворота.
  • Когда быстрая средняя пересекает медленную сверху вниз, стратегия аналогично открывает или разворачивает короткую позицию.
  • Параметры сдвига смещают сигналы на заданное количество закрытых свечей. Отрицательные значения приводятся к нулю, так как значения «из будущего» недоступны при онлайновом расчёте.

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

  • Тейк-профит и стоп-лосс задаются в пунктах (шагах цены). При открытии позиции целевые уровни рассчитываются от цены входа. Для коротких позиций логика симметрична.
  • Трейлинг-стоп также задаётся в пунктах и подтягивается в сторону прибыли только в благоприятную сторону (вверх для лонга, вниз для шорта).
  • Если на завершённой свече достигается любой защитный уровень (хай достигает тейк-профита, лоу — стоп-лосса или трейлинг-стопа), позиция закрывается рыночным ордером, а внутреннее состояние стратегии сбрасывается.

Параметры

Имя Тип Значение по умолчанию Описание
TradeVolume decimal 0.1 Объём ордера при открытии. При развороте добавляется абсолютная величина текущей позиции.
TakeProfitPips decimal 40 Расстояние до тейк-профита в пунктах. 0 отключает уровень.
StopLossPips decimal 0 Расстояние до стоп-лосса в пунктах. 0 отключает уровень.
TrailingStopPips decimal 0 Дистанция трейлинг-стопа в пунктах. 0 отключает подтягивание.
FastPeriod int 5 Период быстрой скользящей средней.
FastShift int -1 Горизонтальный сдвиг быстрой средней. Отрицательные значения приводятся к нулю.
FastMethod MovingAverageMethod Exponential Тип сглаживания быстрой средней: Simple, Exponential, Smoothed, LinearWeighted.
FastPrice AppliedPrice Close Цена свечи для расчёта быстрой средней.
SlowPeriod int 8 Период медленной скользящей средней.
SlowShift int 0 Горизонтальный сдвиг медленной средней.
SlowMethod MovingAverageMethod Exponential Тип сглаживания медленной средней.
SlowPrice AppliedPrice Open Цена свечи для расчёта медленной средней.
CandleType DataType TimeSpan.FromMinutes(30).TimeFrame() Тип свечей, используемых в расчётах.

Примечания

  • Расчёты выполняются только по завершённым свечам, что предотвращает ложные сигналы.
  • Защитные уровни рассчитываются через Security.PriceStep. Если шаг цены не задан, параметры управления рисками не активируются.
  • Версия на Python намеренно не создавалась в рамках задания.
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>
/// 5/8 MA Cross Protect strategy - EMA(5) and EMA(8) crossover.
/// Buys when EMA(5) crosses above EMA(8).
/// Sells when EMA(5) crosses below EMA(8).
/// </summary>
public class FiveEightMaCrossProtectStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

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

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

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

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }

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

		_hasPrev = false;

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

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

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

		if (!_hasPrev)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_hasPrev = true;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
	}
}