L3H3 Pivot Strategy — это перенос советника MetaTrader "L3_H3_Expert" на платформу StockSharp. Изначальный код рассчитывает дневные уровни пивота и размещает две отложенные заявки возле границ диапазона предыдущей сессии, чтобы отработать пробой или откат. Версия на StockSharp сохраняет ту же концепцию: после закрытия каждой свечи повышенного таймфрейма (по умолчанию — дневной) заново вычисляются уровни пивота, а затем стратегия решает, ставить ли стоп или лимит заявку в зависимости от текущего положения цены относительно вчерашнего диапазона.
Торговая логика
Статистика сессии
После закрытия свечи PivotCandleType фиксируются цены открытия, максимума, минимума и закрытия предыдущего периода.
Пивот рассчитывается по формуле (High + Low + Close) / 3 и действует в течение следующей торговой сессии.
Подготовка входа
Цена покупки задаётся чуть выше вчерашнего минимума. Сдвиг равен параметру EntryOffsetPips, выраженному в размерах тика.
Цена продажи совпадает со вчерашним максимумом — как и в оригинальном советнике, дополнительный буфер не используется.
При наступлении нового торгового дня (согласно основной серии свечей EntryCandleType) выставляются свежие отложенные заявки:
Если текущая цена ниже вчерашнего минимума, ставится buy-stop для торговли пробоя вверх.
Если текущая цена выше вчерашнего максимума, ставится sell-stop для игры на разворот вниз.
В остальных случаях выбираются лимитные заявки на тех же уровнях, чтобы купить на откате или продать на росте.
Стоп-лосс отстоит от базового минимума/максимума на StopLossPips, повторяя фиксированное смещение 16 пунктов из MT4.
Тейк-профит обеих заявок выставляется на уровне пивота.
Управление заявками
При каждом пересчёте пивота существующие отложенные заявки отменяются и пересоздаются с новыми параметрами.
При переходе к новой сессии также выполняется отмена устаревших заявок, чтобы не накапливать лишние ордера.
После исполнения заявки соответствующая ссылка очищается, что предотвращает повторные попытки отмены.
Параметры
Имя
Описание
Значение по умолчанию
EntryCandleType
Серия свечей, по которой отслеживается текущая сессия и запускается размещение заявок.
5-минутные свечи
PivotCandleType
Свечи повышенного таймфрейма для расчёта статистики предыдущей сессии.
Дневные свечи
EntryOffsetPips
Смещение точки входа в покупку относительно вчерашнего минимума (в пунктах).
2
StopLossPips
Расстояние стоп-лосса от контрольного минимума/максимума (в пунктах).
16
Отличия от версии MT4
Советник MT4 переключался между азиатской, лондонской и нью-йоркской сессиями через magic number и набор временных окон. StockSharp-реализация упрощает схему, используя настраиваемый таймфрейм для расчёта пивота (по умолчанию — дневной), что облегчает адаптацию под разных брокеров.
В MetaTrader решение о типе отложенной заявки принималось по текущим котировкам Bid/Ask. В портированной версии используется последняя завершённая свеча серии EntryCandleType, что делает логику событийно-ориентированной и повторяемой.
Комментарии к ордерам и magic number были специфичны для MT4, поэтому в StockSharp они не применяются: стратегия хранит прямые ссылки на свои ордера и управляет ими программно.
Рекомендации по применению
Проверьте, что у инструмента задан корректный PriceStep. При его отсутствии стратегия завершит запуск с исключением.
Для точного воспроизведения оригинальных торговых окон можно настроить PivotCandleType на часовые свечи и агрегировать их в нужные временные диапазоны, а также скорректировать параметры смещения и стоп-лосса.
При работе на реальном счёте учитывайте требования брокера к минимальному расстоянию и сроку действия отложенных заявок.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// L3/H3 Pivot strategy - trades around Highest/Lowest channel midpoint.
/// Buys when close crosses above the midpoint, sells when below.
/// Uses a longer lookback to simulate daily pivot levels.
/// </summary>
public class L3H3PivotStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public L3H3PivotStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 48)
.SetDisplay("Channel Period", "Lookback for pivot channel", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0m;
_prevMid = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var mid = (high + low) / 2m;
if (!_hasPrev)
{
_prevClose = close;
_prevMid = mid;
_hasPrev = true;
return;
}
// Cross above midpoint
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Cross below midpoint
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevMid = mid;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class l3_h3_pivot_strategy(Strategy):
"""L3/H3 Pivot strategy - trades around Highest/Lowest channel midpoint.
Buys when close crosses above the midpoint, sells when below.
Uses a longer lookback to simulate daily pivot levels."""
def __init__(self):
super(l3_h3_pivot_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 48) \
.SetDisplay("Channel Period", "Lookback for pivot channel", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def ChannelPeriod(self):
return self._channel_period.Value
def OnReseted(self):
super(l3_h3_pivot_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(l3_h3_pivot_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.ChannelPeriod
lowest = Lowest()
lowest.Length = self.ChannelPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, high, low):
if candle.State != CandleStates.Finished:
return
high_val = float(high)
low_val = float(low)
close = float(candle.ClosePrice)
mid = (high_val + low_val) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
# Cross above midpoint
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Cross below midpoint
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return l3_h3_pivot_strategy()