Стратегия переносит советник TimerEA из MetaTrader на StockSharp. Основная задача — открыть и закрыть позицию в заранее
заданные даты/время, при необходимости используя отложенные ордера, трейлинг и переход в безубыток.
Логика торговли
Расписание
OpenTime активирует постановку ордера, когда завершённая свеча достигает заданной минуты.
CloseTime принудительно закрывает позицию и при необходимости отменяет активные отложенные заявки.
Типы ордеров
Можно выбрать рыночный вход, стоп или лимит. Для отложенных заявок задаётся расстояние в шагах цены и время истечения.
Направления
Отдельные флаги включают покупки и продажи. За один запуск стратегия отправляет по одной заявке каждого разрешённого типа.
Управление риском
Реализованы фиксированный объём и режим «баланс × RiskFactor», повторяющий расчёт лота оригинала.
Стоп-лосс и тейк-профит задаются в шагах цены и пересчитываются при каждом входе.
Трейлинг-стоп поддерживает фиксированный отступ от цены, когда прибыль превышает буфер BreakEvenSteps; сдвиг стопа
происходит только после прохождения дополнительного TrailingStep.
Защита позиций
Порог безубытка запрещает трейлинг, пока прибыль меньше требуемого значения.
Отложенные заявки автоматически снимаются по истечении срока действия.
Параметры по умолчанию
Режим ордеров: Market.
Покупки и продажи: отключены.
Тейк-профит / стоп-лосс: по 10 шагов.
Трейлинг и безубыток: отключены.
Расстояние для отложенных заявок: 10 шагов, истечение — 60 минут.
Размер позиции: Manual volume = 1.0 (RiskFactor = 1.0 в режиме баланса).
Таймфрейм свечей: 1 минута.
Особенности
Обработка идёт только по завершённым свечам, поэтому задержка может достигать одной свечи.
В StockSharp используется неттинговый учёт, одновременные длинная и короткая позиции невозможны даже при включённых обоих
направлениях.
Расстояния рассчитываются через Security.PriceStep. Если шаг цены не задан, значения воспринимаются как абсолютные цены.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Timer EA strategy: SMA crossover with time-of-day filter.
/// Trades only during active session hours.
/// </summary>
public class TimerEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 TimerEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { Length = SlowPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, fastVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
if (prevFast.Value <= prevSlow.Value && fastVal > slowVal && Position <= 0)
BuyMarket();
else if (prevFast.Value >= prevSlow.Value && fastVal < slowVal && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class timer_ea_strategy(Strategy):
def __init__(self):
super(timer_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast Period", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow Period", "Slow SMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(timer_ea_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(timer_ea_strategy, self).OnStarted2(time)
self._fast_ind = SimpleMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = SimpleMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._prev_fast is not None and self._prev_slow is not None:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return timer_ea_strategy()