Стратегия Tokyo Session переносит логику советника MetaTrader TokyoSessionEA_v2.8 в экосистему StockSharp. Она
предназначена для внутридневной торговли вокруг азиатской (Токийской) сессии и строит торговый канал по опорной свече в
указанный час. После формирования канала стратегия проверяет условия пробоя или возврата в другом часе и в зависимости от
режима (ContraryTrend или AccordingTrend) открывает позицию против всплеска цены или по направлению пробоя.
В портированной версии используются только высокоуровневые возможности StockSharp. Сигналы рассчитываются внутри
подписки на свечи, стопы и трейлинг управляются через StartProtection, а все действия сопровождаются сообщениями
LogInfo, что упрощает анализ как в тестере, так и на реальном рынке.
Логика работы
Опорная свеча. В момент TimeSetLevels (час брокера) фиксируются максимум, минимум и цена закрытия свечи.
Полученный диапазон служит каналом для последующих проверок, а внутренние флаги валидности сбрасываются.
Проверка канала. Каждая завершённая свеча между часами TimeSetLevels и TimeCheckLevels может отменить сигнал:
CheckAllBars требует, чтобы закрытие свечей оставалось внутри канала.
ReCheckPrices в момент TimeRecheckPrices сравнивает закрытие со скользящей средней по закрытиям, контролируя
импульс.
Условия входа. Когда закрывается свеча, предшествующая часу TimeCheckLevels, её цена закрытия сравнивается с
границами канала. Если цена попадает в диапазон [MinDistanceOfLevel, MaxDistanceOfLevel], открывается позиция.
Выходы. Сделка может быть закрыта тремя механизмами:
CloseInSignal закрывает позицию при возврате цены в канал (аналогично оригинальному советнику).
CloseOrdersOnTime принудительно фиксирует результат в час TimeCloseOrders, исключая перенос позиций.
Защитные стопы, трейлинг и перевод в безубыток выполняет подсистема StartProtection.
Параметры
Общие
Параметр
Описание
CandleType
Тип свечей для расчётов (по умолчанию H1).
BrokerOffset
Смещение времени брокера относительно GMT в часах.
Сигналы
Параметр
Описание
TypeOfSignals
ContraryTrend — контртрендовая торговля, AccordingTrend — по направлению пробоя.
TimeSetLevels
Час фиксации опорной свечи.
TimeCheckLevels
Час проверки условий входа.
TimeRecheckPrices
Час дополнительной проверки импульса.
MinDistanceOfLevel
Минимальное расстояние от уровня (в пунктах), допускающее вход.
MaxDistanceOfLevel
Максимальное расстояние от уровня (в пунктах). Значение 0 отключает ограничение.
ReCheckPrices
Включает дополнительную проверку импульса.
CheckAllBars
Требует, чтобы все промежуточные свечи оставались внутри канала.
Управление рисками
Параметр
Описание
CloseInSignal
Закрыть позицию при пересечении обратного сигнала.
CloseOrdersOnTime
Закрыть позиции по времени.
TimeCloseOrders
Час закрытия по времени.
UseTakeProfit, TakeProfit
Фиксированный тейк-профит в пунктах.
UseStopLoss, StopLoss
Фиксированный стоп-лосс в пунктах.
UseTrailingStop, TrailingStop, TrailingStep
Настройки трейлинг-стопа StockSharp (в пунктах).
UseBreakEven, BreakEven, BreakEvenAfter
Перевод стопа в безубыток после достижения заданной прибыли.
Торговля
Параметр
Описание
Volume
Базовый объём ордера. При смене направления противоположная позиция закрывается автоматически.
MaxOrders
Максимальное количество объёмов Volume в одну сторону. Значение 0 снимает ограничение.
Порядок использования
Выберите инструмент с корректным шагом цены (Security.PriceStep).
Настройте таймфрейм и смещение времени, чтобы синхронизировать расписание с торговой сессией.
Подберите дистанции и фильтры в соответствии с требованиями рынка или параметрами оригинального советника.
Задайте параметры управления риском. Защитные ордера обслуживает StartProtection.
Запустите стратегию и отслеживайте сообщения LogInfo, фиксирующие захват уровней и сделки.
Отличия от версии MetaTrader
Не реализован режим «плавающего» входа (UseFloatingPoint и PipsFloatingPoint), так как в StockSharp сигналы
исполняются немедленно рыночными ордерами.
Фильтр по спреду и проскальзыванию опущен: высокоуровневые подписки на свечи не содержат поток котировок Bid/Ask.
Автоматическое управление объёмом (AutoLotSize, RiskFactor, восстановление лота и пресеты по инструментам)
заменено на параметры Volume и MaxOrders. Размер позиции следует задавать напрямую в настройках стратегии.
Звуковые и текстовые уведомления заменены на стандартные логи LogInfo.
Все остальные проверки уровней, условия входа и алгоритмы выхода соответствуют оригинальному алгоритму.
Дополнительные замечания
Конфигурация по умолчанию рассчитана на таймфрейм H1. Для других таймфреймов важно, чтобы их длительность делила час
без остатка.
Отсутствие свечей или разрывы в данных могут нарушить расчёт среднего значения и привести к отмене сигнала.
Стратегия закрывает позиции рыночными ордерами; если брокер требует лимитных заявок или накладывает ограничения по
времени удержания, может потребоваться дополнительная адаптация.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Tokyo Session strategy: breakout from session range.
/// Tracks high/low during first hours, then buys breakout above high, sells below low.
/// </summary>
public class TokyoSessionStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
public TokyoSessionStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for volatility filter", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var atr = new AverageTrueRange { Length = AtrPeriod };
var sessionHigh = decimal.MinValue;
var sessionLow = decimal.MaxValue;
var candleCount = 0;
var rangeSet = false;
decimal? prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, (candle, atrVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
candleCount++;
// Build range from first 4 candles (2 hours of 30min candles)
if (candleCount <= 4)
{
if (candle.HighPrice > sessionHigh)
sessionHigh = candle.HighPrice;
if (candle.LowPrice < sessionLow)
sessionLow = candle.LowPrice;
if (candleCount == 4)
rangeSet = true;
prevClose = candle.ClosePrice;
return;
}
if (!rangeSet)
{
prevClose = candle.ClosePrice;
return;
}
// Reset range every 48 candles (24 hours of 30min candles)
if (candleCount % 48 == 0)
{
sessionHigh = candle.HighPrice;
sessionLow = candle.LowPrice;
rangeSet = false;
candleCount = 0;
prevClose = candle.ClosePrice;
return;
}
var close = candle.ClosePrice;
if (prevClose.HasValue)
{
var crossAboveHigh = prevClose.Value <= sessionHigh && close > sessionHigh;
var crossBelowLow = prevClose.Value >= sessionLow && close < sessionLow;
if (crossAboveHigh && Position <= 0)
BuyMarket();
else if (crossBelowLow && Position >= 0)
SellMarket();
}
prevClose = close;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
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 AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class tokyo_session_strategy(Strategy):
def __init__(self):
super(tokyo_session_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for volatility filter", "Indicators")
self._atr = None
self._session_high = None
self._session_low = None
self._candle_count = 0
self._range_set = False
self._prev_close = None
@property
def atr_period(self):
return self._atr_period.Value
def OnReseted(self):
super(tokyo_session_strategy, self).OnReseted()
self._atr = None
self._session_high = None
self._session_low = None
self._candle_count = 0
self._range_set = False
self._prev_close = None
def OnStarted2(self, time):
super(tokyo_session_strategy, self).OnStarted2(time)
self._atr = AverageTrueRange()
self._atr.Length = self.atr_period
self._session_high = -999999999.0
self._session_low = 999999999.0
self._candle_count = 0
self._range_set = False
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._atr, self._process_candle)
subscription.Start()
def _process_candle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
if not self._atr.IsFormed:
return
self._candle_count += 1
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
if self._candle_count <= 4:
if high > self._session_high:
self._session_high = high
if low < self._session_low:
self._session_low = low
if self._candle_count == 4:
self._range_set = True
self._prev_close = close
return
if not self._range_set:
self._prev_close = close
return
if self._candle_count % 48 == 0:
self._session_high = high
self._session_low = low
self._range_set = False
self._candle_count = 0
self._prev_close = close
return
if self._prev_close is not None:
cross_above = self._prev_close <= self._session_high and close > self._session_high
cross_below = self._prev_close >= self._session_low and close < self._session_low
if cross_above and self.Position <= 0:
self.BuyMarket()
elif cross_below and self.Position >= 0:
self.SellMarket()
self._prev_close = close
def CreateClone(self):
return tokyo_session_strategy()