动态 Tick 振荡模型 (DTOM)
Dynamic Ticks Oscillator Model 监控 NYSE Down Ticks 指数的变动率。当 ROC 跌破基于标准差的动态阈值时策略做多;当 ROC 突破正阈值时平仓。
详细信息
- 入场条件:
ROC < -StdDev * EntryStdDevMultiplier - 多空: 仅做多。
- 出场条件:
ROC > StdDev * ExitStdDevMultiplier - 止损: 无。
- 默认值:
RocLength = 5VolatilityLookback = 24EntryStdDevMultiplier = 1.6mExitStdDevMultiplier = 1.4mCandleType = TimeSpan.FromMinutes(5).TimeFrame()
- 过滤器:
- 分类: 均值回归
- 方向: 多头
- 指标: RateOfChange, StandardDeviation
- 止损: 无
- 复杂度: 初级
- 时间框架: 日线
- 季节性: 否
- 神经网络: 否
- 背离: 否
- 风险级别: 中等
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>
/// Dynamic Ticks Oscillator Model strategy.
/// Built for the NYSE Down Ticks index as the strategy security. The RocLength rate of change is compared with the standard
/// deviation of that rate over VolatilityLookback candles: a long opens when the ROC drops below -StdDev * EntryStdDevMultiplier
/// and closes when it rises above StdDev * ExitStdDevMultiplier.
/// </summary>
public class DynamicTicksOscillatorModelStrategy : Strategy
{
private readonly StrategyParam<int> _rocLength;
private readonly StrategyParam<int> _volatilityLookback;
private readonly StrategyParam<decimal> _entryStdDevMultiplier;
private readonly StrategyParam<decimal> _exitStdDevMultiplier;
private readonly StrategyParam<DataType> _candleType;
private StandardDeviation _rocStdDev;
/// <summary>
/// Rate of change length.
/// </summary>
public int RocLength
{
get => _rocLength.Value;
set => _rocLength.Value = value;
}
/// <summary>
/// Candles over which the standard deviation of the ROC is measured.
/// </summary>
public int VolatilityLookback
{
get => _volatilityLookback.Value;
set => _volatilityLookback.Value = value;
}
/// <summary>
/// Standard deviation multiplier of the entry threshold.
/// </summary>
public decimal EntryStdDevMultiplier
{
get => _entryStdDevMultiplier.Value;
set => _entryStdDevMultiplier.Value = value;
}
/// <summary>
/// Standard deviation multiplier of the exit threshold.
/// </summary>
public decimal ExitStdDevMultiplier
{
get => _exitStdDevMultiplier.Value;
set => _exitStdDevMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DynamicTicksOscillatorModelStrategy()
{
_rocLength = Param(nameof(RocLength), 5)
.SetGreaterThanZero()
.SetDisplay("ROC Length", "Rate of change length", "Indicators");
_volatilityLookback = Param(nameof(VolatilityLookback), 24)
.SetGreaterThanZero()
.SetDisplay("Volatility Lookback", "Standard deviation length of the ROC", "Indicators");
_entryStdDevMultiplier = Param(nameof(EntryStdDevMultiplier), 1.6m)
.SetGreaterThanZero()
.SetDisplay("Entry StdDev Mult", "Standard deviation multiplier of the entry threshold", "Signals");
_exitStdDevMultiplier = Param(nameof(ExitStdDevMultiplier), 1.4m)
.SetGreaterThanZero()
.SetDisplay("Exit StdDev Mult", "Standard deviation multiplier of the exit threshold", "Signals");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rocStdDev = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var roc = new RateOfChange { Length = RocLength };
_rocStdDev = new StandardDeviation { Length = VolatilityLookback };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(roc, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, roc);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rocValue)
{
if (candle.State != CandleStates.Finished)
return;
// The deviation is measured on the ROC series itself.
var stdValue = _rocStdDev.Process(new DecimalIndicatorValue(_rocStdDev, rocValue, candle.OpenTime) { IsFinal = true });
if (!stdValue.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var std = stdValue.GetValue<decimal>();
if (Position == 0 && rocValue < -std * EntryStdDevMultiplier)
BuyMarket(Volume);
else if (Position > 0 && rocValue > std * ExitStdDevMultiplier)
SellMarket(Position);
}
}
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 RateOfChange, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class dynamic_ticks_oscillator_model_strategy(Strategy):
"""
Dynamic Ticks Oscillator Model strategy.
Built for the NYSE Down Ticks index as the strategy security. The RocLength rate of change is compared with the standard
deviation of that rate over VolatilityLookback candles: a long opens when the ROC drops below -StdDev * EntryStdDevMultiplier
and closes when it rises above StdDev * ExitStdDevMultiplier.
"""
def __init__(self):
super(dynamic_ticks_oscillator_model_strategy, self).__init__()
self._roc_length = self.Param("RocLength", 5).SetGreaterThanZero().SetDisplay("ROC Length", "Rate of change length", "Indicators")
self._volatility_lookback = self.Param("VolatilityLookback", 24).SetGreaterThanZero().SetDisplay("Volatility Lookback", "Standard deviation length of the ROC", "Indicators")
self._entry_std_dev_multiplier = self.Param("EntryStdDevMultiplier", 1.6).SetGreaterThanZero().SetDisplay("Entry StdDev Mult", "Standard deviation multiplier of the entry threshold", "Signals")
self._exit_std_dev_multiplier = self.Param("ExitStdDevMultiplier", 1.4).SetGreaterThanZero().SetDisplay("Exit StdDev Mult", "Standard deviation multiplier of the exit threshold", "Signals")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._roc_std_dev = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(dynamic_ticks_oscillator_model_strategy, self).OnReseted()
self._roc_std_dev = None
def OnStarted2(self, time):
super(dynamic_ticks_oscillator_model_strategy, self).OnStarted2(time)
roc = RateOfChange()
roc.Length = self._roc_length.Value
self._roc_std_dev = StandardDeviation()
self._roc_std_dev.Length = self._volatility_lookback.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(roc, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, roc)
def _process_candle(self, candle, roc_value):
if candle.State != CandleStates.Finished:
return
# The deviation is measured on the ROC series itself.
std_result = process_float(self._roc_std_dev, roc_value, candle.OpenTime, True)
if not std_result.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
roc = float(roc_value)
std = float(std_result)
if self.Position == 0 and roc < -std * float(self._entry_std_dev_multiplier.Value):
self.BuyMarket(self.Volume)
elif self.Position > 0 and roc > std * float(self._exit_std_dev_multiplier.Value):
self.SellMarket(self.Position)
def CreateClone(self):
return dynamic_ticks_oscillator_model_strategy()