80-20 交易策略·综合运用
(3/3)· 接前两篇的信号模块与基础机器人,本篇把它跑成 EA 并回测世纪末策略在当下盘面的存活率
「用终端全局变量锁住每日单次信号」
把书籍里的 80-20 基础 EA 改造成每日只做一次的短线趋势机器人时,最麻烦的不是信号计算,而是「今天已经下过单」这个状态怎么跨重启保留。程序内存里的布尔变量在终端关闭或 EA 被移除图表时就归零,所以必须把最后一次入场日期写进终端层全局变量,而不是局部变量。 我们给用户暴露了两个输入:One_Trade 控制是否启用每日一单,Magic_Number 给每个 EA 实例分配独立 ID,避免不同品种或回测版本互相覆盖全局变量。代码中前缀 SSB 加上品种名、魔幻数字和测试标识,拼成全局变量命名空间。 OnInit 里读取全局变量 Last_Position_Date 和 Last_Pending_Date,用 TimeCurrent() - TimeCurrent() % 86400 算出当日 0 点时间戳做比对。若相等说明今天已处理过信号,gb_Position_Today / gb_Pending_Today 置真,后续信号直接丢弃。这一处比对逻辑是整段改动的命门,少写 % 86400 就会变成每毫秒都比一遍。 挂单成功和持仓新建两段代码里分别补了 GlobalVariableSet,把当日 0 点时间戳写回终端。这样哪怕 MT5 中途崩了,重启后 EA 仍能从全局变量认出「今天已经动过手」,不会在趋势中段重复追单。外汇与贵金属杠杆高,这类重复入场在滑点扩大时可能把回撤翻倍,验证时建议在策略测试器用 2016 年魔幻数字跑一遍 EURUSD 的 M15。
class="kw">input class="type">bool One_Trade = class="kw">false; class=class="str">"cmt">// 每日一单 class="kw">input class="type">uint Magic_Number = class="num">2016; class=class="str">"cmt">// EA 魔幻数字 class="type">class="kw">string gs_Prefix; class=class="str">"cmt">// 全局变量的标识符 (超级) class="type">bool gb_Position_Today = class="kw">false, gb_Pending_Today = class="kw">false; class="type">int OnInit() { class=class="str">"cmt">// 创建全局变量名的前缀 (超级): gs_Prefix = StringFormat("SSB %s %u %s", _Symbol, Magic_Number, MQLInfoInteger(MQL_TESTER) ? "t " : ""); class=class="str">"cmt">// 今日机器人是否已开单? gb_Position_Today = class="type">int(GlobalVariableGet(gs_Prefix + "Last_Position_Date")) == TimeCurrent() - TimeCurrent() % class="num">86400; gb_Pending_Today = class="type">int(GlobalVariableGet(gs_Prefix + "Last_Pending_Date")) == TimeCurrent() - TimeCurrent() % class="num">86400; } if (i_Try != -class="num">10) { if (Log_Level > LOG_LEVEL_NONE) Print("放置挂单错误"); if (Log_Level > LOG_LEVEL_ERR) PrintFormat("挂单不可放置在 %s 价位。供给价: %s 采购价: %s 停止位: %s", DoubleToString(d_Entry_Level, _Digits), DoubleToString(go_Tick.bid, _Digits), DoubleToString(go_Tick.ask, _Digits), DoubleToString(gd_Stop_Level, _Digits)); } else { GlobalVariableSet(gs_Prefix + "Last_Pending_Date", TimeCurrent() - TimeCurrent() % class="num">86400); gb_Pending_Today = true; } if (PositionSelect(_Symbol)) { if (PositionGetDouble(POSITION_SL) == class="num">0.) { if (!gb_Position_Today) { GlobalVariableSet(gs_Prefix + "Last_Position_Date", TimeCurrent() - TimeCurrent() % class="num">86400); gb_Position_Today = true; } } }
把书里那套形态丢进近五年行情跑一遍
Raschke 和 Connors 原书用的是四位小数报价下的缩进规则,我在 MT5 上拿 EURUSD、USDJPY、XAUUSD 做验证时,把缩进直接放大 10 倍以适配五位小数环境。原文没给尾随参数和止盈算法,我按日线波动挑了组未深度优化的随意比值,先跑裸规则再看加止盈的差别。 EURUSD 取五年历史,原始规则(无止盈)余额曲线和带止盈版本分开跑了;USDJPY 同样五年,因本身波动最猛,两段曲线斜率差异比欧元对更明显;XAUUSD 只用最近 4 年日线,贵金属的高风险属性意味着样本内结果向外推时概率性很强,不能当必然。 每次测试 EA 的全部参数都封在带完整报告的附件里,开 MT5 载入对应 set 文件就能复现这三组余额图,自己改缩进倍数看曲线怎么扭是最直接的验证动作。
◍ 记住这一条就够了
信号模块的编程逻辑底层对应了 80-20 短线系统,但原文作者把原始规则向外扩了一圈:除了改条件,还建议换更贴合系统的交易标的和信号跟踪参数。评论区有人翻出近 6 年回测,单个样本 233 笔交易,结论倾向“单靠原版规则很难盈利”,趋势市相对好用、震荡市吃不到点。 外汇和贵金属自带高杠杆高风险,任何策略在 MT5 里跑完历史测试前都只是“可能有效”。打开你手里的 EA 或指标,先调一下信号检测的阈值,再换两个品种回测,比盲目跟规则实在。