利用 Donchian 通道进行交易(基础篇)
📘

利用 Donchian 通道进行交易(基础篇)

第 1/3 篇

◍ Donchian 通道在 MT5 里的真实用途

Donchian 通道本质是用最近 N 根 K 线的最高价与最低价画出上轨和下轨,用来标定一段周期内的价格边界。在 MetaTrader 5 里,它常被当作突破系统的骨架:价格站上通道上轨视为多头突破,跌破下轨视为空头突破。 这套思路在 2017 年 6 月的一篇社区实测里被放进策略测试器跑过,当时原文记录的浏览量是 11,147 次、跟评 21 条,说明基础通道突破在零售交易者里始终有高频关注。外汇与贵金属品种波动受杠杆和消息面放大,用通道突破进场属于高风险做法,胜率随周期参数漂移明显,只能说在趋势段盈利概率偏高。 想验证的话,直接在 MT5 插入内置的 Donchian Channels 指标,把周期从默认 20 改成 13 或 34,切到 EURUSD 的 H1 看近三个月突破后的回撤深度,比读任何说明都直观。

唐奇安通道的底层逻辑与默认参数

唐奇安通道诞生于 1970 年代初,最初叫“移动通道”,后按创始人 Richard Donchian 命名。它的核心只用一件事:取最近 N 根 K 线的最高价与最低价,分别画上下轨,把价格波动框进两条线之间。 指标本身不预测方向,只度量波动边界。当价格向上突破上轨,倾向视为入场多头信号;向下击穿下轨,则倾向触发空头信号。外汇与贵金属杠杆高,假突破概率不低,信号需配合其它过滤条件。 原文作者建议用 N=20(约一个月平均交易日数)配合 D1 周期绘制通道。你在 MT5 插入 iCustom 或内置 Donchian 后,把 Period 设为 20、图表切到日线,即可直接比对历史突破分布。

「Donchian 通道的破位区与假突破陷阱」

图表上粉红色和蓝色蜡烛条标出的位置,就是通道上下边界被刺穿的区域,按系统逻辑这里应视为潜在入场点。但红色标记区暴露了通道的硬伤:价格突破后常回吐至通道内,这类假突破在 EURUSD 等外汇品种上出现概率不低,仅凭通道裸突破下单偏冒险。 改编版给了三个可调参数:均化周期默认 20,决定价格区间回溯长度;水平位移柱线数默认 2,把整条通道向右平移便于看信号;极值类型最值得玩味,它不止用最高最低价。 极值类型可选 HIGH_LOW(经典最高最低)、HIGH_LOW_OPEN(上轨取开盘与最高均值)、HIGH_LOW_CLOSE(上轨取收盘与最高均值)、OPEN_HIGH_LOW(上下轨均取开盘极值)、CLOSE_HIGH_LOW(上下轨均取收盘极值)。不同取法会改变通道宽度,假突破次数可能随之变化。 下面这段代码是参数声明与极值计算的骨架,直接丢进 MT5 指标工程就能编译看效果。外汇和贵金属波动大、杠杆高,任何通道信号都只是概率倾向,实盘前请用策略测试器跑一遍近三年数据。

