Стратегия повторяет логику MetaTrader-советника Exp_GStopLoss_Tm и служит защитным слоем над любыми торговыми системами. Она не
создаёт собственных сигналов входа, а лишь отслеживает суммарный результат открытых позиций. При превышении заданного уровня
просадки или при выходе рынка за пределы разрешённого торгового окна стратегия закрывает позиции и блокирует дальнейшую торговлю
до полного обнуления позиции.
Логика работы
При запуске фиксируется текущий реализованный PnL, который используется как базовая отметка для расчёта плавающей прибыли.
Каждая сформированная свеча выбранного таймфрейма инициирует проверку риска. По умолчанию используется минутный интервал, что
позволяет максимально оперативно отслеживать состояние позиций.
Фактический убыток определяется как разница между текущим PnL стратегии и базовым значением. Положительная прибыль игнорируется,
пока время находится внутри разрешённого окна.
В режиме Percent модуль сравнивает относительную просадку с текущей стоимостью портфеля (Portfolio.CurrentValue). В режиме
Currency сравнение ведётся в абсолютных денежных единицах счёта.
После превышения порога стоп-лосса активируется флаг остановки. На следующей итерации стратегия отправляет рыночный ордер навстречу
существующей позиции. Флаг сбрасывается только после полного закрытия позиций и обновления базового PnL.
При включённом временном фильтре дополнительно проверяется, входит ли время закрытия свечи в заданный интервал. Окно может
пересекать полночь, как и в оригинальном скрипте.
Когда стоп-flag активен или время выходит за пределы окна, модуль мгновенно закрывает позицию и фиксирует причину в журнале.
Параметры
Параметр
Описание
LossMode
Режим расчёта стоп-лосса: процент от текущей стоимости портфеля или абсолютная сумма.
StopLoss
Значение глобального стоп-лосса. В процентном режиме указывается величина в процентах, в денежном — сумма в валюте счёта.
UseTimeFilter
Включает ограничение по торговому времени. При выключении временной фильтр не используется.
StartTime
Начало торгового окна (UTC), задаётся вместе с EndTime.
EndTime
Конец торгового окна (UTC, не включая конечную точку). Если конец раньше начала, окно считается ночным.
CandleType
Тип свечей, по которым выполняются проверки. По умолчанию — 1 минута.
Особенности реализации
Базовый PnL пересчитывается каждый раз после обнуления позиции, чтобы последующие сделки оценивались от нуля.
В процентном режиме используется текущее значение портфеля, поэтому учитываются как реализованные, так и плавающие изменения.
Все комментарии в коде написаны на английском языке, что соответствует требованиям репозитория.
При наличии графика стратегия выводит свечи и собственные сделки, что облегчает анализ результатов.
Рекомендации по использованию
Запустите стратегию на инструменте, который требуется контролировать. Другие торговые алгоритмы могут продолжать открывать сделки —
данный модуль лишь управляет риском и закрывает позиции при необходимости.
Настройте режим и величину стоп-лосса в соответствии с допустимым риском. Например, LossMode = Percent и StopLoss = 5
приведут к закрытию позиции после 5% плавающей просадки.
Установите параметры StartTime и EndTime, чтобы ограничить торговлю нужным интервалом. Для ночных сессий задайте начало позже
конца, например 20:00–06:00.
Выполните тестирование или запустите стратегию в реальном времени. После закрытия всех позиций защита автоматически сбрасывается и
продолжает контролировать следующие сделки.
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;
/// <summary>
/// Global Stop Loss Time strategy (simplified). Trades EMA crossover with
/// session time filter and global stop loss based on drawdown.
/// </summary>
public class GlobalStopLossTimeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaFastLength;
private readonly StrategyParam<int> _emaSlowLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaFastLength
{
get => _emaFastLength.Value;
set => _emaFastLength.Value = value;
}
public int EmaSlowLength
{
get => _emaSlowLength.Value;
set => _emaSlowLength.Value = value;
}
public GlobalStopLossTimeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_emaFastLength = Param(nameof(EmaFastLength), 8)
.SetGreaterThanZero()
.SetDisplay("EMA Fast", "Fast EMA period", "Indicators");
_emaSlowLength = Param(nameof(EmaSlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("EMA Slow", "Slow EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaFast = new ExponentialMovingAverage { Length = EmaFastLength };
var emaSlow = new ExponentialMovingAverage { Length = EmaSlowLength };
decimal prevFast = 0, prevSlow = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastVal;
prevSlow = slowVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastVal;
prevSlow = slowVal;
return;
}
// EMA crossover signals
if (prevFast <= prevSlow && fastVal > slowVal && Position <= 0)
BuyMarket();
else if (prevFast >= prevSlow && fastVal < slowVal && Position >= 0)
SellMarket();
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
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 global_stop_loss_time_strategy(Strategy):
def __init__(self):
super(global_stop_loss_time_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._ema_fast_length = self.Param("EmaFastLength", 8) \
.SetDisplay("EMA Fast", "Fast EMA period", "Indicators")
self._ema_slow_length = self.Param("EmaSlowLength", 21) \
.SetDisplay("EMA Slow", "Slow EMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaFastLength(self):
return self._ema_fast_length.Value
@property
def EmaSlowLength(self):
return self._ema_slow_length.Value
def OnReseted(self):
super(global_stop_loss_time_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(global_stop_loss_time_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
ema_fast = ExponentialMovingAverage()
ema_fast.Length = self.EmaFastLength
ema_slow = ExponentialMovingAverage()
ema_slow.Length = self.EmaSlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema_fast, ema_slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema_fast)
self.DrawIndicator(area, ema_slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return global_stop_loss_time_strategy()