TakeProfitTimeGuardStrategy emulates the behaviour of the MetaTrader expert Exp_GTakeProfit_Tm by supervising the account-level profit and forcing a flat position state outside of a configurable trading schedule. The strategy does not open positions on its own. Instead, it serves as a risk-management overlay that automatically closes any existing exposure once the profit objective is achieved or when trading must halt outside the permitted time range.
Core Logic
Subscribes to a configurable candle stream (default 1-minute) to evaluate realised and unrealised PnL using the latest close price.
Calculates total profit as the sum of realised PnL (Strategy.PnL) and the floating PnL derived from the current average position price.
Ignores losses while the trading window is open, mirroring the original expert advisor behaviour.
Once the take-profit target is reached, sets an internal stop flag and repeatedly liquidates any remaining positions until the account is flat. The stop flag resets after the portfolio returns to zero position.
When the optional trading window is enabled, the strategy closes all positions whenever the current time falls outside the allowed range, also waiting until the book is flat before re-enabling trading.
Parameters
Parameter
Type
Default
Description
CandleType
DataType
1-minute time-frame
Candle series used to evaluate profit and schedule logic.
TargetMode
ProfitTargetModes (Percent/Currency)
Percent
Selects whether TakeProfitValue is interpreted as a percentage of account capital or as an absolute currency amount.
TakeProfitValue
decimal
100
Profit target threshold. Interpreted according to TargetMode. Must be greater than zero.
UseTradingWindow
bool
true
Enables or disables the time filter.
StartTime
TimeSpan
00:00:00
Beginning of the allowed trading window (inclusive).
EndTime
TimeSpan
23:59:00
End of the allowed trading window. When the start time is greater than the end time, the window spans midnight.
Behavioural Notes
The initial portfolio value is captured when the strategy starts (or on the first update if the value was zero) and is used as the reference for the percentage target.
The strategy computes floating PnL using the latest candle close price; results depend on the selected candle granularity.
If the profit target is met, the strategy keeps sending market orders to flatten the position until the book is empty. It logs the reason for closing the book.
When UseTradingWindow is enabled and the clock is outside the window, the same flattening routine executes even if the profit target was not reached.
The stop flag (_stop) clears only after the position returns to zero, allowing trading to resume when conditions permit.
Differences from the Original MQL Strategy
Uses StockSharp high-level API (SubscribeCandles) instead of per-tick handlers.
Calculates floating profit from the average position price exposed by Strategy.PositionPrice.
Logs take-profit events for easier monitoring.
Time comparison is based on DateTimeOffset.CloseTime of the subscribed candles.
Usage Tips
Attach the strategy to a portfolio already running another trading strategy to act as a guard layer.
Choose a candle timeframe that matches the responsiveness required for profit evaluation (e.g., 1-minute for rapid control).
Ensure the portfolio information (especially CurrentValue) is available; otherwise, set an explicit starting balance before running percentage targets.
The strategy can be combined with StartProtection() in another primary strategy to add further risk controls.
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>
/// Take Profit Time Guard strategy (simplified). Uses CCI momentum
/// with session time awareness for entries and profit management.
/// </summary>
public class TakeProfitTimeGuardStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciLength;
private readonly StrategyParam<decimal> _upperLevel;
private readonly StrategyParam<decimal> _lowerLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int CciLength
{
get => _cciLength.Value;
set => _cciLength.Value = value;
}
public decimal UpperLevel
{
get => _upperLevel.Value;
set => _upperLevel.Value = value;
}
public decimal LowerLevel
{
get => _lowerLevel.Value;
set => _lowerLevel.Value = value;
}
public TakeProfitTimeGuardStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_cciLength = Param(nameof(CciLength), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Length", "CCI period", "Indicators");
_upperLevel = Param(nameof(UpperLevel), 100m)
.SetDisplay("Upper Level", "CCI level for sell signal", "Logic");
_lowerLevel = Param(nameof(LowerLevel), -100m)
.SetDisplay("Lower Level", "CCI level for buy signal", "Logic");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var cci = new CommodityChannelIndex { Length = CciLength };
decimal prevCci = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, (ICandleMessage candle, decimal cciVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevCci = cciVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevCci = cciVal;
return;
}
// CCI crosses up from below lower level
if (prevCci < LowerLevel && cciVal >= LowerLevel && Position <= 0)
BuyMarket();
// CCI crosses down from above upper level
else if (prevCci > UpperLevel && cciVal <= UpperLevel && Position >= 0)
SellMarket();
prevCci = cciVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var cciArea = CreateChartArea();
if (cciArea != null)
DrawIndicator(cciArea, cci);
}
}
}
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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class take_profit_time_guard_strategy(Strategy):
def __init__(self):
super(take_profit_time_guard_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._cci_length = self.Param("CciLength", 14) \
.SetDisplay("CCI Length", "CCI period", "Indicators")
self._upper_level = self.Param("UpperLevel", 100.0) \
.SetDisplay("Upper Level", "CCI level for sell signal", "Logic")
self._lower_level = self.Param("LowerLevel", -100.0) \
.SetDisplay("Lower Level", "CCI level for buy signal", "Logic")
self._prev_cci = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def CciLength(self):
return self._cci_length.Value
@property
def UpperLevel(self):
return self._upper_level.Value
@property
def LowerLevel(self):
return self._lower_level.Value
def OnReseted(self):
super(take_profit_time_guard_strategy, self).OnReseted()
self._prev_cci = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(take_profit_time_guard_strategy, self).OnStarted2(time)
self._prev_cci = 0.0
self._has_prev = False
cci = CommodityChannelIndex()
cci.Length = self.CciLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(cci, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
cv = float(cci_value)
if not self._has_prev:
self._prev_cci = cv
self._has_prev = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = cv
return
if self._prev_cci < self.LowerLevel and cv >= self.LowerLevel and self.Position <= 0:
self.BuyMarket()
elif self._prev_cci > self.UpperLevel and cv <= self.UpperLevel and self.Position >= 0:
self.SellMarket()
self._prev_cci = cv
def CreateClone(self):
return take_profit_time_guard_strategy()