在 GitHub 上查看
Donchian 通道策略
该策略将经典的 "Donchian Channels" EA 移植到 StockSharp 高级 API。策略在较高周期上计算 Donchian 通道,并结合加权移动均线、动量过滤与 MACD 趋势确认,同时提供完整的风险管理模块(止损、止盈、保本、跟踪止损和权益风控)。
策略逻辑
- 市场结构:
- Donchian 通道在更高周期(默认 4 小时)上计算,用于识别潜在的突破结构。
- MACD 在可配置的趋势周期(默认日线)上计算,用于确认大周期趋势方向。
- 入场条件:
- 多头:
- 通道下轨或中轴向上穿越上一根高周期蜡烛实体,提示可能的向上突破。
- 最近两根基础周期蜡烛形成向上的摆动结构(
Low[2] < High[1])。
- 高周期 Momentum 的绝对偏离值在最近三次观察中至少一次超过多头阈值。
- 快速 LWMA 与慢速 LWMA 之间的距离保持在可接受范围内,避免在过度拉升时追高。
- MACD 主线位于信号线之上(无论二者正负),确认多头趋势。
- 空头: 对应条件镜像应用于上轨、向下摆动、动量偏离和 MACD 确认。
- 策略允许分批加仓,直到达到最大持仓次数。
- 出场条件:
- 固定止损与止盈,基于价格步长设置。
- 当价格朝有利方向移动到指定距离后,将止损移动至保本位置。
- 跟踪止损可选择基于最近蜡烛的极值(带缓冲)或传统的触发/步长机制。
- 权益风控监控策略 P&L,当回撤超过设定阈值时强制平仓。
参数说明
| 分组 |
参数 |
说明 |
| General |
Base Candle |
执行与风险控制使用的基础周期。 |
| General |
Donchian Candle |
计算 Donchian 通道及动量的高周期。 |
| General |
Trend Candle |
计算 MACD 的趋势周期。 |
| General |
Volume |
每次下单数量。 |
| Indicators |
Donchian Length |
Donchian 通道的回溯长度。 |
| Indicators |
Fast MA / Slow MA |
基础周期上两条加权均线的长度。 |
| Indicators |
MA Distance |
快慢 LWMA 允许的最大距离(以价格步长计)。 |
| Indicators |
Momentum Period |
动量指标的周期。 |
| Filters |
Momentum Buy / Sell |
多/空方向所需的动量偏离阈值。 |
| Risk |
Stop Loss / Take Profit |
固定止损/止盈距离。 |
| Risk |
Use Trailing |
是否启用跟踪止损。 |
| Risk |
Trailing Trigger / Step |
传统跟踪止损的触发距离和步长。 |
| Risk |
Candle Trail / Trail Candles |
是否使用蜡烛极值及其数量来计算跟踪止损。 |
| Risk |
Trailing Padding |
在蜡烛极值基础上的附加缓冲。 |
| Risk |
Use BreakEven |
是否启用保本逻辑。 |
| Risk |
BreakEven Trigger / Offset |
移动到保本所需的距离及偏移量。 |
| Risk |
Use Equity Stop |
是否启用权益风控。 |
| Risk |
Equity Risk |
最大允许回撤(账户货币)。 |
| Risk |
Max Trades |
最大分批持仓次数。 |
使用建议
- 周期搭配: 按交易风格选择基础周期(如 1 小时或 4 小时),并保持 Donchian/MACD 的周期更高,以维持多周期确认。
- 动量阈值: 原版 EA 以 100 为基准衡量动量偏离,可从 0.3 这一较小阈值起步,在震荡市场中适度提高以减少噪音信号。
- 风险参数: 将 MQL 版本中的点数换算为实际价格步长,并确认交易品种的
Step 值后再设定止损、跟踪和保本距离。
- 分批加仓: 如需单次建仓,可将
Max Trades 设为 1;若要测试金字塔加仓,可逐步提升该值。
- 权益保护:
Equity Risk 表示允许的最大回撤(以账户货币计),请根据个人风险承受能力调整。
回测说明
- 策略可直接在 StockSharp Designer/Backtester 中使用,仅需蜡烛数据,无需 tick 数据。
- 回测或实盘前请确认数据提供商支持所选的全部周期。
- 优化时建议优先调整 Donchian 长度、MA Distance 以及动量阈值,它们对胜率和交易频率影响最大。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class DonchianChannelsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevHigh, _prevLow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public DonchianChannelsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 20).SetGreaterThanZero().SetDisplay("Channel Period", "Donchian channel lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null; _prevLow = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevHigh = high; _prevLow = low; return; }
if (_prevHigh == null || _prevLow == null) { _prevHigh = high; _prevLow = low; return; }
if (candle.ClosePrice > _prevHigh.Value && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (candle.ClosePrice < _prevLow.Value && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevHigh = high; _prevLow = low;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class donchian_channels_strategy(Strategy):
def __init__(self):
super(donchian_channels_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 20) \
.SetDisplay("Channel Period", "Donchian channel lookback", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(donchian_channels_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(donchian_channels_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return donchian_channels_strategy()