Открыть на GitHub

Стратегия SampleTrailingstop MT5

Описание

SampleTrailingstopMt5Strategy переносит в StockSharp логику советника MetaTrader 5 SampleTrailingstop-MT5.mq5. Стратегия круглосуточно поддерживает две встречные стоп-заявки на пробой, оформляет отдельные защитные ордера после входа и включает трейлинг-стоп при появлении плавающей прибыли. Все расчёты выполняются в «пунктах» и приводятся к цене через шаг цены инструмента, благодаря чему поведение совпадает с исходным МQL-скриптом.

Логика работы

  1. Подписка на данные. Используются котировки Level1 (лучшие bid/ask), которые инициируют обновление заявок и трейлинг-стопа.
  2. Вход в позицию.
    • На основе BuyStop выставляется покупка выше рынка. Новая заявка создаётся только после завершения предыдущей.
    • Зеркально размещается SellStop ниже текущей цены.
    • Обе заявки используют одинаковый объём, стоп-лосс и тейк-профит, а также получают срок действия +1 сутки, как в оригинальном файле.
  3. Защита позиции.
    • После сделок рассчитывается знаковая позиция и средняя цена входа.
    • Создаются отдельные защитные заявки: стоп-ордер (SellStop/BuyStop) и тейк-профит (SellLimit/BuyLimit), чтобы уровни сохранялись даже после отмены входных ордеров.
    • При изменении позиции или цены входа параметры защитных заявок синхронизируются автоматически.
  4. Трейлинг-стоп.
    • Когда прибыль достигает заданной дистанции, стоп подтягивается на фиксированное расстояние от текущего bid (для лонга) или ask (для шорта).
    • Стоп не пересекает цену входа и обновляется минимум на один шаг цены.
  5. Учёт позиции. Каждая своя сделка пересчитывает объём позиции и среднюю цену с учётом частичных закрытий и разворотов.

Параметры

Параметр Назначение
TradeVolume Постоянный объём для обеих пробойных стоп-заявок.
TakeProfitPoints Дистанция тейк-профита в пунктах. Ноль отключает тейк-профит.
StopLossPoints Дистанция защитного стоп-лосса в пунктах.
TrailingStopPoints Дистанция трейлинг-стопа в пунктах. Ноль отключает трейлинг.

Дополнительные детали

  • Новые стоп-заявки размещаются только после завершения предыдущих, что соответствует функции CheckPendingOrder из оригинала.
  • Перевод пунктов в цены выполняется через Security.PriceStep, что делает стратегию универсальной для инструментов с любой точностью.
  • При полном закрытии позиции все защитные заявки отменяются, а внутренние состояния обнуляются.
  • Для работы достаточно данных Level1; свечи и индикаторы не требуются, поэтому перенос максимально близок к MQL-версии.

Порядок использования

  1. Перед стартом задайте инструмент и портфель.
  2. Настройте параметры: объём, дистанции стоп-лосса, тейк-профита и трейлинг-стопа под конкретный рынок.
  3. Запустите стратегию — она самостоятельно будет поддерживать пробойные ордера и защиту позиции.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Sample Trailingstop MT5 strategy: EMA + RSI confirmation.
/// Buys when close above EMA and RSI above 50, sells when close below EMA and RSI below 50.
/// </summary>
public class SampleTrailingstopMt5Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal _prevClose;
	private decimal _prevEma;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }

	public SampleTrailingstopMt5Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevEma = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = 0;
		_prevEma = 0;
		_hasPrev = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, rsi, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevClose <= _prevEma && candle.ClosePrice > emaValue && rsiValue > 55 && Position <= 0)
				BuyMarket();
			else if (_prevClose >= _prevEma && candle.ClosePrice < emaValue && rsiValue < 45 && Position >= 0)
				SellMarket();
		}

		_prevClose = candle.ClosePrice;
		_prevEma = emaValue;
		_hasPrev = true;
	}
}