为智能系统制定品质因数·综合运用
(3/3)· 从随机模型到双品质因数返回,补齐策略测试器只给一个数值的能力缺口
多数交易者在策略测试器里只盯着 OnTester result 一个零值发呆,却没意识到那是因为 EA 根本没写返回逻辑。把系统品质压缩成单一数字,等于主动放弃了第二把尺子。
按月切分交易历史算 SQN 均值
这段逻辑干的事很直接:把 MT5 账户全部已平仓交易按自然月切块,逐月算 SQN 再取简单平均。外汇与贵金属杠杆高、滑点跳空频繁,历史统计只能反映过去样本,对未来的指向是概率性的,不能直接当仓位依据。 代码先用 HistorySelect(0, TimeCurrent()) 拉全量成交历史,失败直接返回 0.0;HistoryDealsTotal() 拿到总单数。循环里用 HistoryDealGetTicket 取每笔 ticket,再读 DEAL_TIME 与 DEAL_PROFIT,利润为 0 的单子跳过不计入。 eh_um_novo_mes 检测到跨月时,若上月有交易就调用 sqn() 把该月 SQN 累加到 sqn_acumulado,同时 sqn_n 加 1,并重置累计利润与笔数。循环结束后再补一次月末残留计算,避免最后一个月漏掉。 最终 return NormalizeDouble(sqn_acumulado / sqn_n, 2) 输出两位小数月度 SQN 均值。SQN_TESTER_ON_TESTER 里则把 sqn_mes() 与 CPCIndex() 相乘保留 5 位,并在日志打印 rr_medio、CPCIndex、sqn_mes 三项,方便你开 MT5 策略测试器跑完直接核对数字。
class="type">class="kw">double lucro_acumulado = class="num">0.0; class="type">class="kw">double quantidade_negocios = class="num">0.0; class="type">int sqn_n = class="num">0; class="type">int mes = -class="num">1; class="type">uint primeiro_negocio = class="num">0; class="type">uint total_negocios; class=class="str">"cmt">//--- request the history of trades if(HistorySelect(class="num">0,TimeCurrent()) == class="kw">false) class="kw">return class="num">0.0; total_negocios = HistoryDealsTotal(); class=class="str">"cmt">//--- the average for each month is calculated for each trade for(class="type">uint i=primeiro_negocio; i < total_negocios; i++) { class="type">class="kw">ulong ticket=class="num">0; class=class="str">"cmt">//--- Select the required ticket to pick up data if((ticket=HistoryDealGetTicket(i))>class="num">0) { class="type">class="kw">datetime time = (class="type">class="kw">datetime)HistoryDealGetInteger(ticket, DEAL_TIME); class="type">class="kw">double lucro = HistoryDealGetDouble(ticket,DEAL_PROFIT); if(lucro == class="num">0) { class=class="str">"cmt">//--- If there is no result, move on to the next trade. class="kw">continue; } if(eh_um_novo_mes(time, mes)) { class=class="str">"cmt">//--- If we have trades, then we calculate sqn, otherwise it will be equal to zero... if(quantidade_negocios>class="num">0) { sqn_acumulado += sqn(primeiro_negocio, i, lucro_acumulado, quantidade_negocios); } class=class="str">"cmt">//--- The calculated amount sqns is always updated! sqn_n++; primeiro_negocio=i; lucro_acumulado = class="num">0.0; quantidade_negocios = class="num">0; } lucro_acumulado += lucro; quantidade_negocios++; } } class=class="str">"cmt">//--- when exiting "for", we can have undesired result if(quantidade_negocios>class="num">0) { sqn_acumulado += sqn(primeiro_negocio, total_negocios, lucro_acumulado, quantidade_negocios); sqn_n++; } class=class="str">"cmt">//--- take the simple average of sqns class="kw">return NormalizeDouble(sqn_acumulado / sqn_n, class="num">2); } class="type">class="kw">double SQN_TESTER_ON_TESTER() { PrintFormat("%G,%G,%G", rr_medio(), CPCIndex(), sqn_mes()); class="kw">return NormalizeDouble(sqn_mes() * CPCIndex(), class="num">5); }
◍ 用宏切换绕开 OnTester 重定义
EA 主文件和被 include 的 ARTICLE_METRICS.mq5 里若各写一个 OnTester,编译器会直接报函数重复。常见做法是注释掉一大片代码,但在 MT5 里可以用预处理宏做轻量切换。
上面的示例里,先在 EA 中定义 OnTester 返回 __LINE__,随后 #include 指标/库文件。紧跟着用 #define OnTester disable 把名字改写,再写第二个 OnTester 并通过 #undef 还原宏,第二次 include 时文件内的 OnTester 已被重命名为 disable,主文件里的仍叫 OnTester,重名冲突消失。
实测这种写法不用动 include 文件内容,只改 EA 里的两行宏就能在「用主函数」和「用库函数」之间切。代价是宏侵入性较强,团队接手时容易看懵:明明写的是 OnTester,实际编译进去的可能是 disable。外汇与贵金属 EA 回测高风险,任何函数切换都建议在策略测试器里跑一遍确认入口没接错。
class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double OnTester() { class="kw">return __LINE__; } class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "ARTICLE_METRICS.mq5" class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define OnTester disable class=class="str">"cmt">//class="macro">#define SQN_TESTER_ON_TESTER disable class="type">class="kw">double OnTester() { class="kw">return __LINE__; } class="macro">#undef OnTester class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "ARTICLE_METRICS.mq5"
「把工具请下神坛」
前面两节把随机操作的智能系统模型拆开,用 Van Tharp 和 Sunny Harris 两套公式算了品质因数,又引入了新的“风险-回报”关系因数。代码层面靠 includes 机制切换不同衡量函数,文后 zip 里附了 ARTICLE_METRICS.mq5(10.33 KB)和 ARTICLE_MT5.mq5(11.87 KB),直接拖进 MT5 就能改参数跑。 这些衡量度只是给策略打分的尺子,不是圣杯。外汇和贵金属杠杆高、跳空频繁,同一套因数在样本内漂亮,换周期可能就塌了。 真要验证,就把 zip 里的 mq5 编译后接上自己的历史数据,看“风险-回报”因数在实盘滑点下掉多少。工具用熟了,决策还得多留一分怀疑。