探索标准库的交易策略类 - 自定义策略·进阶篇
(2/3)· 不想从零写 EA?借标准库策略类与向导,把 RSI、MA 信号拼成自己的交易逻辑
「给 CCI 信号类补两种零轴行为模式」
在基于商品通道指数(CCI)做信号生成的派生类里,传统只识别方向、超买超卖反转、背离这几类市况。原文在成员里扩展了 model 4 与 model 5,把「数值穿越零轴」和「数值在零轴附近弹跳」也量化成 0–100 的权重字段,等于多喂了两种微观结构给决策树。 具体看成员声明:m_pattern_4 对应数值交叉零轴,m_pattern_5 对应零轴周边弹震;二者都和前面的 m_pattern_0~3 一样用 int 存置信度。回测时若只开 0~3,EURUSD 一小时图某段震荡市信号稀疏;把 4、5 权重调到 30 以上,触发次数倾向明显增加,但外汇与贵金属属高风险品种,参数过拟合概率同步上升。 构造器 CSignalCCIxx::CSignalCCIxx() 为空实现,真正的对象绑定在 protected 的 m_CCIxx(CiCCI 实例)里完成。开 MT5 把下面片段贴进信号类头文件,就能直接编译验证这两种新模式字段是否进位。
class="type">int m_extr_pos[class="num">10]; class=class="str">"cmt">// array of shifts of extremums(in bars) class="type">uint m_extr_map; class=class="str">"cmt">// resulting bit-map of ratio of extremums of the oscillator and the price class=class="str">"cmt">//--- "weights" of market models(class="num">0-class="num">100) class="type">int m_pattern_0; class=class="str">"cmt">// model class="num">0 "the oscillator has required direction" class="type">int m_pattern_1; class=class="str">"cmt">// model class="num">1 "reverse behind the level of overbuying/overselling" class="type">int m_pattern_2; class=class="str">"cmt">// model class="num">2 "divergence of the oscillator and price" class="type">int m_pattern_3; class=class="str">"cmt">// model class="num">3 "class="type">class="kw">double divergence of the oscillator and price" class="type">int m_pattern_4; class=class="str">"cmt">// model class="num">4 "our own first new pattern: values cross the zero" class="type">int m_pattern_5; class=class="str">"cmt">// model class="num">5 "our own second new pattern: values bounce around the zero" class CSignalCCIxx : class="kw">public CExpertSignal { class="kw">protected: CiCCI m_CCIxx; class=class="str">"cmt">// object-oscillator }; class="type">void CSignalCCIxx::CSignalCCIxx() {
◍ 给市场模型分配权重参数
在指标初始化阶段,先声明受保护的数据用途:把高价序列与低价序列的引用开关同时打开,即 m_used_series 赋值为 USE_SERIES_HIGH+USE_SERIES_LOW,后续计算才会同时抓取上下影线信息。 紧接着给 CCI 类振荡器一个默认周期 14,这是 MT5 里 CCI 最常规的观察窗口,交易者可在加载指标后改这个值来适配不同品种波动率。 核心在于给 6 种市场模型预设“权重”:模型0(振荡器方向达标)给 90,模型1(超买超卖区反转)给 60,模型2(价指背离)给 100,模型3(双背离)给 50,模型4 与模型5 是自定义新形态,各给 90。权重越高,该模型在综合评分里的话语权越大,外汇与贵金属波动剧烈,高权重模型触发不代表概率必胜,仅代表信号倾向更强。 开 MT5 把这段塞进自定义指标源码,调 m_pattern_2 从 100 降到 70,能直观看到背离信号对总评分的拉动减弱,可用于过滤震荡市的假背离。
class=class="str">"cmt">//--- initialization of class="kw">protected data m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; class=class="str">"cmt">//--- setting class="kw">default values for the oscillator parameters m_periodCCIxx =class="num">14; class=class="str">"cmt">//--- setting class="kw">default "weights" of the market models m_pattern_0 =class="num">90; class=class="str">"cmt">// model class="num">0 "the oscillator has required direction" m_pattern_1 =class="num">60; class=class="str">"cmt">// model class="num">1 "reverse behind the level of overbuying/overselling" m_pattern_2 =class="num">100; class=class="str">"cmt">// model class="num">2 "divergence of the oscillator and price" m_pattern_3 =class="num">50; class=class="str">"cmt">// model class="num">3 "class="type">class="kw">double divergence of the oscillator and price" m_pattern_4 =class="num">90; class=class="str">"cmt">// model class="num">4 "our own first new pattern: " m_pattern_5 =class="num">90; class=class="str">"cmt">// model class="num">5 "our own second new pattern:
CCI 零线穿越的两类早期信号
用 CCI 抓转折,最朴素的办法是看零线在最近两根柱里被怎么穿。柱1指当前柱前一根,柱2指前两根,只要这两根之间零线被跨过,模式就成立。 看涨情形:柱2的 CCI 为 -53.92(<0),柱1的 CCI 为 45.16(>0),零线 0.00 在两根柱内被自下而上穿越,价格随后走高概率偏大。 看跌情形反过来:柱2的 CCI 为 2.41(>0),柱1的 CCI 为 -28.49(<0),零线在两根内被自上而下穿越,下行倾向增强。 外汇与贵金属杠杆高,CCI 零线穿越只是概率提示,实盘前请在 MT5 用不同品种周期核对这两组数值是否稳定复现。
「CCI 三柱穿零的反转信号」
CCI 在零轴附近的来回穿梭,比单次穿越更有参考价值。看涨结构要求:当前柱前 1 根 CCI 为 119.06(>0),前 2 根 -20.38(<0),前 3 根 116.85(>0)——零线被自上而下穿过后,3 根柱内线体回到零轴上方并反弹。 看跌结构刚好镜像:前 1 根 -58.72(<0),前 2 根 57.65(>0),前 3 根 -85.54(<0)。零线被自下而上穿越,随后 3 根柱内回到零轴下方并反弹。 这类三柱穿零形态,在 EURUSD 或 XAUUSD 的 15 分钟图上出现时,价格短期反转概率倾向抬升,但外汇与贵金属杠杆高、滑点大,须用迷你仓验证。 开 MT5 把 CCI 周期设 14,切到 15M,肉眼扫最近 50 根柱就能确认这两种排列是否频繁出现于拐点前。
◍ 用 idx+N 把 CCI 多柱关系写进信号
给买入、卖出条件补代码时,最关键的不是判断本身,而是 (idx+1)、(idx+2) 这种写法。idx 是第 0 根烛形(当前柱),+N 就是往左数第 N 根。N 越大回看越早的柱,每个 (idx+n) 在同一周期下对应指标里相同垂直位置的值。 图 16 里第 0 根柱 CCI 低于 0.00,第 1、2 根(idx+1、idx+2)也在 0 轴下;把鼠标移到 idx+3 能看到它 CCI 已高于 0.00。新手要习惯:图表烛形、CCI 图形、idx 变量、指标值这四者是一一垂直的,能在图上“看”到这种对应,才写得出靠谱策略。 SignalCCIxx.mqh 里加的两个自定义模式就是范例:用选定指标值(此处 CCI)拼出“价格将上涨 / 下跌”的条件,逻辑可继续叠加复杂判断。开平仓机制在标准库交易策略类有说明,MyExpert.mq5 只暴露两个整型输入:Signal_ThresholdOpen 建仓阈值、Signal_ThresholdClose 平仓阈值,取值 0–100。 每个信号文件由若干模式组成并带权重。SignalCCIxx.mqh 复制了标准 0/1/2/3,又加了 4、5 两个模式,权重 80 和 90。回测或挂图时,所有信号模式连续计算;若 m_pattern_4 条件成立(柱1 CCI>0 且柱2 CCI<0),该模式激活,权重绝对值 80,方向涨为正、跌带负号。 信号只在两种竞争情形下触发:它是唯一真信号且强度×系数 ≥ Signal_ThresholdOpen;或它和同策略反向及其他指标反向信号竞争后胜出。向导把每模式当牛熊两派,同方向激活值相加,再与阈值比。 假设除 m_pattern_4=80 外全为 0,Signal_CCIxx_Weight=0.8,则强度=80×0.8=64。无反向竞争时 64>40(ThresholdOpen),买入持仓建立。若 Weight 改 0.4,强度 32<40,不建仓。 换有竞争的例子:m_pattern_4 牛 80 / 熊 -80,RSI 的 m_pattern_1 牛 100 / 熊 -100。四种组合里 A=67 建多、D=-67 建空且互平;B=-3、C=3 均因绝对值<40 不触发。建仓先判正负定方向,再取绝对值比 ThresholdOpen;平仓同理用反向符号转绝对值比 ThresholdClose。外汇与贵金属波动剧烈,这套权重投票仅描述机制,实盘须自行压力测试。
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| "Voting" that price will grow. |</span> <span class="comment">class=class="str">"cmt">//| INPUT: no. |</span> <span class="comment">class=class="str">"cmt">//| OUTPUT: number of "votes" that price will grow. |</span>
多模型 CCI 做多信号的判定分支
CSignalCCIxx::LongCondition() 是 CCI 自定义信号类里给出做多「票数」的函数,返回整型 result,0 表示无信号。它先在 StartIndex() 取当前计算柱,再用 Diff(idx)>0.0 过滤出 oscillator 向上这一前提,之后才进各模式分支。 模式 0 是纯确认信号:只要 IS_PATTERN_USAGE(0) 开启就给 m_pattern_0。模式 1 要求前一根 Diff 向下且 CCIxx(idx+1) 低于 -100.0,也就是超卖区后方圆向上反转,才给 m_pattern_1。 模式 2 与 3 共用 ExtState(idx) 扩展分析。模式 2 用 CompareMaps(1,1) 抓普通背离给 m_pattern_2;模式 3 用 CompareMaps(0x11,2) 抓双背离,且直接 return(m_pattern_3) 不再往下走。 被高亮的那段是模式 4 与 5:模式 4 看零轴下穿转上(idx+1 正、idx+2 负)给 m_pattern_4;模式 5 再多看一根,要求 idx+3 又转正,形成零轴附近弹动,给 m_pattern_5。外汇与贵金属杠杆高,这类信号只代表概率倾向,实盘前务必在 MT5 用历史数据逐模式回测。
class="type">int CSignalCCIxx::LongCondition() { class="type">int result=class="num">0; class="type">int idx =StartIndex(); class=class="str">"cmt">//--- if(Diff(idx)>class="num">0.0) { class=class="str">"cmt">//--- the oscillator is directed upwards confirming the possibility of price growth if(IS_PATTERN_USAGE(class="num">0)) result=m_pattern_0; class=class="str">"cmt">// "confirming" signal number class="num">0 class=class="str">"cmt">//--- if the model class="num">1 is used, search for a reverse of the oscillator upwards behind the level of overselling if(IS_PATTERN_USAGE(class="num">1) && Diff(idx+class="num">1)<class="num">0.0 && CCIxx(idx+class="num">1)<-class="num">100.0) result=m_pattern_1; class=class="str">"cmt">// signal number class="num">1 class=class="str">"cmt">//--- if the model class="num">2 or class="num">3 is used, perform the extended analysis of the oscillator state if(IS_PATTERN_USAGE(class="num">2) || IS_PATTERN_USAGE(class="num">3)) { ExtState(idx); class=class="str">"cmt">//--- if the model class="num">2 is used, search for the "divergence" signal if(IS_PATTERN_USAGE(class="num">2) && CompareMaps(class="num">1,class="num">1)) class=class="str">"cmt">// 00000001b result=m_pattern_2; class=class="str">"cmt">// signal number class="num">2 class=class="str">"cmt">//--- if the model class="num">3 is used, search for the "class="type">class="kw">double divergence" signal if(IS_PATTERN_USAGE(class="num">3) && CompareMaps(0x11,class="num">2)) class=class="str">"cmt">// 00010001b class="kw">return(m_pattern_3); class=class="str">"cmt">// signal number class="num">3 } class=class="str">"cmt">// if the model class="num">4 is used, look for crossing of the zero line if(IS_PATTERN_USAGE(class="num">4) && CCIxx(idx+class="num">1)>class="num">0.0 && CCIxx(idx+class="num">2)<class="num">0.0) result=m_pattern_4; class=class="str">"cmt">// signal number class="num">4 class=class="str">"cmt">// if the model class="num">5 is used, look for the bouncing around the zero line if(IS_PATTERN_USAGE(class="num">5) && CCIxx(idx+class="num">1)>class="num">0.0 && CCIxx(idx+class="num">2)<class="num">0.0 && CCIxx(idx+class="num">3)>class="num">0.0) result=m_pattern_5; class=class="str">"cmt">// signal number class="num">5 } class=class="str">"cmt">//--- class="kw">return the result class="kw">return(result); }