Стратегия тренда по теории Доу
Стратегия определяет направление тренда по пивотам. При появлении последовательности повышающихся максимумов и минимумов открывается длинная позиция, при понижении максимумов и минимумов открывается короткая позиция.
Детали
- Условия входа: рост пивотных максимумов и минимумов для лонга; падение максимумов и минимумов для шорта.
- Long/Short: обе стороны.
- Условия выхода: противоположный сигнал.
- Стопы: нет.
- Значения по умолчанию:
PivotLookback= 10CandleType= TimeSpan.FromMinutes(1)
- Фильтры:
- Категория: Следование тренду
- Направление: Обе
- Индикаторы: Ценовое действие
- Стопы: Нет
- Сложность: Базовая
- Таймфрейм: Любой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Да
- Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Dow Theory Trend strategy.
/// A pivot high is a candle whose high is above the highs of the PivotLookback candles on each side, a pivot low mirrors it with
/// lows; a pivot is confirmed PivotLookback candles after it formed. When the last pivot high is above the one before it and the
/// last pivot low is above the one before it, the trend is up and the strategy goes long; lower highs and lower lows go short.
/// The opposite signal reverses the position.
/// </summary>
public class DowTheoryTrendStrategy : Strategy
{
private readonly StrategyParam<int> _pivotLookback;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _highs = [];
private readonly List<decimal> _lows = [];
private decimal? _lastPivotHigh;
private decimal? _prevPivotHigh;
private decimal? _lastPivotLow;
private decimal? _prevPivotLow;
/// <summary>
/// Candles on each side of a pivot.
/// </summary>
public int PivotLookback
{
get => _pivotLookback.Value;
set => _pivotLookback.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DowTheoryTrendStrategy()
{
_pivotLookback = Param(nameof(PivotLookback), 10)
.SetGreaterThanZero()
.SetDisplay("Pivot Lookback", "Candles on each side of a pivot", "Pivots");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).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();
ResetState();
}
private void ResetState()
{
_highs.Clear();
_lows.Clear();
_lastPivotHigh = null;
_prevPivotHigh = null;
_lastPivotLow = null;
_prevPivotLow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var lookback = PivotLookback;
var size = lookback * 2 + 1;
_highs.Add(candle.HighPrice);
_lows.Add(candle.LowPrice);
if (_highs.Count > size)
{
_highs.RemoveAt(0);
_lows.RemoveAt(0);
}
if (_highs.Count < size)
return;
var centerHigh = _highs[lookback];
var centerLow = _lows[lookback];
var isPivotHigh = true;
var isPivotLow = true;
for (var i = 0; i < size; i++)
{
if (i == lookback)
continue;
if (_highs[i] >= centerHigh)
isPivotHigh = false;
if (_lows[i] <= centerLow)
isPivotLow = false;
}
if (isPivotHigh)
{
_prevPivotHigh = _lastPivotHigh;
_lastPivotHigh = centerHigh;
}
if (isPivotLow)
{
_prevPivotLow = _lastPivotLow;
_lastPivotLow = centerLow;
}
if (_lastPivotHigh is not decimal lastHigh || _prevPivotHigh is not decimal prevHigh
|| _lastPivotLow is not decimal lastLow || _prevPivotLow is not decimal prevLow)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var upTrend = lastHigh > prevHigh && lastLow > prevLow;
var downTrend = lastHigh < prevHigh && lastLow < prevLow;
if (upTrend && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (downTrend && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class dow_theory_trend_strategy(Strategy):
"""
Dow Theory Trend strategy.
A pivot high is a candle whose high is above the highs of the PivotLookback candles on each side, a pivot low mirrors it with
lows; a pivot is confirmed PivotLookback candles after it formed. When the last pivot high is above the one before it and the
last pivot low is above the one before it, the trend is up and the strategy goes long; lower highs and lower lows go short.
The opposite signal reverses the position.
"""
def __init__(self):
super(dow_theory_trend_strategy, self).__init__()
self._pivot_lookback = self.Param("PivotLookback", 10).SetGreaterThanZero().SetDisplay("Pivot Lookback", "Candles on each side of a pivot", "Pivots")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._highs = []
self._lows = []
self._last_pivot_high = None
self._prev_pivot_high = None
self._last_pivot_low = None
self._prev_pivot_low = None
def OnReseted(self):
super(dow_theory_trend_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(dow_theory_trend_strategy, self).OnStarted2(time)
self._reset_state()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
lookback = self._pivot_lookback.Value
size = lookback * 2 + 1
self._highs.append(candle.HighPrice)
self._lows.append(candle.LowPrice)
if len(self._highs) > size:
self._highs.pop(0)
self._lows.pop(0)
if len(self._highs) < size:
return
center_high = self._highs[lookback]
center_low = self._lows[lookback]
is_pivot_high = True
is_pivot_low = True
for i in range(size):
if i == lookback:
continue
if self._highs[i] >= center_high:
is_pivot_high = False
if self._lows[i] <= center_low:
is_pivot_low = False
if is_pivot_high:
self._prev_pivot_high = self._last_pivot_high
self._last_pivot_high = center_high
if is_pivot_low:
self._prev_pivot_low = self._last_pivot_low
self._last_pivot_low = center_low
if self._last_pivot_high is None or self._prev_pivot_high is None or self._last_pivot_low is None or self._prev_pivot_low is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
up_trend = self._last_pivot_high > self._prev_pivot_high and self._last_pivot_low > self._prev_pivot_low
down_trend = self._last_pivot_high < self._prev_pivot_high and self._last_pivot_low < self._prev_pivot_low
if up_trend and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif down_trend and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return dow_theory_trend_strategy()