Three Timeframes Strategy переносит эксперта MetaTrader Three timeframes.mq5 на платформу StockSharp с использованием высокоуровневого API. Алгоритм объединяет сигналы с трёх таймфреймов:
MACD (M5) — отслеживает краткосрочные развороты импульса на рабочем таймфрейме.
Alligator (H4) — подтверждает направление тренда на старшем таймфрейме.
RSI (H1) — проверяет, поддерживает ли средний таймфрейм движение.
Дополнительный фильтр торговой сессии ограничивает работу стратегии указанными часами.
Каждая сделка сопровождается уровнем стоп-лосса и тейк-профита в пунктах. После появления прибыли опциональный трейлинг подтягивает защитный ордер, когда цена проходит расстояние TrailingStopPips + TrailingStepPips.
Логика сигналов
Стратегия подписывается на три потока свечей: рабочие M5, старшие H4 для Аллигатора и промежуточные H1 для RSI.
Условия покупки:
Линия MACD на предыдущей свече находится ниже сигнальной, а на свече до неё — выше сигнальной, что повторяет правило оригинального эксперта.
Значение RSI на H1 превышает 50.
На последней завершённой H4 свече линии Alligator упорядочены как Jaw > Teeth > Lips.
Продажа зеркальна: MACD пересекает сигнальную линию вверх, RSI ниже 50, а линии Alligator упорядочены как Lips > Teeth > Jaw.
При наличии противоположной позиции стратегия сначала закрывает её встречным рыночным ордером, затем открывает новый вход по направлению сигнала.
После входа выставляются стоп-лосс и тейк-профит. Трейлинг обновляет защитный уровень, когда прибыль превышает сумму дистанции и шага трейлинга.
Фильтр торговых часов полностью повторяет реализацию MetaTrader: если начало меньше конца, то торгуем только внутри диапазона; если начало больше конца, окно работы охватывает вечер и ночные часы, переходя через полночь.
Управление рисками
Стоп-лосс / тейк-профит — задаются в пунктах и переводятся в цену через Security.PriceStep с учётом трёх- и пятизнаковых котировок.
Трейлинг-стоп — активируется после прохождения «дистанция + шаг» и переносит стоп-ордер на цена − дистанция (лонг) или цена + дистанция (шорт).
Объём сделки — определяет базовый размер рыночных заявок. При смене направления позиция закрывается автоматически.
Отличия от версии MetaTrader
Во StockSharp нет необходимости отслеживать флаги ожидания транзакций (m_waiting_transaction): методы BuyMarket и SellMarket сами обрабатывают подтверждения.
Настройки проскальзывания, режима маржи и типа исполнения из MQL скрыты платформой и не дублируются в .NET реализации.
Индикатор Alligator собран из трёх сглаженных скользящих средних и хранит значения в буферах, чтобы сохранить сдвиг линий, характерный для MetaTrader.
Параметры
Имя
Описание
Значение по умолчанию
TradeVolume
Объём рыночной сделки.
1
StopLossPips
Начальная дистанция стоп-лосса (пункты).
50
TakeProfitPips
Начальная дистанция тейк-профита (пункты).
140
TrailingStopPips
Дистанция трейлинг-стопа (пункты).
5
TrailingStepPips
Дополнительный шаг перед обновлением трейлинга.
5
MacdFastPeriod
Быстрый период MACD.
13
MacdSlowPeriod
Медленный период MACD.
26
MacdSignalPeriod
Период сигнальной линии MACD.
10
JawPeriod, TeethPeriod, LipsPeriod
Периоды SMA для линий Аллигатора.
13, 8, 5
JawShift, TeethShift, LipsShift
Сдвиг линий Аллигатора.
8, 5, 3
RsiPeriod
Период RSI на среднем таймфрейме.
14
CandleType
Рабочий таймфрейм (по умолчанию 5 минут).
M5
AlligatorCandleType
Таймфрейм для Аллигатора (по умолчанию 4 часа).
H4
RsiCandleType
Таймфрейм для RSI (по умолчанию 1 час).
H1
UseTimeFilter
Включение фильтра торговых часов.
true
StartHour
Час начала сессии (включительно).
10
EndHour
Час окончания сессии (исключая).
15
Рекомендации по использованию
Убедитесь, что выбранный инструмент предоставляет свечи всех трёх таймфреймов (M5, H1, H4). Метод GetWorkingSecurities() автоматически запрашивает необходимые подписки.
Пересчёт пунктов опирается на Security.PriceStep. Для инструментов с нетипичным шагом цены скорректируйте параметры риска вручную.
Для отключения трейлинга достаточно установить TrailingStopPips или TrailingStepPips в ноль — поведение полностью соответствует оригинальному MQL эксперту.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ThreeTimeframesStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public ThreeTimeframesStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 three_timeframes_strategy(Strategy):
def __init__(self):
super(three_timeframes_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(three_timeframes_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(three_timeframes_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return three_timeframes_strategy()