Базовая стратегия по скользящей средней — это перенос на StockSharp эксперта MetaTrader 4 из каталога MQL/27964. Исходный робот анализировал свечи старшего таймфрейма и открывал сделку, когда предыдущая свеча пересекала скользящую среднюю. C# версия полностью сохраняет логику, но предоставляет доступ ко всем настройкам через параметры StockSharp, что позволяет удобно оптимизировать систему в новой среде.
Алгоритм ждёт закрытия свечи, затем сравнивает её цену открытия и закрытия с заранее сдвинутым значением скользящей средней. Если свеча открылась выше средней и закрылась ниже — формируется короткий сигнал; если наоборот — длинный. Открывается только одна позиция за раз, как и в оригинале, где перед входом проверялось отсутствие активных ордеров с указанным MagicNumber.
Стоп-лосс и тейк-профит задаются в пунктах. При запуске стратегия вычисляет размер пункта, исходя из шага цены и количества знаков после запятой (для пяти- и трёхзнаковых котировок шаг умножается на десять), после чего переводит значения в абсолютное расстояние по цене и передаёт их в модуль защиты.
Логика торговли
Источник данных: одна серия свечей, выбираемая параметром CandleType (по умолчанию H4).
Индикатор: настраиваемая скользящая средняя (SMA, EMA, SMMA, LWMA) с параметром MovingAverageShift, полностью повторяющим аргумент shift функции iMA из MetaTrader.
Правила входа:
Лонг: предыдущая свеча открылась ниже и закрылась выше сдвинутой средней, позиция отсутствует.
Шорт: предыдущая свеча открылась выше и закрылась ниже средней, позиция отсутствует.
Правила выхода: исполняются автоматически через StartProtection, куда передаются пересчитанные уровни стоп-лосса и тейк-профита. Даже при нулевых значениях модуль защиты включается, чтобы можно было подключить трейлинг или вручную закрывать сделки.
Фильтр по позиции: новые сигналы игнорируются до полного закрытия текущей позиции.
Параметры
Параметр
Описание
Значение по умолчанию
CandleType
Тип свечей для расчёта сигналов.
H4 (4-часовые свечи)
MovingAveragePeriod
Длина окна скользящей средней.
49
MovingAverageShift
Сдвиг значения скользящей средней вперёд.
0
MovingAverageMethod
Тип средней (Simple, Exponential, Smoothed, LinearWeighted).
Simple
TakeProfitPips
Размер тейк-профита в пунктах, конвертируется в абсолютную цену.
38.5
StopLossPips
Размер стоп-лосса в пунктах, конвертируется в абсолютную цену.
48.5
Управление рисками
Абсолютные уровни рассчитываются из пункта и автоматически прикрепляются к рыночным заявкам. Благодаря этому ограничения по минимальной дистанции до стопов соответствуют требованиям брокера, как и в версии MetaTrader.
Особенности конверсии
Двухэтапная схема выставления ордеров (с последующей модификацией SL/TP) заменена на вызов BuyMarket()/SellMarket() с StartProtection, что упрощает код и достигает той же цели.
Проверки объёма и свободной маржи из функций CheckVolumeValue и CheckMoneyForTrade не переносятся. Рекомендуется использовать встроенные модули риск-менеджмента StockSharp.
Вместо сообщений в лог добавлено рисование свечей, индикатора и сделок в графике стратегии, что облегчает визуальный анализ.
Стратегия демонстрирует, как можно аккуратно перенести MQL-алгоритм на высокоуровневый API StockSharp и получить готовый шаблон для дальнейшего развития.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Basic MA Template strategy: trades when price crosses a moving average.
/// Opens long when previous candle crosses above MA, short when crosses below.
/// </summary>
public class BasicMaTemplateStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _prevOpen;
private decimal? _prevClose;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public BasicMaTemplateStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 49)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOpen = null;
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevOpen = null;
_prevClose = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sma)
{
if (candle.State != CandleStates.Finished) return;
if (_prevOpen.HasValue && _prevClose.HasValue)
{
if (_prevOpen.Value > sma && _prevClose.Value < sma && Position >= 0)
SellMarket();
else if (_prevOpen.Value < sma && _prevClose.Value > sma && Position <= 0)
BuyMarket();
}
_prevOpen = candle.OpenPrice;
_prevClose = candle.ClosePrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class basic_ma_template_strategy(Strategy):
def __init__(self):
super(basic_ma_template_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._ma_period = self.Param("MaPeriod", 49) \
.SetDisplay("MA Period", "Moving average period", "Indicators")
self._prev_open = None
self._prev_close = None
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def ma_period(self):
return self._ma_period.Value
@ma_period.setter
def ma_period(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(basic_ma_template_strategy, self).OnReseted()
self._prev_open = None
self._prev_close = None
def OnStarted2(self, time):
super(basic_ma_template_strategy, self).OnStarted2(time)
self._prev_open = None
self._prev_close = None
sma = SimpleMovingAverage()
sma.Length = self.ma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if self._prev_open is not None and self._prev_close is not None:
if self._prev_open > sma_value and self._prev_close < sma_value and self.Position >= 0:
self.SellMarket()
elif self._prev_open < sma_value and self._prev_close > sma_value and self.Position <= 0:
self.BuyMarket()
self._prev_open = float(candle.OpenPrice)
self._prev_close = float(candle.ClosePrice)
def CreateClone(self):
return basic_ma_template_strategy()