Открыть на GitHub

Стратегия Sensitive MACD Trailing

Описание

Стратегия является переносом советника «Sensitive» для MetaTrader 5 на платформу StockSharp. Основная идея — отрабатывать пересечения линий MACD вблизи нулевой отметки и сопровождать позицию набором защитных инструментов: фиксированными стоп-лоссом и тейк-профитом, а также ступенчатым трейлинг-стопом в пунктах. Вся логика работает только на закрытых свечах и использует высокоуровневый API.

Используемые данные и индикаторы

  • MACD (Moving Average Convergence Divergence) с настраиваемыми периодами быстрой, медленной EMA и сигнальной линии.
  • Свечи выбранного таймфрейма (параметр CandleType).

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

  1. Новый сигнал анализируется только после завершения очередной свечи.
  2. Из привязанного MACD получаем значения основной и сигнальной линий.
  3. Покупка выполняется, если выполняются условия:
    • Линия MACD пересекла сигнальную снизу вверх (текущее macd > signal, предыдущее macd < signal).
    • Значение MACD остаётся отрицательным.
    • Модуль MACD больше MacdOpenLevel * Point, что отсекает слабые колебания.
    • Текущая позиция не длинная (Position <= 0). При наличии короткой позиции выполняется разворот за один рыночный ордер.
  4. Продажа симметрична покупкам:
    • MACD пересекает сигнал сверху вниз, оставаясь положительным.
    • Модуль MACD превышает порог.
    • Нет активной короткой позиции (Position >= 0), при необходимости выполняется разворот из лонга.

Управление сделкой

  • Тейк-профит рассчитывается в момент входа по параметру TakeProfitPips. Длинная позиция закрывается, когда максимум свечи достигает целевой цены, короткая — когда минимум уходит ниже целевого уровня.
  • Стоп-лосс строится аналогично по StopLossPips. Для лонга выход происходит при касании стоп-уровня минимумом свечи, для шорта — при пробое максимума.
  • Трейлинг-стоп активируется, если TrailingStopPips > 0. После того как цена прошла в сторону позиции не менее TrailingStopPips + TrailingStepPips пунктов, стоп подтягивается вслед за ценой, сохраняя расстояние TrailingStopPips. Каждый следующий шаг выполняется только при дополнительном продвижении на величину TrailingStepPips. Если трейлинг включён, но шаг равен нулю, стратегия выводит сообщение об ошибке и останавливается.
  • После закрытия позиции внутренние переменные (_entryPrice, _stopLoss, _takeProfit) очищаются, чтобы избежать повторного срабатывания старых уровней.

Объём сделок

Количество контрактов задаётся параметром Volume (по умолчанию 0.1). При развороте позиция закрывается и открывается новое направление одной рыночной заявкой: к целевому объёму прибавляется абсолютное значение текущей позиции.

Параметры

Параметр Назначение Значение по умолчанию
FastLength Период быстрой EMA в MACD 12
SlowLength Период медленной EMA в MACD 26
SignalLength Период сигнальной EMA 9
MacdOpenLevel Минимальная величина MACD (в ценовых пунктах) для открытия сделки 3
StopLossPips Дистанция стоп-лосса в пунктах 35
TakeProfitPips Дистанция тейк-профита в пунктах 75
TrailingStopPips Базовое расстояние трейлинг-стопа (0 — выключено) 5
TrailingStepPips Минимальный шаг цены для обновления трейлинг-стопа 5
CandleType Тип и таймфрейм свечей Свечи 1 минуты
Volume Торговый объём (лоты/контракты) 0.1

Дополнительные сведения

  • Пункты и величина Point вычисляются из шага цены и количества знаков инструмента; для трёх- и пятизнаковых форекс-символов величина пункта автоматически масштабируется.
  • Все комментарии в коде на английском языке, реализация использует только высокоуровневые методы, как предписано в инструкциях.
  • Стратегия предполагает мгновенное исполнение рыночных ордеров. Если необходимо учитывать частичное исполнение или проскальзывание, логику можно доработать.
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>
/// Sensitive MACD Trailing strategy. Uses EMA crossover (5/15).
/// </summary>
public class SensitiveMacdTrailingStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast;
	private decimal? _prevSlow;

	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 SensitiveMacdTrailingStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 15).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}