DailyTargetStrategy — порт советника MetaTrader 4 «Daily Target». Стратегия отслеживает совокупный результат за текущий
календарный день и прекращает торговлю, когда плавающая + реализованная прибыль достигают заданной цели либо уходит ниже
максимально допустимого убытка. После срабатывания одного из порогов все активные заявки снимаются, а позиция закрывается рыночной
заявкой. Торговля возобновится только после наступления следующего дня.
Логика работы
Запуск
В методе OnStarted вызывается ResetDailySnapshot, который запоминает дату и базовое значение реализованного PnL.
SubscribeLevel1() обеспечивает поток котировок Bid/Ask, необходимый для точного расчёта плавающей прибыли.
SubscribeTrades() сохраняет цену последней сделки, чтобы иметь резервный источник цены при отсутствии котировок.
Таймер с периодом одна минута позволяет заметить смену даты даже в периоды без рыночных событий.
Оценка PnL
EvaluateDailyThresholds пересчитывает реализованный PnL (текущий PnL минус сохранённая база) и добавляет плавающий PnL,
вычисленный из последних Bid/Ask или цены сделки.
При достижении целевой прибыли либо просадке ниже отрицательного порога вызывается TriggerDailyStop.
Аварийный выход
TriggerDailyStop пишет информационное сообщение в лог, отменяет все отложенные заявки и отправляет рыночный ордер на
закрытие оставшейся позиции.
Флаг _dailyStopTriggered блокирует повторный вход в тот же день. После смены даты ResetDailySnapshot очищает флаг и
пересчитывает базовый PnL.
Параметры
Имя
Значение по умолчанию
Описание
DailyTarget
10
Целевая прибыль в валюте счёта. Достигнув её, стратегия прекращает торговать до конца дня.
DailyMaxLoss
0
Допустимый дневной убыток в валюте счёта. Значение 0 отключает фильтр. При достижении порога стратегия останавливает торговлю до следующего дня.
Примечания
Стратегия управляет только основным инструментом Security, что соответствует односимвольной логике оригинального советника.
Плавающий PnL считается по Bid для длинных и по Ask для коротких позиций. Если котировки отсутствуют, используется последняя
цена сделки.
Версия на Python не предоставляется, пакет содержит только C#-реализацию на высокоуровневом API.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Daily Target strategy: TEMA crossover.
/// Buys when fast TEMA crosses above slow TEMA, sells on cross below.
/// </summary>
public class DailyTargetStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DailyTargetStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast TEMA", "Fast TEMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow TEMA", "Slow TEMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
}
}