小型趋势指标、中型趋势指标和主要趋势指标·综合运用
(3/3)·小型抓拐点、中型定波段、主趋势管方向,三层信号如何不打架才是实战关键
◍ 信号类的摆动参数与接口骨架
在 MT5 里做甘恩突破信号,第一步是把主趋势与中级趋势的摆动结构分开存。下面这段类声明给出了核心缓冲区与对外设置接口,直接在 EA 的 Include 目录里建个 signal_gannbreak.mqh 就能照着填。 int handle_middle_swing; 存中级趋势指示器的句柄。double main_swing_buff[] 与 middle_swing_buff[] 分别装主、中趋势的摆动值;datetime time_buff[] 和 double price_buff[] 记录拐点时间与价格,回测时可用数组长度判断当前已捕捉几段 swing。 公开方法里 MinMainSwingContinuance(int) 限定主趋势摆动最少延续根数,MinMainSwingSize(double) 限定最小幅度(报价单位)。中级趋势用 MinMiddleSwingContinuance 与 MaxMiddleSwingSize 双向卡边界,避免噪声段触发。OpenPriceSpace 与 StopLossSpace 直接给开仓价与止损留了点差空间参数。 CheckOpenLong / CheckOpenShort 是重载 CExpertSignal 的入口,传出 price、sl、tp、expiration 引用;ValidationSettings 负责在 OnInit 阶段拦截非法参数。外汇与贵金属杠杆高,这类信号在震荡市可能连续假突破,参数没过 ValidationSettings 就别挂实盘。 protected 里的 SetMainSwingParameters 与 SetMiddleSwingParameters 用左右拐点时间加价格四参写入,GetMainSwing / GetMiddleSwing 负责从图表取段——这两个私有取段函数若返回 0,说明当前品种周期下摆动识别失败,需降周期或放宽 Min 条件。
class="type">int handle_middle_swing; class="type">class="kw">double main_swing_buff[]; class="type">class="kw">double middle_swing_buff[]; class="type">class="kw">datetime time_buff[]; class="type">class="kw">double price_buff[]; class="kw">public: TGannBreakSignal(); class=class="str">"cmt">// constuctor ~TGannBreakSignal(); class=class="str">"cmt">// destructor class=class="str">"cmt">// Settings: class="type">void MinMainSwingContinuance(class="type">int _cont); class="type">void MinMainSwingSize(class="type">class="kw">double _size); class="type">void MinMiddleSwingContinuance(class="type">int _cont); class="type">void MaxMiddleSwingSize(class="type">class="kw">double _size); class="type">void OpenPriceSpace(class="type">class="kw">double _space); class="type">void StopLossSpace(class="type">class="kw">double _space); class="type">int GetMainSwingContinuance(); class=class="str">"cmt">// gets swing duration time on the chart of the main trend class="type">class="kw">double GetMainSwingSizePoints(); class=class="str">"cmt">// gets swing amplitude(in class="num">4-digit points) on the chart of the main trend class="type">int GetMiddleSwingContinuance(); class=class="str">"cmt">// gets swing duration time on the chart of the middle trend class="type">class="kw">double GetMiddleSwingSizePoints(); class=class="str">"cmt">// gets swing amplitude(in class="num">4-digit points) on the chart of the middle trend class=class="str">"cmt">// overloaded methods of the CExpertSignal class: class="kw">virtual class="type">bool ValidationSettings(); class="kw">virtual class="type">bool CheckOpenLong(class="type">class="kw">double &price,class="type">class="kw">double &sl,class="type">class="kw">double &tp,class="type">class="kw">datetime &expiration); class="kw">virtual class="type">bool CheckOpenShort(class="type">class="kw">double &price,class="type">class="kw">double &sl,class="type">class="kw">double &tp,class="type">class="kw">datetime &expiration); class="kw">virtual class="type">bool InitIndicators(CIndicators *indicators); class=class="str">"cmt">// Additional methods: class="kw">protected: class=class="str">"cmt">// Sets swing parameters of the main trend class="type">void SetMainSwingParameters(class="type">class="kw">datetime _lf_dt,class="type">class="kw">double _lf_price,class="type">class="kw">datetime _rt_dt,class="type">class="kw">double _rt_price); class=class="str">"cmt">// Sets swing parameters of the middle trend class="type">void SetMiddleSwingParameters(class="type">class="kw">datetime _lf_dt,class="type">class="kw">double _lf_price,class="type">class="kw">datetime _rt_dt,class="type">class="kw">double _rt_price); class=class="str">"cmt">// Gets swing parameters of the main trend class="type">int GetMainSwing(); class=class="str">"cmt">// Gets swing parameters of the middle trend
参数校验与多浪过滤的开多逻辑
Gann 突破信号类里,ValidationSettings 是先跑的一道闸。四个阈值参数若 ≤0 会直接 Print 报错并返回 false:主浪最小存续、主浪最小点数、中浪最小存续、中浪最大点数,任何一项不合法,后续信号计算全部不执行。 CheckOpenLong 的过滤链更硬。先调 GetMainSwing 与 GetMiddleSwing,返回 -1 即说明对应波段没识别出来,直接退出;接着比对 right 与 left 价格,主浪或中浪若出现 rt_price >= lf_price,意味着该段不是向下摆动,同样不进单。 波段尺度还要过双表:主浪存续须 ≥ min_main_swing_continuance 且点数 ≥ min_main_swing_size_points;中浪存续须 ≥ min_middle_swing_continuance 且点数 ≤ max_middle_swing_size_points。四条件任一不满足,函数返回 false,不会给 _price / _sl / _tp 赋值。 在 MT5 里把 min_main_swing_continuance 设成 0 试一下,日志会立刻吐出 Wrong Parameter 且信号类失效——这比看文档更快确认阈值下限。外汇与贵金属波动随机性高,此类过滤只降低噪音,不预示方向。
class="type">int GetMiddleSwing(); }; class=class="str">"cmt">//--------------------------------------------------------------------- class=class="str">"cmt">// Validation of settings class=class="str">"cmt">//--------------------------------------------------------------------- class="type">bool TGannBreakSignal::ValidationSettings() { if(this.min_main_swing_continuance<=class="num">0) { Print("Wrong Parameter: min_main_swing_continuance = ", this.min_main_swing_continuance); class="kw">return(false); } if(this.min_main_swing_size_points<=class="num">0.0) { Print("Wrong Parameter: min_main_swing_size_points = ", DoubleToString(this.min_main_swing_size_points,class="num">1)); class="kw">return(false); } if(this.min_middle_swing_continuance<=class="num">0) { Print("Wrong Parameter: min_middle_swing_continuance = ",this.min_middle_swing_continuance); class="kw">return(false); } if(this.max_middle_swing_size_points<=class="num">0.0) { Print("Wrong Parameter: max_middle_swing_size_points = ",DoubleToString(this.max_middle_swing_size_points,class="num">1)); class="kw">return(false); } class="kw">return(true); } class=class="str">"cmt">//--------------------------------------------------------------------- class=class="str">"cmt">// Checks conditions to open class="type">long position class=class="str">"cmt">//--------------------------------------------------------------------- class="type">bool TGannBreakSignal::CheckOpenLong(class="type">class="kw">double &_price,class="type">class="kw">double &_sl,class="type">class="kw">double &_tp,class="type">class="kw">datetime &_expiration) { if(this.GetMainSwing()==-class="num">1) { class="kw">return(false); } if(this.GetMiddleSwing()==-class="num">1) { class="kw">return(false); } class=class="str">"cmt">// If the main swing upward, exit if(this.main_swing_rt_price>=this.main_swing_lf_price) { class="kw">return(false); } class=class="str">"cmt">// If the middle weak swing isn&class="macro">#x27;t formed, exit: if(this.middle_swing_rt_price>=this.middle_swing_lf_price) { class="kw">return(false); } class=class="str">"cmt">// Check swing parameters on the main trend chart if(this.main_swing_continuance<this.min_main_swing_continuance || this.main_swing_size_points<this.min_main_swing_size_points) { class="kw">return(false); } class=class="str">"cmt">// Check swing parameters on the middle trend chart if(this.middle_swing_continuance<this.min_middle_swing_continuance || this.middle_swing_size_points>this.max_middle_swing_size_points) { class="kw">return(false); } class="type">class="kw">double unit=this.PriceLevelUnit();
「弱中摆突破后的多单信号与跟踪止损骨架」
当价格向上越过弱中摆的峰值,并留出 open_price_space 单位的缓冲时,系统倾向给出多头开仓信号。代码里用 Bid 价减去(左摆价 + open_price_space*unit)得到 delta,要求 delta 落在 [0, 10*unit) 区间内才触发,避免追在过分延展的位置。 触发后 _price 与 _tp 置 0,代表采用市价进场且不预设止盈;止损则 NormalizePrice 到右侧摆价减去 stop_loss_space*unit。外汇与贵金属杠杆高,这种仅用摆点挂止损的方式在快速反转时可能滑点放大,实盘前需在 MT5 用历史 tick 校验。 trailing 类通过 wizard 描述块暴露 StopLossSpace 参数,默认 5.0,即止损距摆点 5 个最小单位。类内缓存了左右摆的 datetime 与 price,以及 middle_swing_buff / time_buff / price_buff 三组数组,方便后续 CheckTrailing 里动态重算止损。 别把 10*unit 当铁律 delta 上限写死 10*unit 只是原逻辑的一种保守过滤,换到 XAUUSD 这类点值大的品种,可按点值重算该阈值,否则可能几乎不吃到信号。
class=class="str">"cmt">// If the price has crossed the peak of the weak middle swing, set signal to open class="type">long position: class="type">class="kw">double delta=this.m_symbol.Bid() -(this.middle_swing_lf_price+this.open_price_space*unit); if((delta>=class="num">0.0) && (delta<(class="num">10.0*unit))) { _price=class="num">0.0; _sl = this.m_symbol.NormalizePrice(this.middle_swing_rt_price - stop_loss_space*unit); _tp = class="num">0.0; class="kw">return(true); } class="kw">return(false); } class="macro">#include <Expert\ExpertTrailing.mqh> class=class="str">"cmt">// wizard description start class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Description of the class | class=class="str">"cmt">//| Title=Trailing on peaks/bottoms on the chart of the middle trend | class=class="str">"cmt">//| Type=Trailing | class=class="str">"cmt">//| Name=MiddleTrend | class=class="str">"cmt">//| Class=MiddleTrendTrailing | class=class="str">"cmt">//| Page= | class=class="str">"cmt">//| Parameter=StopLossSpace,class="type">class="kw">double,class="num">5.0 | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// wizard description end class=class="str">"cmt">//+------------------------------------------------------------------+ class MiddleTrendTrailing : class="kw">public CExpertTrailing { class="kw">private: class="type">class="kw">datetime middle_swing_lf_datetime; class=class="str">"cmt">// time of left point of a swing on the chart of the main trend class="type">class="kw">double middle_swing_lf_price; class=class="str">"cmt">// price of left point of a swing on the chart of the main trend class="type">class="kw">datetime middle_swing_rt_datetime; class=class="str">"cmt">// time of right point of a swing on the chart of the main trend class="type">class="kw">double middle_swing_rt_price; class=class="str">"cmt">// price of right point of a swing on the chart of the main trend class="type">class="kw">double stop_loss_space; class=class="str">"cmt">// the distance between peak/bottom and stop loss price class="type">int handle_middle_swing; class="type">class="kw">double middle_swing_buff[]; class="type">class="kw">datetime time_buff[]; class="type">class="kw">double price_buff[]; class="kw">public: MiddleTrendTrailing(); class=class="str">"cmt">// constructor
◍ 中摆跟随止盈止损的多头判定分支
上面这段是 MiddleTrendTrailing 类尾部的方法声明与多头尾随止损的具体实现,核心在于用「中间摆点」动态推算止损位。 类声明里先放了析构函数 ~MiddleTrendTrailing() 和私有方法 GetMiddleSwing() 用来取中间摆动参数;对外暴露的 StopLossSpace(double _space) 让你直接注入止损缓冲空间,其余 ValidationSettings / InitIndicators / CheckTrailingStopLong / CheckTrailingStopShort 均为对 CExpertTrailing 的虚函数重载。 看 CheckTrailingStopLong:入参为空或 GetMiddleSwing() 返回 -1(取不到摆点)时直接返回 false,不改动仓位。 sl_req_price 的计算是关键——取左右两侧中间摆点价格的最小值,再减去 stop_loss_space 个「校准点」(adjusted_point),并用 NormalizePrice 对齐报价精度。若当前止损已优于该价(>=),同样不动作;否则把 _tp 置为 EMPTY_VALUE、_sl 写成新价并返回 true,MT5 会在下一 tick 尝试挪损。 实盘接这段逻辑时,stop_loss_space 建议从 0.5 起步在 EURUSD 的 M15 回测,外汇与贵金属杠杆高,摆点失效时可能连续返回 false 不 protective 平仓,需自加熔断。
~MiddleTrendTrailing(); class=class="str">"cmt">// destructor class="kw">private: class="type">int GetMiddleSwing(); class=class="str">"cmt">// get parameters of the middle swing class="kw">public: class=class="str">"cmt">// Settings: class="type">void StopLossSpace(class="type">class="kw">double _space); class=class="str">"cmt">// Overloaded methods of CExpertTrailing class: class="kw">virtual class="type">bool ValidationSettings(); class="kw">virtual class="type">bool InitIndicators(CIndicators *indicators); class="kw">virtual class="type">bool CheckTrailingStopLong(CPositionInfo *position,class="type">class="kw">double &sl,class="type">class="kw">double &tp); class="kw">virtual class="type">bool CheckTrailingStopShort(CPositionInfo *position,class="type">class="kw">double &sl,class="type">class="kw">double &tp); }; class=class="str">"cmt">//--------------------------------------------------------------------- class=class="str">"cmt">// Checks conditions of trailing stop for class="type">long position class=class="str">"cmt">//--------------------------------------------------------------------- class="type">bool MiddleTrendTrailing::CheckTrailingStopLong(CPositionInfo *_position,class="type">class="kw">double &_sl,class="type">class="kw">double &_tp) { if(_position==NULL) { class="kw">return(false); } if(this.GetMiddleSwing()==-class="num">1) { class="kw">return(false); } class="type">class="kw">double sl_req_price = this.m_symbol.NormalizePrice(MathMin(middle_swing_lf_price,middle_swing_rt_price) - this.stop_loss_space * this.m_adjusted_point ); if(_position.StopLoss() >= sl_req_price ) { class="kw">return(false); } _tp = EMPTY_VALUE; _sl = sl_req_price; class="kw">return(true); }
用向导把信号模块拼成可跑 EA
在 MT5 里把写好的信号变成自动交易程序,走 MetaEditor 的 File / New 调出生成向导即可,不用手搓框架。第一步选 EA (generate) 单选钮进下一页;第二步给 EA 起名并把 EveryTick 设 true,让程序处理每一次报价跳动,幻数留默认也行。 第三步从信号列表里挑你之前编的那个信号模块,弹出的输入参数框可以直接改默认值,比如均线周期或阈值,改完继续下一步。第四步选仓位追踪方式,若你做过自定义追踪止损就选它,同样能调外部参数。 第五步资金管理保持固定手数不变,点 Done 就能拿到带建仓、追踪、风控规则的完整 EA。图 17 的回测里趋势被识别完整(在该方法允许范围内),且用的全是默认参数,说明信号逻辑本身能跑通。外汇与贵金属杠杆高,实盘前务必在策略测试器用真实点差多周期验证。 [CODE] "" [/CODE]
「按市场选对时间颗粒度」
甘氏模型落地的第一层约束,是时间周期必须贴合品种的自然交易架构,否则图形划分会失真。 股票市场用日、周、月线就够了;货币市场得切到会话(session)间隔,才能对齐流动性节奏;商品市场除了日周月,还要叠季节性波动。 实操上,开 MT5 把 EURUSD 的 H1 和「会话分隔」视图各拉一遍,你会看到支撑阻力在会话边界的重排概率明显更高——这是验证模型适配性的最快路径。外汇与贵金属属高杠杆品种,session 级信号失效时回撤可能快速扩大,需自设止损。
◍ 把工具请下神坛
顺着上面那张圆形水平分布图往下看,2000—2011 年日线数据里欧元和股票的顶底并未整齐落在 50、100 这类整数尾数上,日元也不是稳稳收在 40;分布有偏斜,但和“圆数”假设对不齐。这意味着甘氏的圆形水平更像一种模糊倾向,而非可单独开仓的依据。 真要验,就把附带的 gannmiddletrend.mq5 拖进 MT5 按日线跑一遍,自己数小数点末三位在 0–50 区间的顶底频次——外汇和贵金属杠杆高、滑点狠,这套只是历史统计的补充视角,别拿来当信号圣经。 作者给的 mqh 在现行 MT5 向导里常报无法识别,得手动改 include 路径和文件名大小写;它撑不起自动交易,但当作手动复盘时的分布参考还算够用。