Открыть на GitHub

Стратегия Expert MACD EURUSD 1 Hour

Обзор

Данная стратегия представляет собой перевод советника MetaTrader 5 Expert MACD EURUSD 1 Hour на C#. Торговля ведётся по часовым свечам с использованием индикатора MACD с периодами 5 / 15 / 3. Стратегия ищет импульсные развороты, когда основная линия MACD пересекает нулевой уровень, а сигнальная линия подтверждает движение. Для защиты позиций используется трейлинг-стоп, а выход из сделки происходит при смене наклона MACD против текущей позиции.

Параметры

  • FastLength – период быстрой EMA для MACD (по умолчанию 5).
  • SlowLength – период медленной EMA для MACD (по умолчанию 15).
  • SignalLength – период сигнальной линии MACD (по умолчанию 3).
  • TrailingPoints – размер трейлинг-стопа в пунктах цены (по умолчанию 25).
  • CandleType – тип свечей, таймфрейм (по умолчанию 1 час).
  • Объём позиций задаётся свойством стратегии Volume.

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

Вход в лонг

  1. Значения сигнальной линии: mac8 > mac7 > mac6 и mac6 < mac5 (рост сигнальной линии).
  2. Значения основной линии: mac4 > mac3 < mac2 < mac1 (рост основной линии после снижения).
  3. mac2 < -0.00020, mac4 < 0 и mac1 > 0.00020 – основная линия пересекает нулевой уровень вверх.
  4. При выполнении условий и отсутствии позиции покупается по рынку.

Вход в шорт

  1. Значения сигнальной линии: mac8 < mac7 < mac6 и mac6 > mac5 (падение сигнальной линии).
  2. Значения основной линии: mac4 < mac3 > mac2 > mac1 (падение основной линии после вершины).
  3. mac2 > 0.00020, mac4 > 0 и mac1 < -0.00035 – основная линия пересекает нулевой уровень вниз.
  4. При выполнении условий и отсутствии позиции продаётся по рынку.

Правила выхода

  • Лонг закрывается, если текущее значение основной линии ниже предыдущего.
  • Шорт закрывается, если текущее значение основной линии выше предыдущего.
  • Трейлинг-стоп обновляется на каждой свече и закрывает позицию при пересечении цены уровня стопа.

Примечания

Пример демонстрирует использование высокоуровневого API StockSharp с привязкой индикаторов и ручным управлением трейлинг-стопом. Стратегия предназначена для учебных целей и не содержит расширенного манименеджмента помимо фиксированного параметра Volume.

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD based strategy converted from MetaTrader 5 Expert Advisor.
/// Uses MACD indicator with custom pattern checks on recent values and optional trailing stop.
/// </summary>
public class ExpertMacdEurusd1HourStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<decimal> _trailingPoints;
	private readonly StrategyParam<DataType> _candleType;
	private ExponentialMovingAverage _fastEma;
	private ExponentialMovingAverage _slowEma;
	private ExponentialMovingAverage _signalEma;

	private decimal _main0, _main1;
	private decimal _signal0, _signal1;
	private int _counter;

	/// <summary>
	/// Fast EMA length for MACD.
	/// </summary>
	public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }

	/// <summary>
	/// Slow EMA length for MACD.
	/// </summary>
	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }

	/// <summary>
	/// Signal line length for MACD.
	/// </summary>
	public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }

	/// <summary>
	/// Trailing stop distance in price points.
	/// </summary>
	public decimal TrailingPoints { get => _trailingPoints.Value; set => _trailingPoints.Value = value; }

	/// <summary>
	/// Candle type for analysis.
	/// </summary>
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	/// <summary>
	/// Initialize strategy with default parameters.
	/// </summary>
	public ExpertMacdEurusd1HourStrategy()
	{
		_fastLength = Param(nameof(FastLength), 12)
			.SetDisplay("Fast Length", "Fast EMA length for MACD", "Parameters")
			;

		_slowLength = Param(nameof(SlowLength), 26)
			.SetDisplay("Slow Length", "Slow EMA length for MACD", "Parameters")
			;

		_signalLength = Param(nameof(SignalLength), 9)
			.SetDisplay("Signal Length", "Signal length for MACD", "Parameters")
			;

		_trailingPoints = Param(nameof(TrailingPoints), 25m)
			.SetDisplay("Trailing Points", "Trailing stop distance in points", "Risk");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_main0 = _main1 = 0m;
		_signal0 = _signal1 = 0m;
		_counter = 0;
		_fastEma = null;
		_slowEma = null;
		_signalEma = null;
	}

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

		_fastEma = new ExponentialMovingAverage { Length = FastLength };
		_slowEma = new ExponentialMovingAverage { Length = SlowLength };
		_signalEma = new ExponentialMovingAverage { Length = SignalLength };

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

		StartProtection(
			new Unit(2000m, UnitTypes.Absolute),
			new Unit(1000m, UnitTypes.Absolute));

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

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

		var fast = _fastEma.Process(candle.ClosePrice, candle.CloseTime, true).ToDecimal();
		var slow = _slowEma.Process(candle.ClosePrice, candle.CloseTime, true).ToDecimal();
		if (!_fastEma.IsFormed || !_slowEma.IsFormed)
			return;

		var main = fast - slow;
		var signal = _signalEma.Process(main, candle.CloseTime, true).ToDecimal();
		if (!_signalEma.IsFormed)
			return;

		// shift stored values
		_main1 = _main0;
		_main0 = main;

		_signal1 = _signal0;
		_signal0 = signal;

		if (_counter < 3)
		{
			_counter++;
			return;
		}

		var buySignal = _main1 <= _signal1 && _main0 > _signal0 && _main0 < 0m;
		var sellSignal = _main1 >= _signal1 && _main0 < _signal0 && _main0 > 0m;

		if (buySignal && Position <= 0)
			BuyMarket();
		else if (sellSignal && Position >= 0)
			SellMarket();
	}
}