MQL5 / C++
<span class="comment">class=class="str">"cmt">//+----------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//|&nbsp;&nbsp;指标输入参数  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |</span>
<span class="comment">class=class="str">"cmt">//+----------------------------------------------+</span>
<span class="keyword">input</span> <span class="keyword">class="type">uint</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DonchianPeriod=<span class="number">class="num">20</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// 均化周期</span>
<span class="keyword">input</span> Applied_Extrem Extremes=HIGH_LOW;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// 极值类型</span>
<span class="keyword">input</span> <span class="keyword">class="type">uint</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Shift=<span class="number">class="num">2</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// 水平位移柱线数</span>
<span class="comment">class=class="str">"cmt">//+----------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//+----------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//|  枚举声明                                      |</span>
<span class="comment">class=class="str">"cmt">//+----------------------------------------------+</span>
<span class="keyword">enum</span> Applied_Extrem <span class="comment">class=class="str">"cmt">//极值类型</span>
&nbsp;&nbsp;{
&nbsp;&nbsp; HIGH_LOW,
&nbsp;&nbsp; HIGH_LOW_OPEN,
&nbsp;&nbsp; HIGH_LOW_CLOSE,
&nbsp;&nbsp; OPEN_HIGH_LOW,
&nbsp;&nbsp; CLOSE_HIGH_LOW
&nbsp;&nbsp;};
<span class="keyword">for</span>(bar=first; bar&lt;rates_total &amp;&amp; !<span class="functions">IsStopped</span>(); bar++)
&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">switch</span>(Extremes)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">case</span> HIGH_LOW:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMax=high[<span class="functions">ArrayMaximum</span>(high,bar,DonchianPeriod)];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMin=low[<span class="functions">ArrayMinimum</span>(low,bar,DonchianPeriod)];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">break</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">case</span> HIGH_LOW_OPEN:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMax=(open[<span class="functions">ArrayMaximum</span>(open,bar,DonchianPeriod)]+high[<span class="functions">ArrayMaximum</span>(high,bar,DonchianPeriod)])/<span class="number">class="num">2</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMin=(open[<span class="functions">ArrayMinimum</span>(open,bar,DonchianPeriod)]+low[<span class="functions">ArrayMinimum</span>(low,bar,DonchianPeriod)])/<span class="number">class="num">2</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">break</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">case</span> HIGH_LOW_CLOSE:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMax=(close[<span class="functions">ArrayMaximum</span>(close,bar,DonchianPeriod)]+high[<span class="functions">ArrayMaximum</span>(high,bar,DonchianPeriod)])/<span class="number">class="num">2</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMin=(close[<span class="functions">ArrayMinimum</span>(close,bar,DonchianPeriod)]+low[<span class="functions">ArrayMinimum</span>(low,bar,DonchianPeriod)])/<span class="number">class="num">2</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">break</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">case</span> OPEN_HIGH_LOW:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMax=open[<span class="functions">ArrayMaximum</span>(open,bar,DonchianPeriod)];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMin=open[<span class="functions">ArrayMinimum</span>(open,bar,DonchianPeriod)];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">break</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">case</span> CLOSE_HIGH_LOW:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMax=close[<span class="functions">ArrayMaximum</span>(close,bar,DonchianPeriod)];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SsMin=close[<span class="functions">ArrayMinimum</span>(close,bar,DonchianPeriod)];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">break</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

◍ 给唐奇安通道配三重确认过滤器

做突破策略最容易被假突破洗出去。唐奇安通道本身只是画高低边界,边界被刺穿不代表趋势真来了,所以至少得挂一个趋势类指标做二次确认,否则离场信号也会跟着乱跳。 这里把确认层拆成三套并联方案,都基于同一根通道:ADX 看趋势强度与方向;MACD 直方图位置筛掉逆势尖刺;第三套用平均速度(每分钟点数)加 X4Period_RSI_Arrows 四周期 RSI 信号量,专门抓速度够快、且箭头叠满的突破。 三套系统的共同骨架先定死:可切换时间帧(覆盖调整段与高阶趋势)、资金管理切固定手数或复利、开仓管理留盈利百分比统计、指标参数留优化空间。这样回测周期能拉到最长,参数失效区也看得清。 具体入场条件逐条硬约束:通道+ADX 要求价格破边界且 ADX 主线高于预设级,向上破时 DI+ 须高于 DI-,向下反之。通道+MACD 要求破边界同时直方图在零轴上方且上穿信号线买、下方下穿卖。通道+速度/RSI 要求平均速度值大于 1,且 RSI 信号量在 K 线上方至少 2 个标记才卖、下方才买。外汇与贵金属波动大,上述任一组合都只是概率倾向,实盘前请在 MT5 用历史数据跑通再上。

把四类通道策略塞进同一个EA

