Главная
/
Примеры стратегий
Открыть на GitHub
Стратегия Timer
Стратегия Timer пересчитывает уровни пробоя через заданные интервалы времени и открывает позиции при пересечении ценой этих динамических уровней. Уровни формируются на основе индикатора ATR и дополнительного смещения в пунктах, что позволяет реагировать на краткосрочные импульсы в любую сторону.
Каждые WaitSeconds стратегия устанавливает:
Уровень покупки на close + pipDistance + ATR.
Уровень продажи на close - pipDistance - ATR.
Если следующая завершённая свеча закрывается за пределами одного из уровней, размещается рыночный ордер в соответствующем направлении. Позиция защищается стоп-лоссом, тейк-профитом и трейлинг-стопом.
При необходимости торговля может ограничиваться определённым временным окном.
Параметры
WaitSeconds – интервал в секундах между пересчётом уровней.
PipDistance – дополнительное смещение от текущей цены в пунктах.
AtrPeriod – период индикатора ATR.
TakeProfit – расстояние до тейк-профита в пунктах.
StopLoss – расстояние до стоп-лосса в пунктах.
TrailingStop – расстояние трейлинг-стопа в пунктах.
TradeVolume – объём ордера.
CandleType – тип свечей для расчётов.
UseTradingHours – включение фильтра торгового времени.
StartTime – начало торгового окна.
StopTime – конец торгового окна.
Логика работы
Подписка на свечи и расчёт ATR.
Для каждой завершённой свечи:
При истечении заданного интервала пересчитываются уровни.
При включённом фильтре проверяется попадание во временной диапазон.
При пересечении ценой соответствующего уровня отправляется рыночный ордер.
Защитные ордера управляются инфраструктурой стратегии автоматически.
Особенности
Торговля ведётся в обе стороны.
Подходит для любого инструмента и таймфрейма.
Уровни, основанные на ATR, адаптируются к волатильности рынка.
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>
/// Timer strategy using EMA crossover.
/// </summary>
public class TimerStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TimerStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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 timer_strategy(Strategy):
def __init__(self):
super(timer_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) .SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 26) .SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) .SetDisplay("Candle Type", "Candle type", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(timer_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(timer_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
self.SubscribeCandles(self.candle_type).Bind(fast, slow, self.process_candle).Start()
def process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
cross_up = self._prev_fast <= self._prev_slow and fv > sv
cross_down = self._prev_fast >= self._prev_slow and fv < sv
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return timer_strategy()