Double MA Breakout Strategy — портирование эксперта MetaTrader DoubleMA_Breakout на StockSharp. Стратегия анализирует две скользящие средние на закрытых свечах. Когда быстрая средняя поднимается выше медленной, размещается отложенный приказ Buy Stop на заданном расстоянии от цены закрытия. При обратном пересечении размещается Sell Stop ниже рынка. Все отложенные заявки снимаются, а позиции закрываются, если сигнал меняется или торговое окно закрывается.
При конвертации сохранена ключевая логика пробоя, добавлены высокоуровневые методы управления приказами и расширена конфигурация через StrategyParam<T>. Все комментарии в коде переведены на английский язык.
Параметры
Параметр
Значение по умолчанию
Описание
FastMaPeriod
2
Период быстрой скользящей средней.
SlowMaPeriod
5
Период медленной скользящей средней.
FastMaMode
Simple
Тип расчёта для быстрой средней (SMA, EMA, SMMA, LWMA, LSMA).
SlowMaMode
Simple
Тип расчёта для медленной средней.
FastAppliedPrice
Close
Источник цены для быстрой средней (close, open, high, low, median, typical, weighted).
SlowAppliedPrice
Close
Источник цены для медленной средней.
SignalShift
1
Количество завершённых свечей, используемых для оценки пересечения (0 — текущая свеча).
BreakoutDistancePoints
45
Отступ в шагах цены, на котором выставляются стоп-приказы.
UseTimeWindow
true
Включает фильтр по времени начала и окончания торгов.
StartHour
11
Час (включительно), начиная с которого разрешено открывать сделки.
StopHour
16
Час (включительно), после которого торговля прекращается.
UseFridayCloseAll
true
Закрывает позиции и снимает приказы после наступления времени закрытия в пятницу.
FridayCloseTime
21:30
Время в пятницу, когда выполняется принудительное закрытие.
UseFridayStopTrading
false
Запрещает новые входы после заданного времени в пятницу, сохраняя открытые позиции.
FridayStopTradingTime
19:00
Время в пятницу, после которого новые входы блокируются (при включении).
CandleType
1 час
Тип свечей, используемый для расчётов.
Логика торговли
Подписка на завершённые свечи CandleType и расчёт двух скользящих средних согласно выбранным режимам и источникам цены.
Хранение кратких историй значений индикаторов, что позволяет ссылаться на свечу SignalShift без использования запрещённых методов GetValue.
Бычий сигнал: если быстрая средняя выше медленной на выбранной свече, снимаются Sell Stop, закрываются короткие позиции и выставляется Buy Stop на расстоянии BreakoutDistancePoints × PriceStep при отсутствии активных заявок и позиций.
Медвежий сигнал: если быстрая средняя ниже медленной, снимаются Buy Stop, закрываются длинные позиции и выставляется Sell Stop на симметричном расстоянии ниже.
Управление временем: при выходе за торговое окно все отложенные заявки снимаются. В пятницу учитываются опциональные времена остановки торговли и принудительного закрытия перед выходными.
При исполнении стоп-заявки противоположная заявка снимается для предотвращения одновременных сделок.
Отличия от оригинального эксперта
Функции мани-менеджмента и сложные схемы трейлинг-стопа не перенесены. Размер сделки задаётся через свойство Volume, а управление риском можно реализовать стандартными защитными модулями StockSharp.
Многократные попытки регистрации ордеров и низкоуровневые вызовы заменены высокоуровневыми методами (BuyStop, SellStop, ClosePosition, CancelOrder).
Специфичные для брокера проверки (например, Margincutoff, Slippage) опущены; при необходимости их можно добавить отдельно.
Режим LSMA использует индикатор LinearRegression из StockSharp для аппроксимации метода наименьших квадратов в MetaTrader.
Рекомендации по использованию
Перед запуском задайте нужный Volume; по умолчанию открывается один лот/контракт.
В коде вызывается StartProtection(), так что можно подключить стандартные стоп-лоссы и тейк-профиты платформы.
Для оптимизации включайте нужные параметры через .SetCanOptimize в конструкторе.
Убедитесь, что у инструмента корректно задан PriceStep; иначе расстояние пробоя принудительно устанавливается в 1.
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>
/// Double MA breakout strategy.
/// Buys on fast/slow EMA bullish crossover.
/// Sells on bearish crossover.
/// </summary>
public class DoubleMaBreakoutStrategy : 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 DoubleMaBreakoutStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 25)
.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;
}
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}