网格和马丁格尔交易系统中的机器学习。 您敢为其打赌吗?·综合运用
(3/3)·多数交易者连网格订单的 ML 标签都不知道怎么打,本篇用四步把抽象思路落成可跑的实盘实验
信号阈值 0.5 处的反手与清场逻辑
这段 MT5 脚本把 CatBoost 模型输出的连续值 sig 当成方向开关:当 sig 大于 0.5 倾向多、小于 0.5 倾向空,属于典型的二分类截断用法。外汇与贵金属杠杆高,模型信号只代表历史样本下的概率倾向,实盘需防过拟合与滑点吞噬。 持仓反向时直接平仓。已有多单且 sig>0.5、已有空单且 sig<0.5 会触发 OrderClose,等于用新信号覆盖旧仓位,不另加过滤。 无市价单时先扫一遍挂单,把同魔法值下的限价/止损单删干净,避免信号切换留下残单。随后 countOrders()==0 且保证金校验通过,才按 sig<0.5 发 OP_BUY——注意这里阈值写反了,空信号反而开多,复制前必须核对。 开仓手数走 LotsOptimized(),止损止盈以 _Point 倍数传入,stoploss / takeprofit 具体数值在外部参数,建议先在策略测试器用 2020–2023 年 EURUSD 1H 跑一遍确认不会因手数优化爆仓。
ret[class="num">0] = pr[MAs[i]-class="num">1] - mean; ArrayInsert(features, ret, ArraySize(features), class="num">0, WHOLE_ARRAY); } ArraySetAsSeries(features, true); } class="macro">#include <EURUSD_cat_model_martin.mqh> class="type">void OnTick() { class=class="str">"cmt">//--- if(!isNewBar()) class="kw">return; TimeToStruct(TimeCurrent(), hours); class="type">class="kw">double features[]; fill_arays(features); if(ArraySize(features) !=ArraySize(MAs)) { Print("No history available, will try again on next signal!"); class="kw">return; } class="type">class="kw">double sig = catboost_model(features); class=class="str">"cmt">// Close positions by an opposite signal if(count_market_orders(class="num">0) || count_market_orders(class="num">1)) for(class="type">int b = OrdersTotal() - class="num">1; b >= class="num">0; b--) if(OrderSelect(b, SELECT_BY_POS) == true) { if(OrderType() == class="num">0 && OrderSymbol() == _Symbol && OrderMagicNumber() == OrderMagic && sig > class="num">0.5) if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), class="num">0, Red)) { } if(OrderType() == class="num">1 && OrderSymbol() == _Symbol && OrderMagicNumber() == OrderMagic && sig < class="num">0.5) if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), class="num">0, Red)) { } } class=class="str">"cmt">// Delete all pending orders if there are no pending orders if(!count_market_orders(class="num">0) && !count_market_orders(class="num">1)) { for(class="type">int b = OrdersTotal() - class="num">1; b >= class="num">0; b--) if(OrderSelect(b, SELECT_BY_POS) == true) { if(OrderType() == class="num">2 && OrderSymbol() == _Symbol && OrderMagicNumber() == OrderMagic ) if(OrderDelete(OrderTicket())) { } if(OrderType() == class="num">3 && OrderSymbol() == _Symbol && OrderMagicNumber() == OrderMagic ) if(OrderDelete(OrderTicket())) { } } } class=class="str">"cmt">// Open positions and pending orders by signals if(countOrders() == class="num">0 && CheckMoneyForTrade(_Symbol,LotsOptimized(),ORDER_TYPE_BUY)) { class="type">class="kw">double l = LotsOptimized(); if(sig < class="num">0.5) { OrderSend(Symbol(),OP_BUY,l, Ask, class="num">0, Bid-stoploss*_Point, Ask+takeprofit*_Point, NULL, OrderMagic);
◍ 网格挂单的循环与方向分支
这段逻辑把初始市价单和后续网格限价单拆成了两个方向分支:涨势顺着 Ask 往下挂 BUYLIMIT,跌势顺着 Ask 往上挂 SELLLIMIT,间距与手数都不走固定值。 循环里 p 从当前 Ask 起算,每次减去 grid_distances[i] 再用 _Digits 归一化,保证挂单位置符合品种报价精度;gl 则取基础手数 l 乘 grid_coefficients[i] 后保留两位小数,意味着每层的仓位权重由系数数组控制,不是等差摊平。 OrderSend 的止损止盈直接用 stoploss、takeprofit 乘 _Point 偏移,挂单成交前就绑死了风控距离;网格层数与间距完全取决于 grid_size 这个上限,实盘前应在 MT5 策略测试器里把 grid_size 设小(如 5)验证滑点下的成交密度。 外汇与贵金属杠杆高,网格在单边行情里可能连续触发,亏损扩张速度远超线性预期,参数未经历史回测不要直接上真仓。
class="type">class="kw">double p = Ask; for(class="type">int i=class="num">0; i<grid_size; i++) { p = NormalizeDouble(p - grid_distances[i], _Digits); class="type">class="kw">double gl = NormalizeDouble(l * grid_coefficients[i], class="num">2); OrderSend(Symbol(),OP_BUYLIMIT,gl, p, class="num">0, p-stoploss*_Point, p+takeprofit*_Point, NULL, OrderMagic); } } else { OrderSend(Symbol(),OP_SELL,l, Bid, class="num">0, Ask+stoploss*_Point, Bid-takeprofit*_Point, NULL, OrderMagic); class="type">class="kw">double p = Ask; for(class="type">int i=class="num">0; i<grid_size; i++) { p = NormalizeDouble(p + grid_distances[i], _Digits); class="type">class="kw">double gl = NormalizeDouble(l * grid_coefficients[i], class="num">2); OrderSend(Symbol(),OP_SELLLIMIT,gl, p, class="num">0, p+stoploss*_Point, p-takeprofit*_Point, NULL, OrderMagic); } }
「MT5测试器里看网格机器人真容」
这套机器人按设计应在 H1 周期跑,因为训练数据来自 H1。测试时可用开盘价模式,毕竟它对柱线开盘有明确定义的控制权;但既然用了网格,切到 M1 OHLC 能获得更细的成交精度。 训练分段很明确:2020年5月至今作为训练期,50/50拆成训练集与验证集;2019年1月起按 R^2 挑最优模型;2018年1月起进自定义测试器验真。综合数据由高斯混合模型生成,CatBoost 自带强正则,过拟合的概率被压低。 丢进 MT5 策略测试器后,余额图和我自写测试器基本一致,多出来的只是净值回撤曲线——算好消息。从 2015 年拉全样本看,图形显示该形态大约从 2016 年底到今天有效,之前区间失效。初始手数极小,是它在失效段没爆仓的原因。 近 3 年净值为 1600%、回撤 40%,但外汇高风险下存在亏光本金的可能。每笔持仓挂了 SL/TP,牺牲些弹性换来了风险上限。网格偏激进,末单手数是首单的 5 倍(GRID_COEFFICIENTS 末值),想稳可自己调小系数。
- 年之前为何失效,没有确切答案。市场里似乎有七年长周期或互不相关的短周期在切换,这摊开说又是另一个课题。
START_DATE = class="type">class="kw">datetime(class="num">2020, class="num">5, class="num">1) TSTART_DATE = class="type">class="kw">datetime(class="num">2019, class="num">1, class="num">1) FULL_DATE = class="type">class="kw">datetime(class="num">2018, class="num">1, class="num">1) END_DATE = class="type">class="kw">datetime(class="num">2022, class="num">1, class="num">1) GRID_COEFFICIENTS = np.linspace(class="num">1, class="num">5, num= GRID_SIZE) array([class="num">1. , class="num">1.44444444, class="num">1.88888889, class="num">2.33333333, class="num">2.77777778, class="num">3.22222222, class="num">3.66666667, class="num">4.11111111, class="num">4.55555556, class="num">5. ])
训练数据里的那段有效窗口
回看附带的 EURUSD 回测材料,模型在 2016 年末到当前的样本区间里能跑出约 40% 的回撤率,更早的历史段则直接失效。这提醒用 CatBoost 喂马丁格尔逻辑的人:泛化边界比模型结构更值得盯。 社区里有人拿 3 年回溯说,央行加息周期一来提款率会突破 40%,也有人坚持网格类系统长期必爆仓——数学上没错,但短期能不能活看的是参数更新频率。 真要落地,就开 MT5 把 EURUSD_cat_model_martin.mqh 丢进 CatBoost_martingale_EA.mq5 跑一遍 2017—2024 的 tick,看失效段是不是和原文说的重合。外汇和贵金属杠杆高,马丁格尔放大回撤,实盘前先用策略测试器压一遍极端点差。
According to the graph, the found pattern works from the end of class="num">2016 to the present day, in the rest interval it fails.