自定义指标:为净额结算账户绘制部分入场、出场和反转交易·综合运用
(3/3)·从动态矩阵到EA集成,把复杂仓位变动画成一眼能懂的图表
很多交易者开了净额账户,却仍用眼睛去数几次部分平仓后的剩余手数和均价,结果在反转发生时反应慢半拍。图表上只显示当前报价,历史仓位脉络全靠脑补,容易误判真实敞口。把仓位事件直接画出来,比任何事后复盘都更直观。
「逐笔成交量回填的收尾处理」
在循环把已统计过的 Element[i][1] 清零并累加到 newVolume 之后,需要用总成交量 volume 减去已处理部分,得到本笔成交实际应追加的量。 newVolume=volume-newVolume; 这一行就是差额计算,若之前 Element 里累计了 0.30 手而 volume 是 0.50 手,newVolume 最终为 0.20 手。 随后 AddValue(deal_price,newVolume,double(ticket)) 把价格、增量手数和订单号写入深度数据容器,最后 PlotRectangles() 刷新图形层。开 MT5 把这段接在你自己的成交回调里,改一下 Element 的索引维度就能直接验证重绘效果。外汇与贵金属品种跳空频繁,这类逐笔回填在流动性断层时可能漏算,需自行加边界判断。
newVolume+=Element[i][class="num">1]; Element[i][class="num">1]=class="num">0; } newVolume=volume-newVolume; AddValue(deal_price,newVolume,class="type">class="kw">double(ticket)); } } } } PlotRectangles(); }
◍ 净额账户下逐笔交易如何改写数组
在净额结算账户里,同一品种同时只存在一个头寸,所有相关交易共享同一 positionID。上面这份 WINM23 的实盘外成交记录,能直接看到算法怎么靠单号筛选并维护 Element 数组:从 2023.05.04 09:42:05 的 1 手 buy in(价 104035、ticket 1352975)开始,OnTrade() 触发后 ListOrdersPositions 拉取 09:42:05 至当前时间的历史,AddValue 把价格、成交量、单号写进空数组。 下一分钟来了 2 手 sell in/out,原 1 手多单反转成 1 手空单。AddValue 在数组中按单号 1352975 找到旧行,把旧行成交量置零,再算 newVolume = 2 - 1 = 1,插入 {103900, 1, 1356370}。Sort 后数组首项变 103900,PlotRectangles 新建对象,104035 那行只更新属性。此时数组为 {{103900,1,1356370},{104035,0,1352975}}。 第三笔 1 手 sell out(价 103700、ticket 2193299)调用 RemoveValue,ArrayBsearch 在已排序数组里定位到最接近的 103900 行,成交量同为 1 故置零并移除图形,再插入 {103700,0,2193299}。头寸平掉后 numberOfPositions=0、数组清空、date 刷新,系统回到初始空阵状态等待新成交。外汇与贵金属品种用这套逻辑时波动快、滑点大,实盘表现可能与回测有偏差,属于高风险场景,建议在 MT5 策略测试器外先用手动成交验证一次。
把自定义指标塞进回测流程的两条路
在 MT5 策略测试器里调用自定义指标,一般就两条路。一条是写 EA 或上级指标去显式引用,另一条是把指标挂图上存成 Tester.tpl 让测试器自己加载。 走代码引用这条路,先确认编译好的 ex5 已落在 Indicators 目录下,文件名得是“Plotagem de Entradas Parciais.ex5”。调用方要在文件顶部把 handlePlotagemEntradasParciais 声明成 int,再在 OnInit() 里建句柄。下面这段就是建句柄并判错的骨架: iCustom(_Symbol,PERIOD_CURRENT,"Plotagem de Entradas Parciais"); 这一行用当前品种、当前周期去取指标句柄,返回值是 int 类型句柄。 if(handlePlotagemEntradasParciais ==INVALID_HANDLE) 若句柄等于 INVALID_HANDLE,说明创建失败,进分支处理。 PrintFormat("Failed to create indicator handle for symbol %s/%s, error code %d", _Symbol, EnumToString(_Period), GetLastError()); 打印失败品种、周期枚举名和系统错误码,方便定位是路径问题还是指标内部报错。 return(INIT_FAILED); 直接让 OnInit 返回 INIT_FAILED,EA 初始化中止,不会带着空句柄跑逻辑。 另一条路更懒人:把指标手动拖到图表,存模板为 Tester.tpl(同名就覆盖)。之后每次测 EA,只要测试器开了“可视化模式 + 图表显示”,指标就会自动跟着加载,不用动 EA 源码。 注意这第二种只在可视化测试时管用;关掉图表显示的话,模板里的指标不会被加载,EA 里又没写 iCustom,那相关绘图和信号就全丢了。外汇与贵金属回测本身存在模型与实盘偏差的高风险,模板法省事但别误以为等效于代码内引用。
iCustom(_Symbol,PERIOD_CURRENT,"Plotagem de Entradas Parciais"); class=class="str">"cmt">//--- if the handle is not created if(handlePlotagemEntradasParciais ==INVALID_HANDLE) { class=class="str">"cmt">//--- Print an error message and exit with an error code PrintFormat("Failed to create indicator handle for symbol %s/%s, error code %d", _Symbol, EnumToString(_Period), GetLastError()); class=class="str">"cmt">//--- The indicator is terminated prematurely class="kw">return(INIT_FAILED); }
「收束」
这套部分入场绘制指标把 MT5 的自定义指标机制用到了实盘可视化的缝隙里:用 OnCalculate 里维护的静态缓冲区,把每一笔分批成交按价位回画到主图,省掉了交易者自己翻成交明细的麻烦。
附带的 Plotagem_de_Entradas_Parciais.mq5 文件体积 33.4 KB,在 MT5 里直接编译就能挂上 EURUSD 或 XAUUSD 的 M5 图看效果;外汇与贵金属杠杆高、滑点随机,分批入场也只是降低单次暴露,不消除方向误判的亏损可能。
想验证就开 MT5 把文件丢进 Indicators 目录,加载后随便下一单部分平仓,图上的分段标记立刻出来——比看账户历史直观得多。