This strategy replicates the behaviour of the MetaTrader expert Exp_GStopLoss_Tm, providing a risk overlay that monitors the
combined result of all trades opened by the strategy instance. The module does not generate entry signals by itself; instead it
tracks the profit and loss of existing positions and enforces both a global stop loss threshold and an optional trading session
window. When losses exceed the configured limit or the market moves outside the permitted time range, the strategy liquidates the
current exposure and blocks any further trades until the book is flat again.
Trading Logic
On start-up the strategy records the current realised PnL as the baseline reference. This allows it to measure floating profit
relative to the most recent flat state.
Each finished candle produced by the configured candle type triggers a risk check. The default timeframe is one minute to
emulate tick-level surveillance without overwhelming the system.
The module calculates the unrealised profit as the difference between the current strategy PnL and the baseline value. Positive
PnL is ignored while the strategy remains inside the trading window, matching the original expert advisor.
If the loss mode is set to Percent, the strategy compares the absolute loss percentage against the account equity obtained
from Portfolio.CurrentValue. For Currency mode the comparison is made in absolute currency units.
Once the loss threshold is exceeded the stop flag is latched and the strategy begins closing the open position on the next
iteration. The flag is released only after the position size returns to zero and the baseline PnL is refreshed.
When the optional trading window is enabled, the risk check also evaluates whether the candle close time sits inside the allowed
interval. The window supports intraday sessions that wrap around midnight, mirroring the MetaTrader logic.
Any time the stop flag is active or the session filter detects that the market is outside the permitted hours, the module sends a
market order in the opposite direction to flatten the position. Informational log entries describe the reason for each exit.
Parameters
Name
Description
LossMode
Selects how the loss threshold is interpreted: percentage of current account equity or absolute account currency.
StopLoss
Loss threshold value. For percentage mode the number represents percent, while currency mode uses the account currency.
UseTimeFilter
Enables the intraday trading window. When disabled the strategy ignores the time filter entirely.
StartTime
Inclusive start of the trading window in UTC. Works together with EndTime to define the valid session.
EndTime
Exclusive end of the trading window in UTC. Supports wrap-around sessions when the end time is earlier than the start.
CandleType
Candle subscription used to drive the periodic risk evaluation. The default is a 1-minute time frame.
Implementation Notes
The baseline PnL is recalculated whenever the position size returns to zero so that subsequent trades start with a clean slate.
Equity values are pulled from the live portfolio, therefore the percentage mode adapts to both realised and unrealised changes in
account value.
All comments in the source code are written in English as required by the project conventions.
The strategy draws candles and own trades on the default chart area when one is available, helping to visualise the behaviour
during testing.
Usage Guidelines
Attach the strategy to the instrument you want to supervise. Order generation from other strategies can still occur; this
module only monitors and closes positions.
Configure the loss mode and threshold that match your risk appetite. For example, LossMode = Percent and StopLoss = 5 will
close the position after a 5% unrealised drawdown relative to current equity.
Set the StartTime and EndTime parameters to limit trading to a particular intraday session. To cover an overnight window,
specify a start time later than the end time (for example 20:00 to 06:00).
Run the backtest or live session. The strategy will automatically reset the stop flag once all positions are flattened and will
continue to supervise subsequent trades.
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()