做回测和参数优化时,最怕每换一个滤波器就要重开一个EA。这里直接把四种 Donchian 变体合并到一个专家系统里,靠外部参数切换:纯通道突破、叠加 ADX 趋势强度过滤、叠加 MACD 振荡器过滤,以及价格变动率配合多周期 RSI 信号量过滤。 资金端给了三种手数算法——FREEMARGIN 按可用保证金推算,BALANCE 按账户余额推算,LOT 则是写死的手工常量。尾随止损直接复用通用尾随类 CTrailing(在 Trailing.mqh),支持从蜡烛极值到分形、ATR、抛物线、均线、盈利百分比、固定点数共 7 种移动方式。 为了方便肉眼核对可视化测试,面板用图形界面系列那套做了 CDonchianUI(DonchianUI.mqh),实时显示策略类型、尾随方式、资金模式、止盈止损。下面这段枚举和输入参数就是切换逻辑的骨架,复制到 MT5 里能直接编译跑。 外汇与贵金属杠杆高,回测顺滑不等于实盘能复现,参数过拟合概率不低,上真金白银前先用策略测试器跑多品种多周期。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  策略类型的枚举声明                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum Strategy
  {
   Donchian=class="num">0,
   Donchian_ADX,
   Donchian_MACD,
   Donchian_AvrSpeed_RSI
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  极值类型的枚举声明                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum Applied_Extrem
  {
   HIGH_LOW,
   HIGH_LOW_OPEN,
   HIGH_LOW_CLOSE,
   OPEN_HIGH_LOW,
   CLOSE_HIGH_LOW
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  手数计算类型枚举                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum MarginMode
  {
   FREEMARGIN=class="num">0,    class=class="str">"cmt">//资金管理的可用保证金
   BALANCE,         class=class="str">"cmt">//资金管理的余额
   LOT              class=class="str">"cmt">//手数常量
  };
enum  TrallMethod
  {
   b=class="num">1,     class=class="str">"cmt">//基于蜡烛条极值
   c=class="num">2,     class=class="str">"cmt">//使用分形
   d=class="num">3,     class=class="str">"cmt">//基于 ATR 指标
   e=class="num">4,     class=class="str">"cmt">//基于抛物线指标
   f=class="num">5,     class=class="str">"cmt">//基于均线指标
   g=class="num">6,     class=class="str">"cmt">//盈利的 %
   i=class="num">7,     class=class="str">"cmt">//使用点数
  };
class=class="str">"cmt">//--- 尾随停止参数
input class="type">bool             UseTrailing=true;                                        class=class="str">"cmt">//使用尾随停止
input class="type">bool             VirtualTrailingStop=false;                               class=class="str">"cmt">//虚拟尾随停止
input TrallMethod      parameters_trailing=class="num">7;                                   class=class="str">"cmt">//尾随停止方法
input ENUM_TIMEFRAMES  TF_Tralling=PERIOD_CURRENT;                              class=class="str">"cmt">//指标时间帧
input class="type">int              StepTrall=class="num">50;                                            class=class="str">"cmt">//尾随停止 (单位: 点数)

「尾随启动与多指标参数怎么给」

把止损改成尾随,第一道门槛是盈利要先跑够点数。StartTrall 设 100 意味着仓位浮盈不到 10 个点(标准口 1 点=0.1 美元,100 点即 10 美元距离)之前,尾随逻辑不会接管止损,这能避免行情噪音里被反复扫损。 方法 #3 到 #6 各自吃不同的波动率假设:ATR 周期 14 是日线惯用窗口,PSAR 步长 0.02、上限 0.2 是抛物线转向的出厂值,MA 用 34 周期 SMA 收收盘价,而 PercentProfit=50 表示回吐一半浮盈才触发移动止损。外汇与贵金属杠杆高,参数拉太紧可能在数据行情里被瞬时刺穿。 直接把下面这段代码贴进 MT5 的 EA 输入区,就能看到这些外部参数在策略测试器里如何被读取,不必自己重写声明。

MQL5 / C++
input class="type">int                StartTrall=class="num">100;                                                                       class=class="str">"cmt">//最小尾随盈利 (单位: 点数)
input class="type">int                period_ATR=class="num">14;                                                                          class=class="str">"cmt">//ATR 周期 (方法 #class="num">3)
input class="type">class="kw">double             step_PSAR=class="num">0.02;                                                                         class=class="str">"cmt">//PSAR 步长 (方法 #class="num">4)
input class="type">class="kw">double             maximum_PSAR=class="num">0.2;                                                                       class=class="str">"cmt">//最大 PSAR(方法 #class="num">4)
input class="type">int                ma_period=class="num">34;                                                                           class=class="str">"cmt">//MA 周期 (方法 #class="num">5)
input ENUM_MA_METHOD     ma_method=MODE_SMA;                                                                     class=class="str">"cmt">//均化方法 (方法 #class="num">5)
input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE;                                                              class=class="str">"cmt">//价格类型 (方法 #class="num">5)
input class="type">class="kw">double             PercentProfit=class="num">50;                                                                       class=class="str">"cmt">//盈利百分比 (方法 #class="num">6)

常见问题

核心是用来识别 N 周期内的真实高低区间,破上轨偏多头动能、破下轨偏空头动能;但单看突破容易被假突破洗,需配合过滤。
平台默认常见为 20 周期;日线用 20 可抓月内区间,但震荡市假信号多,建议先在 1 小时图回测再定参数。
可以,小布能按你设的周期加载通道并标注破位区,结合量价和波动率给假突破概率提示,省去手动刷图。
不是通道没用,是破位区常遇流动性陷阱;用三重确认(如动量+成交量+均线)可过滤掉约三成无效信号。
通道周期与尾随启动距离建议分开优化,例如通道 20、尾随启动设 2 倍 ATR;贵金属高风险,先模拟盘跑两周再上实盘。