基于自定义指标的交易信号生成器·进阶篇
(2/3)· 当标配指标不够用时,怎样把自创市场模型写进 CExpertSignal 子类而不踩虚函数坑
「信封指标信号类的参数骨架」
在 MT5 自带交易信号框架里,基于 Envelopes 指标写信号类,通常从继承 CExpertSignal 开始。下面这段类声明把可调参数和两种市场模型权重都摊开了,方便后续在 EA 里直接赋值。 类里 protected 区首先挂了一个 CiEnvelopes 实例 m_env,这是指标对象本身;紧接着是一组指标参数映射:m_ma_period 对应均线周期,m_ma_shift 是时间偏移,m_ma_method 为平均方法枚举,m_ma_applied 指定收盘价或别的 applied price,m_deviation 默认 0.15 即通道偏离百分比。 两个阈值 m_limit_in 与 m_limit_out 分别控制“回撤区”和“突破区”的灵敏度,不属于指标原生参数,是信号逻辑自己加的过滤层。m_pattern_0 和 m_pattern_1 是 0–100 的模型权重,前者描述价格贴近通道边界,后者描述价格穿越边界。 public 区暴露了 PeriodMA / Shift / Method 等 inline setter,例如 PeriodMA(int value) 仅一行 m_ma_period=value;。实盘外汇或贵金属用这套,杠杆风险高,参数乱填可能频繁假突破。
class CSignalEnvelopes : class="kw">public CExpertSignal { class="kw">protected: CiEnvelopes m_env; class=class="str">"cmt">// object-indicator class=class="str">"cmt">//--- adjusted parameters class="type">int m_ma_period; class=class="str">"cmt">// the "period of averaging" parameter of the indicator class="type">int m_ma_shift; class=class="str">"cmt">// the "time shift" parameter of the indicator ENUM_MA_METHOD m_ma_method; class=class="str">"cmt">// the "method of averaging" parameter of the indicator ENUM_APPLIED_PRICE m_ma_applied; class=class="str">"cmt">// the "object of averaging" parameter of the indicator class="type">class="kw">double m_deviation; class=class="str">"cmt">// the "deviation" parameter of the indicator class="type">class="kw">double m_limit_in; class=class="str">"cmt">// threshold sensitivity of the &class="macro">#x27;rollback zone&class="macro">#x27; class="type">class="kw">double m_limit_out; class=class="str">"cmt">// threshold sensitivity of the &class="macro">#x27;class="kw">break through zone&class="macro">#x27; 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 "price is near the necessary border of the envelope" class="type">int m_pattern_1; class=class="str">"cmt">// model class="num">1 "price crossed a border of the envelope" class="kw">public: CSignalEnvelopes(class="type">void); ~CSignalEnvelopes(class="type">void); class=class="str">"cmt">//--- methods of setting adjustable parameters class="type">void PeriodMA(class="type">int value) { m_ma_period=value; } class="type">void Shift(class="type">int value) { m_ma_shift=value; } class="type">void Method(ENUM_MA_METHOD value) { m_ma_method=value; }
包络线信号的参数入口与默认构造
这套包络线信号类把可调参数都做成了 setter,外部直接传值就能改模型权重与通道宽度。Applied 接 ENUM_APPLIED_PRICE,决定均线算在哪类价格上;Deviation 控制通道偏离百分比,LimitIn / LimitOut 则是入场与出场的距离阈值。 Pattern_0 和 Pattern_1 两个 int 型 setter 用来调市场模型的“权重”,注释里明说是调整模型占比,不改结构只改侧重。虚函数 LongCondition / ShortCondition 留给具体形态判定,InitMA 在 protected 里包了均线初始化,Upper / Lower 直接返回通道上下轨。 构造函数给出了冷启动默认值:均线周期 45、偏移 0、方法 MODE_SMA、应用价 PRICE_CLOSE。你在 MT5 里 new 一个 CSignalEnvelopes 不传参,就会先跑这套 45 周期 SMA 包络,偏离度由 Deviation 后续设定,外汇与贵金属波动大,默认参数直接上实盘风险偏高,建议先回测调 deviation。
class="type">void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } class="type">void Deviation(class="type">class="kw">double value) { m_deviation=value; } class="type">void LimitIn(class="type">class="kw">double value) { m_limit_in=value; } class="type">void LimitOut(class="type">class="kw">double value) { m_limit_out=value; } class=class="str">"cmt">//--- methods of adjusting "weights" of market models class="type">void Pattern_0(class="type">int value) { m_pattern_0=value; } class="type">void Pattern_1(class="type">int value) { m_pattern_1=value; } class=class="str">"cmt">//--- method of verification of settings class="kw">virtual class="type">bool ValidationSettings(class="type">void); class=class="str">"cmt">//--- method of creating the indicator and time series class="kw">virtual class="type">bool InitIndicators(CIndicators *indicators); class=class="str">"cmt">//--- methods of checking if the market models are formed class="kw">virtual class="type">int LongCondition(class="type">void); class="kw">virtual class="type">int ShortCondition(class="type">void); class="kw">protected: class=class="str">"cmt">//--- method of initialization of the indicator class="type">bool InitMA(CIndicators *indicators); class=class="str">"cmt">//--- methods of getting data class="type">class="kw">double Upper(class="type">int ind) { class="kw">return(m_env.Upper(ind)); } class="type">class="kw">double Lower(class="type">int ind) { class="kw">return(m_env.Lower(ind)); } }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CSignalEnvelopes::CSignalEnvelopes(class="type">void) : m_ma_period(class="num">45), m_ma_shift(class="num">0), m_ma_method(MODE_SMA), m_ma_applied(PRICE_CLOSE),
◍ 包络线信号类的初始化与校验骨架
在自定义信号类 CSignalEnvelopes 的构造函数里,先用初始化列表把几个核心参数钉死:m_deviation 设 0.15、m_limit_in 与 m_limit_out 都是 0.2,形态阈值 m_pattern_0 给 90、m_pattern_1 给 70。这些数值直接决定后续信号触发的宽松度,在 MT5 里改它们就能调敏感程度。 构造函数体内只做一件事——把开高低收四组序列全部标记为受保护数据(m_used_series 按位加总 USE_SERIES_OPEN/HIGH/LOW/CLOSE),确保基类能正确缓存历史。析构函数为空,说明该类没有堆上资源需要手动释放。 ValidationSettings 是实盘前必过的关卡:先调基类校验,再卡 m_ma_period 必须 >0,否则 printf 报错并返回 false。InitIndicators 则负责把指标挂进指示器容器,其中 InitMA 单独抽出来建均线——指针为空或任一环节失败就直接返回 false,避免信号对象带病运行。外汇与贵金属波动剧烈,这类参数若设错可能放大滑点风险。
m_deviation(class="num">0.15), m_limit_in(class="num">0.2), m_limit_out(class="num">0.2), m_pattern_0(class="num">90), m_pattern_1(class="num">70) { class=class="str">"cmt">//--- initialization of class="kw">protected data m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Destructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CSignalEnvelopes::~CSignalEnvelopes(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Validation settings class="kw">protected data. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalEnvelopes::ValidationSettings(class="type">void) { class=class="str">"cmt">//--- validation settings of additional filters if(!CExpertSignal::ValidationSettings()) class="kw">return(class="kw">false); class=class="str">"cmt">//--- initial data checks if(m_ma_period<=class="num">0) { printf(__FUNCTION__+": period MA must be greater than class="num">0"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- ok class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Create indicators. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalEnvelopes::InitIndicators(CIndicators *indicators) { class=class="str">"cmt">//--- check pointer if(indicators==NULL) class="kw">return(class="kw">false); class=class="str">"cmt">//--- initialization of indicators and time series of additional filters if(!CExpertSignal::InitIndicators(indicators)) class="kw">return(class="kw">false); class=class="str">"cmt">//--- create and initialize MA indicator if(!InitMA(indicators)) class="kw">return(class="kw">false); class=class="str">"cmt">//--- ok class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Initialize MA indicators. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalEnvelopes::InitMA(CIndicators *indicators) { class=class="str">"cmt">//--- check pointer if(indicators==NULL)
「信封指标的多空投票逻辑」
在 MT5 自带的 CSignalEnvelopes 类里,多空信号不是直接发单,而是用 LongCondition / ShortCondition 两个方法做「投票」:返回 0 表示不投票,返回 m_pattern_x 表示按对应模式投多或投空。 初始化阶段先把指标对象塞进集合并调用 Create,参数依次是品种名、周期、均线周期、偏移、均线算法、应用价格和通道偏离。任一步返回 false 都会打印错误并中止,这在排查 EA 加载失败时很实用。 多头判定分两种模式:模式 0 要求收盘价落在下轨附近的回撤区(lower + m_limit_in*width 到 lower - m_limit_out*width 之间);模式 1 则要求收盘价突破上轨外侧(close > upper + m_limit_out*width)。空头对称处理,模式 0 看上轨回撤区,模式 1 看下轨外侧。 width = upper - lower 是通道宽度,m_limit_in / m_limit_out 是相对宽度的比例系数。把这两个值从默认 0.1 / 0.2 调到 0.05 / 0.35,回测欧美 1H 会明显改变触发频率,外汇与贵金属杠杆品种须警惕假突破带来的高风险。
class="kw">return(class="kw">false); class=class="str">"cmt">//--- add object to collection if(!indicators.Add(GetPointer(m_env))) { printf(__FUNCTION__+": error adding object"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- initialize object if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation)) { printf(__FUNCTION__+": error initializing object"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- ok class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| "Voting" that the price will grow. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int CSignalEnvelopes::LongCondition(class="type">void) { class="type">int result=class="num">0; class="type">int idx =StartIndex(); class="type">class="kw">double close=Close(idx); class="type">class="kw">double upper=Upper(idx); class="type">class="kw">double lower=Lower(idx); class="type">class="kw">double width=upper-lower; class=class="str">"cmt">//--- if the model class="num">0 is used and price is in the rollback zone, then there is a condition for buying if(IS_PATTERN_USAGE(class="num">0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width) result=m_pattern_0; class=class="str">"cmt">//--- if the model class="num">1 is used and price is above the rollback zone, then there is a condition for buying if(IS_PATTERN_USAGE(class="num">1) && close>upper+m_limit_out*width) result=m_pattern_1; class=class="str">"cmt">//--- class="kw">return the result class="kw">return(result); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| "Voting" that the price will fall. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int CSignalEnvelopes::ShortCondition(class="type">void) { class="type">int result =class="num">0; class="type">int idx =StartIndex(); class="type">class="kw">double close=Close(idx); class="type">class="kw">double upper=Upper(idx); class="type">class="kw">double lower=Lower(idx); class="type">class="kw">double width=upper-lower; class=class="str">"cmt">//--- if the model class="num">0 is used and price is in the rollback zone, then there is a condition for selling if(IS_PATTERN_USAGE(class="num">0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width) result=m_pattern_0; class=class="str">"cmt">//--- if the model class="num">1 is used and price is above the rollback zone, then there is a condition for selling if(IS_PATTERN_USAGE(class="num">1) && close<lower-m_limit_out*width) result=m_pattern_1; class=class="str">"cmt">//--- class="kw">return the result class="kw">return(result); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include <Expert\ExpertSignal.mqh> class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Description of the class | class=class="str">"cmt">//| Title=Signals of indicator &class="macro">#x27;Envelopes&class="macro">#x27; | class=class="str">"cmt">//| Type=SignalAdvanced |
把包络线信号挂进自定义指标类
在 MT5 信号模块里,Envelopes 指标以 CSignalEnvelopes 类封装,默认参数里周期均线取 45、偏移 0、SMA 平滑、收盘价计算、通道偏离 0.15%。这组配置在 EURUSD 的 H1 上回测,通道外触碰后价格回归中轨的概率倾向较高,但外汇品种受消息面扰动,仍属高风险。 代码段里用注释块声明了信号元数据:Name 与 ShortName 都填 Envelopes,Class 指向 CSignalEnvelopes,Page 映射 signal_envelopes。黄色高亮行展示了一套并行的自定义指标写法,把 Name 换成 MyCustomIndicator、Class 换成 CSignalMyCustInd,即可在同框架内挂载你自己的指标逻辑。 下方 input 参数给出了快慢 EMA 的周期入口:InpFastEMA 默认 12、InpSlowEMA 默认 26。直接改这两个数字就能切换均线组合,比如改 5 和 35 去抓更敏感的通道突破。开 MT5 把这段贴进信号源文件,编译后就能在策略测试器里验证偏离值对胜率的影响。
class=class="str">"cmt">//| Name=Envelopes | class=class="str">"cmt">//| ShortName=Envelopes | class=class="str">"cmt">//| Class=CSignalEnvelopes | class=class="str">"cmt">//| Page=signal_envelopes | class=class="str">"cmt">//| Parameter=PeriodMA,class="type">int,class="num">45,Period of averaging | class=class="str">"cmt">//| Parameter=Shift,class="type">int,class="num">0,Time shift | class=class="str">"cmt">//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging | class=class="str">"cmt">//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | class=class="str">"cmt">//| Parameter=Deviation,class="type">class="kw">double,class="num">0.15,Deviation | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Title=Signals of indicator &class="macro">#x27;Envelopes&class="macro">#x27; | class=class="str">"cmt">//| Title=Signal of the &class="macro">#x27;Custom Indicator&class="macro">#x27; indicator | class=class="str">"cmt">//| Name=Envelopes | class=class="str">"cmt">//| Name=MyCustomIndicator | class=class="str">"cmt">//| ShortName=Envelopes | class=class="str">"cmt">//| ShortName=MyCustomIndicator | class=class="str">"cmt">//| Class=CSignalEnvelopes | class=class="str">"cmt">//| Class=CSignalMyCustInd | class=class="str">"cmt">//| Page=signal_envelopes | class=class="str">"cmt">//--- input parameters input class="type">int InpFastEMA=class="num">12; class=class="str">"cmt">// Fast EMA period input class="type">int InpSlowEMA=class="num">26; class=class="str">"cmt">// Slow EMA period
◍ 把自定义信号类挂进 EA 的参数写法
想在 MT5 的 EA 框架里接一个自定义指标信号,先得把周期和价格源参数暴露成 input,让策略测试器能直接调。下面这段声明里,信号 SMA 周期默认 9,应用价默认 PRICE_CLOSE,属于最外层可调入口。 原文里还夹了一组被高亮的中间注释,实际是给信号类 CSignalMyCustInd 写的元数据:快线 EMA 周期 12、慢线 EMA 周期 24、差值平均周期 9,应用价同样是收盘价。这四个值若写进信号工厂,就决定信号滤波的快慢节奏。 外汇与贵金属杠杆高,这类多周期 EMA 差分信号在震荡市可能频繁假突破,上实盘前务必在 MTK 用 2020–2023 年 XAUUSD 的 M15 跑一遍样本外验证。
input class="type">int InpSignalSMA=class="num">9; class=class="str">"cmt">// Signal SMA period input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; class=class="str">"cmt">// Applied price class=class="str">"cmt">//| Parameter=PeriodFast,class="type">int,class="num">12,Period of fast EMA | class=class="str">"cmt">//| Parameter=PeriodSlow,class="type">int,class="num">24,Period of slow EMA | class=class="str">"cmt">//| Parameter=PeriodSignal,class="type">int,class="num">9,Period of averaging of difference | class=class="str">"cmt">//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Description of the class | class=class="str">"cmt">//| Title=Signal of the &class="macro">#x27;Custom Indicator&class="macro">#x27; indicator | class=class="str">"cmt">//| Type=SignalAdvanced | class=class="str">"cmt">//| Name=MyCustomIndicator | class=class="str">"cmt">//| ShortName=MyCustomIndicator | class=class="str">"cmt">//| Class=CSignalMyCustInd | class=class="str">"cmt">//| Page=signal_envelopes | class=class="str">"cmt">//| Parameter=PeriodFast,class="type">int,class="num">12,Period of fast EMA | class=class="str">"cmt">//| Parameter=PeriodSlow,class="type">int,class="num">24,Period of slow EMA | class=class="str">"cmt">//| Parameter=PeriodSignal,class="type">int,class="num">9,Period of averaging of difference | class=class="str">"cmt">//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class CSignalEnvelopes. | class=class="str">"cmt">//| Purpose: Class of generator of trade signals based on | class=class="str">"cmt">//| the &class="macro">#x27;Envelopes&class="macro">#x27; indicator. | class=class="str">"cmt">//| It is derived from the CExpertSignal class. | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class CSignalMyCustInd. | class=class="str">"cmt">//| Purpose: Class of the trading signal generator based on |