Donchian 通道系统
Donchian 通道系统 使用 Donchian 通道的突破信号并加入 Shift 参数以避免前瞻性偏差。
工作原理
- 做多:当收盘价上穿
Shift根K线前计算的 Donchian 上轨。 - 做空:当收盘价下破
Shift根K线前计算的 Donchian 下轨。 - 反向突破时头寸反转。
参数
DonchianPeriod= 20Shift= 2CandleType= 4h
指标
- Donchian 通道
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>
/// Donchian Channels System strategy.
/// Opens long on breakout above shifted upper band and short on breakout below shifted lower band.
/// </summary>
public class DonchianChannelsSystemStrategy : Strategy
{
private readonly StrategyParam<int> _donchianPeriod;
private readonly StrategyParam<int> _shift;
private readonly StrategyParam<DataType> _candleType;
private readonly Queue<decimal> _upperBuffer = new();
private readonly Queue<decimal> _lowerBuffer = new();
private decimal _prevClose;
public int DonchianPeriod
{
get => _donchianPeriod.Value;
set => _donchianPeriod.Value = value;
}
public int Shift
{
get => _shift.Value;
set => _shift.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public DonchianChannelsSystemStrategy()
{
_donchianPeriod = Param(nameof(DonchianPeriod), 20)
.SetDisplay("Donchian Period", "Lookback period for Donchian Channel", "Indicators")
.SetOptimize(10, 60, 5);
_shift = Param(nameof(Shift), 2)
.SetDisplay("Shift", "Bars offset for breakout evaluation", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe for analysis", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_upperBuffer.Clear();
_lowerBuffer.Clear();
_prevClose = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_upperBuffer.Clear();
_lowerBuffer.Clear();
_prevClose = default;
var donchian = new DonchianChannels { Length = DonchianPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(donchian, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, donchian);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue donchianValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (donchianValue is not IDonchianChannelsValue dc)
return;
if (dc.UpperBand is not decimal upper || dc.LowerBand is not decimal lower)
return;
_upperBuffer.Enqueue(upper);
_lowerBuffer.Enqueue(lower);
if (_upperBuffer.Count > Shift + 1)
{
_upperBuffer.Dequeue();
_lowerBuffer.Dequeue();
}
if (_upperBuffer.Count <= Shift)
{
_prevClose = candle.ClosePrice;
return;
}
var shiftedUpper = _upperBuffer.Peek();
var shiftedLower = _lowerBuffer.Peek();
var upBreak = candle.ClosePrice > shiftedUpper && _prevClose <= shiftedUpper;
var dnBreak = candle.ClosePrice < shiftedLower && _prevClose >= shiftedLower;
if (upBreak && Position <= 0)
BuyMarket();
else if (dnBreak && Position >= 0)
SellMarket();
_prevClose = candle.ClosePrice;
}
}
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 DonchianChannels
from StockSharp.Algo.Strategies import Strategy
class donchian_channels_system_strategy(Strategy):
def __init__(self):
super(donchian_channels_system_strategy, self).__init__()
self._donchian_period = self.Param("DonchianPeriod", 20) \
.SetDisplay("Donchian Period", "Lookback period for Donchian Channel", "Indicators")
self._shift = self.Param("Shift", 2) \
.SetDisplay("Shift", "Bars offset for breakout evaluation", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe for analysis", "General")
self._upper_buffer = []
self._lower_buffer = []
self._prev_close = 0.0
@property
def donchian_period(self):
return self._donchian_period.Value
@property
def shift(self):
return self._shift.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(donchian_channels_system_strategy, self).OnReseted()
self._upper_buffer = []
self._lower_buffer = []
self._prev_close = 0.0
def OnStarted2(self, time):
super(donchian_channels_system_strategy, self).OnStarted2(time)
self._upper_buffer = []
self._lower_buffer = []
self._prev_close = 0.0
donchian = DonchianChannels()
donchian.Length = self.donchian_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(donchian, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, donchian)
self.DrawOwnTrades(area)
def process_candle(self, candle, donchian_value):
if candle.State != CandleStates.Finished:
return
upper = donchian_value.UpperBand
lower = donchian_value.LowerBand
if upper is None or lower is None:
return
upper = float(upper)
lower = float(lower)
shift = int(self.shift)
self._upper_buffer.append(upper)
self._lower_buffer.append(lower)
if len(self._upper_buffer) > shift + 1:
self._upper_buffer.pop(0)
self._lower_buffer.pop(0)
if len(self._upper_buffer) <= shift:
self._prev_close = float(candle.ClosePrice)
return
shifted_upper = self._upper_buffer[0]
shifted_lower = self._lower_buffer[0]
close_price = float(candle.ClosePrice)
up_break = close_price > shifted_upper and self._prev_close <= shifted_upper
dn_break = close_price < shifted_lower and self._prev_close >= shifted_lower
if up_break and self.Position <= 0:
self.BuyMarket()
elif dn_break and self.Position >= 0:
self.SellMarket()
self._prev_close = close_price
def CreateClone(self):
return donchian_channels_system_strategy()