Стратегия Simple Multiple Time Frame Moving Average
Эта стратегия является адаптацией simple_multiple_time_frame_moving_average.mq4. Логика основана на согласовании направлений простых скользящих средних на двух таймфреймах.
Логика стратегии
Вычисляет SMA с периодом Length для свечей 1H и 4H.
Покупает, когда обе SMA растут.
Продаёт, когда обе SMA падают.
Закрывает длинную позицию, если любая SMA начинает снижаться.
Закрывает короткую позицию, если любая SMA начинает расти.
Одновременно активна только одна позиция.
Параметры
MA Length (Length) — период скользящих средних.
Short Time Frame (ShortCandleType) — таймфрейм короткой SMA (по умолчанию 1H).
Long Time Frame (LongCandleType) — таймфрейм длинной SMA (по умолчанию 4H).
Объём заявок берётся из свойства Volume стратегии.
Примечания
Реализация сосредоточена на часовом и четырёхчасовом таймфреймах, используемых в оригинальной версии MQL, и не включает расчёты для более высоких таймфреймов.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy using fast and slow SMA slopes for trade direction.
/// Buys when both SMAs are rising, sells when both are falling.
/// </summary>
public class SimpleMultipleTimeFrameMovingAverageStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SimpleMultipleTimeFrameMovingAverageStrategy()
{
_fastLength = Param(nameof(FastLength), 5)
.SetDisplay("Fast MA", "Fast moving average period", "General");
_slowLength = Param(nameof(SlowLength), 20)
.SetDisplay("Slow MA", "Slow moving average period", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = _prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastSma = new ExponentialMovingAverage { Length = FastLength };
var slowSma = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastSma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast is decimal pf && _prevSlow is decimal ps)
{
var fastUp = fast > pf;
var fastDown = fast < pf;
var slowUp = slow > ps;
var slowDown = slow < ps;
if (fastUp && slowUp && Position <= 0)
BuyMarket();
else if (fastDown && slowDown && Position >= 0)
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
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 simple_multiple_time_frame_moving_average_strategy(Strategy):
def __init__(self):
super(simple_multiple_time_frame_moving_average_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 5) \
.SetDisplay("Fast MA", "Fast moving average period", "General")
self._slow_length = self.Param("SlowLength", 20) \
.SetDisplay("Slow MA", "Slow moving average period", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candles", "General")
self._prev_fast = None
self._prev_slow = None
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(simple_multiple_time_frame_moving_average_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(simple_multiple_time_frame_moving_average_strategy, self).OnStarted2(time)
fast_sma = ExponentialMovingAverage()
fast_sma.Length = self.fast_length
slow_sma = ExponentialMovingAverage()
slow_sma.Length = self.slow_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_sma, slow_sma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_sma)
self.DrawIndicator(area, slow_sma)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
f = float(fast)
s = float(slow)
if self._prev_fast is not None and self._prev_slow is not None:
fast_up = f > self._prev_fast
fast_down = f < self._prev_fast
slow_up = s > self._prev_slow
slow_down = s < self._prev_slow
if fast_up and slow_up and self.Position <= 0:
self.BuyMarket()
elif fast_down and slow_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = f
self._prev_slow = s
def CreateClone(self):
return simple_multiple_time_frame_moving_average_strategy()