Стратегия повторяет оригинального советника MQL, основанного на пересечении скользящих средних. Она использует высокоуровневый API StockSharp, чтобы контролировать две простые скользящие средние на выбранной серии свечей. Сигналы появляются при пересечении быстрой средней и медленной, а при необходимости активная позиция может быть закрыта при появлении противоположного сигнала.
Логика торговли
Подписка на заданный тип свечей и расчёт значений быстрой и медленной SMA на каждой завершённой свече.
Бычий сигнал фиксируется, когда быстрая SMA переходит из области ниже медленной в область выше. При отсутствии позиции открывается покупка выбранным объёмом.
Медвежий сигнал возникает, когда быстрая SMA переходит из области выше медленной в область ниже. При отсутствии позиции открывается продажа выбранным объёмом.
Если опция «Закрывать по противоположному сигналу» активна, текущая позиция закрывается сразу после появления обратного пересечения.
Управление рисками
Для каждой позиции рассчитывается фиксированный стоп-лосс и тейк-профит в пунктах инструмента.
После достижения заданной прибыли стоп переносится в зону безубыточности с дополнительным запасом прибыли.
Когда прибыль достигает заданного порога, включается трейлинг-стоп, который сопровождает цену и никогда не сдвигается в сторону убытка.
Параметры
Fast MA Period – период быстрой SMA.
Slow MA Period – период медленной SMA.
Trade Volume – торговый объём (лоты).
Stop Loss (points) – размер стоп-лосса в пунктах.
Take Profit (points) – размер тейк-профита в пунктах.
Break-even Trigger – прибыль в пунктах, необходимая для перевода стопа в безубыток.
Break-even Offset – дополнительный запас прибыли при переносе стопа в безубыток.
Trailing Start – прибыль, при которой активируется трейлинг-стоп.
Trailing Distance – расстояние между ценой и трейлинг-стопом.
Close On Opposite – закрытие позиции при появлении обратного сигнала.
Candle Type – тип свечей, по которым выполняются расчёты.
Рекомендации по использованию
Проверьте наличие корректного PriceStep у инструмента. При его отсутствии стратегия использует значение 1.
Перенос стопа в безубыток и трейлинг выполняются по закрытию свечей, что соответствует логике исходного советника.
Для разных инструментов и таймфреймов рекомендуется оптимизировать периоды средних и параметры управления риском.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Moving Averages Crossover strategy: EMA crossover.
/// Buys when fast EMA crosses above slow EMA. Sells on cross below.
/// </summary>
public class MovingAveragesCrossoverStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 MovingAveragesCrossoverStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, fastVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
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 moving_averages_crossover_strategy(Strategy):
def __init__(self):
super(moving_averages_crossover_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(moving_averages_crossover_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(moving_averages_crossover_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._prev_fast is not None and self._prev_slow is not None:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return moving_averages_crossover_strategy()