Стратегия переносит логику эксперта MQL/34176/MACross.mq4 на высокоуровневый API StockSharp. Она торгует один инструмент по пересечению скользящих средних и сохраняет все защитные механизмы, выраженные в пунктах и капитале счёта.
Торговая логика
На выбранном типе свечей строятся две простые скользящие средние (SMA):
FastPeriod — быстрый фильтр, мгновенно реагирующий на цену.
После закрытия каждой свечи сравниваются значения SMA:
Пересечение вверх (быстрая выше медленной) открывает длинную позицию. При наличии шорта он закрывается перед новым входом.
Пересечение вниз (быстрая ниже медленной) открывает короткую позицию после закрытия лонга.
Любой вход выполняется рыночным объёмом LotSize, который дополнительно подгоняется под биржевые ограничения (VolumeStep, MinVolume, MaxVolume).
После открытия позиции стратегия отслеживает два уровня управления риском, заданных в пунктах. Размер пункта определяется по Security.Decimals (или PriceStep, если количество знаков неизвестно):
TakeProfitPips — дистанция до цели по прибыли. Достижение уровня приводит к рыночному выходу.
StopLossPips — расстояние защитного стопа. Его пробой немедленно закрывает позицию.
Порог MinEquity позволяет приостановить появление новых сделок. Если текущая стоимость портфеля падает ниже заданного уровня, стратегия продолжает сопровождать открытую позицию, но не инициирует новые входы.
Вся логика работает только на закрытых свечах, что полностью соответствует оригинальному эксперту, проверявшему условия после формирования нового бара.
Визуализация
При наличии панели графика отображаются:
Свечи выбранного таймфрейма.
Быстрая и медленная SMA.
Собственные сделки стратегии, показывающие точки входа и выхода.
Параметры
Название
Тип
Значение по умолчанию
Описание
FastPeriod
int
8
Длина быстрой SMA, определяющей сигналы на вход.
SlowPeriod
int
20
Длина медленной SMA, задающей направление тренда.
TakeProfitPips
decimal
20
Дистанция до цели по прибыли в пунктах. Размер пункта вычисляется автоматически.
StopLossPips
decimal
20
Расстояние защитного стопа в пунктах. Использует ту же формулу пункта, что и тейк-профит.
LotSize
decimal
1
Базовый объём заявки. Перед отправкой округляется к допустимому значению.
MinEquity
decimal
100
Минимальный капитал счёта. При падении ниже порога новые входы блокируются.
CandleType
DataType
TimeSpan.FromMinutes(1).TimeFrame()
Свечной ряд, по которому считаются SMA и принимаются решения.
Отличия от версии MQL
В MQL-реализации стоп и тейк передавались в OrderSend равными нулю. В StockSharp-версии выходы выполняются вручную при достижении ценовых уровней на закрытии свечей.
Проверка капитала (cekMinEquity) теперь использует Portfolio.CurrentValue и Portfolio.BeginValue вместо AccountEquity(), сохраняя ту же логику порога.
Определение размера пункта повторяет функцию GetPipPoint: для двух- и трёхзнаковых котировок берётся 0.01, для четырёх- и пятизнаковых — 0.0001, иначе используется PriceStep.
Стратегия готова к оптимизации по всем параметрам и интегрируется с механизмами визуализации и риск-менеджмента StockSharp.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MA Cross strategy: SMA crossover.
/// Buys when fast SMA crosses above slow SMA, sells on cross below.
/// </summary>
public class MacrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
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 MacrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_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 fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_cross_strategy(Strategy):
"""
MA Cross strategy: EMA crossover.
Buys when fast crosses above slow, sells on cross below.
"""
def __init__(self):
super(ma_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60))).SetDisplay("Candle Type", "Timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ma_cross_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
f = float(fast_val)
s = float(slow_val)
if self._has_prev:
if self._prev_fast <= self._prev_slow and f > s and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and self.Position >= 0:
self.SellMarket()
else:
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = f
self._prev_slow = s
self._has_prev = True
return
if f > s and self.Position <= 0:
self.BuyMarket()
elif f < s and self.Position >= 0:
self.SellMarket()
self._prev_fast = f
self._prev_slow = s
self._has_prev = True
def CreateClone(self):
return ma_cross_strategy()