TakeProfitTimeGuardStrategy повторяет логику советника MetaTrader Exp_GTakeProfit_Tm, контролируя прибыль всего счёта и принудительно закрывая позиции вне заданного временного окна. Стратегия не генерирует новые сделки — она служит уровнем риск-менеджмента поверх основной торговой логики и следит за тем, чтобы портфель оставался без позиций после достижения целевой прибыли или по окончании торговой сессии.
Ключевые идеи
Подписывается на поток свечей с настраиваемым таймфреймом (по умолчанию 1 минута) и вычисляет как реализованную, так и плавающую прибыль по цене закрытия последней свечи.
Под плавающей прибылью понимается произведение текущей позиции на разницу между ценой закрытия и средней ценой позиции (Strategy.PositionPrice).
Прибыль ниже нуля игнорируется, пока торговое окно открыто — поведение полностью соответствует оригиналу на MQL5.
Когда целевое значение прибыли достигнуто, стратегия устанавливает внутренний флаг _stop и инициирует серию рыночных ордеров на закрытие текущей позиции до полного обнуления портфеля. Флаг сбрасывается после выхода в ноль.
При активированном временном фильтре стратегия применяет тот же сценарий закрытия при выходе из торгового интервала, даже если целевая прибыль не достигнута.
Параметры
Параметр
Тип
Значение по умолчанию
Описание
CandleType
DataType
1-минутные свечи
Серия свечей, по которой вычисляются условия стратегии.
TargetMode
ProfitTargetModes (Percent / Currency)
Percent
Режим интерпретации TakeProfitValue: процент от капитала или абсолютное значение в валюте счёта.
TakeProfitValue
decimal
100
Целевой уровень прибыли. Должен быть больше нуля.
UseTradingWindow
bool
true
Включает или отключает контроль по времени.
StartTime
TimeSpan
00:00:00
Начало торгового окна (включительно).
EndTime
TimeSpan
23:59:00
Конец торгового окна. Если начало позже конца, окно продолжается через полночь.
Поведение
Начальное значение капитала считывается при запуске (или на первом обновлении, если изначально оно было нулевым) и используется как база для процентной цели.
Для вычисления плавающей прибыли используется цена закрытия последней полученной свечи, поэтому частота свечей напрямую влияет на скорость реакции.
При достижении целевой прибыли стратегия логирует событие и многократно отправляет рыночные заявки на закрытие, пока позиция не станет равной нулю.
Если активирован временной фильтр и текущее время выходит за пределы окна, происходит принудительное закрытие аналогично режиму достижения цели.
Флаг _stop автоматически очищается только после полного закрытия позиции, что предотвращает повторный запуск закрытия до завершения операции.
Отличия от версии MQL
Используется высокоуровневый API StockSharp (SubscribeCandles) вместо обработки каждого тика.
Плавающая прибыль рассчитывается через Strategy.PositionPrice, а не через прямой доступ к позициям терминала.
Добавлены информативные сообщения в журнал о срабатывании целевой прибыли.
Сравнение времени основано на CloseTime полученных свечей.
Рекомендации по использованию
Запускайте стратегию вместе с основной торговой логикой на том же портфеле, чтобы обеспечить дополнительный уровень контроля прибыли.
Подбирайте таймфрейм свечей исходя из требуемой скорости реакции: чем короче свеча, тем быстрее сработает защита.
Убедитесь, что в портфеле доступно значение CurrentValue, иначе процентный режим не сможет корректно определить базу капитала.
При необходимости комбинируйте стратегию с другими инструментами риск-менеджмента StockSharp (например, StartProtection).
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()