前阵子看FCA又发了个关于零售外汇杠杆的咨询文件,底下评论区吵成一片,我倒是想起另一件事——上个月帮一个做黄金日内的小账户调MT4图表卡顿的问题,折腾半天发现根子不在VPS,也不在历史数据量,而是他自己写的那个自定义指标开了8个缓冲区,图表刷新跟幻灯片似的。今天就把这个坑掰开聊聊。
MT4的指标缓冲区(SetIndexBuffer)本质上是给每个指标线分配一块独立的内存数组,MT4在每根K线更新时会把所有缓冲区从头算一遍。很多人写指标习惯性多开缓冲区,觉得“反正用不上就不画”,但只要你SetIndexBuffer了,MT4就会老老实实分配、填充、刷新。8个缓冲区意味着每根K线要跑8次数组写入,黄金1分钟图上一天几千根K线,累积起来就是肉眼可见的卡顿。
我当时做的压缩思路是这样的:
改完之后在同样的VPS上跑,黄金M1图表从原来拖动一下卡半秒,变成基本跟手,刷新速度目测快了一倍不止。这里提醒一句,压缩缓冲区之后一定要重新跑一遍历史回测,确认指标数值和之前一致,尤其是那些被合并的中间计算,浮点精度偶尔会有细微差异,在黄金这种点值大的品种上,0.01的偏差都可能影响信号触发。
还有个细节:如果你的指标是被EA通过iCustom调用的,缓冲区数量变了之后,iCustom里的参数索引也要同步改,不然EA读到的就是错位的值。我那个朋友就是改完指标忘了改EA,实盘跑了两天才发现信号不对,好在是模拟仓。
其实MT4这套缓冲区机制挺老的,MT5的指标句柄模式在这方面灵活不少,但架不住现在还有大量EA和指标跑在MT4上。你们手头有没有那种开了五六个缓冲区、图表一卡就怪VPS的指标?可以贴出来一起看看能不能再砍两刀。
补充个小细节:压缩缓冲区时记得顺手把用不到的SetIndexStyle设成DRAW_NONE,不然MT4还是会分配内存去算,白忙活。
MT4的指标缓冲区(SetIndexBuffer)本质上是给每个指标线分配一块独立的内存数组,MT4在每根K线更新时会把所有缓冲区从头算一遍。很多人写指标习惯性多开缓冲区,觉得“反正用不上就不画”,但只要你SetIndexBuffer了,MT4就会老老实实分配、填充、刷新。8个缓冲区意味着每根K线要跑8次数组写入,黄金1分钟图上一天几千根K线,累积起来就是肉眼可见的卡顿。
我当时做的压缩思路是这样的:
- 先盘清楚哪些缓冲区是真在用的。把指标源码翻出来,看每个SetIndexBuffer后面到底有没有对应的绘图调用(SetIndexStyle、SetIndexLabel、PlotIndexSetInteger之类)。我那个朋友8个缓冲区里有3个是早期调试留下的,根本没画线,纯占内存。
- 把仅用于中间计算的缓冲区改成普通double数组。这是最关键的一步。很多人把中间变量也塞进缓冲区,其实完全没必要。缓冲区是给终端绘图和跨指标读取用的,纯中间结果用普通数组或者直接局部变量就行,SetIndexBuffer的数量直接砍到3个。
- 合并同向计算的缓冲区。原来他分了两个缓冲区分别存快线和慢线的差值,其实一个缓冲区存差值就够了,另一条线在OnCalculate里现算。
- 检查IndicatorBuffers的声明。这个坑我踩过——压缩了SetIndexBuffer数量,但IndicatorBuffers(8)忘了改,结果MT4还是按8个分配,白忙活。改成3之后内存占用和刷新频率才真正降下来。
改完之后在同样的VPS上跑,黄金M1图表从原来拖动一下卡半秒,变成基本跟手,刷新速度目测快了一倍不止。这里提醒一句,压缩缓冲区之后一定要重新跑一遍历史回测,确认指标数值和之前一致,尤其是那些被合并的中间计算,浮点精度偶尔会有细微差异,在黄金这种点值大的品种上,0.01的偏差都可能影响信号触发。
还有个细节:如果你的指标是被EA通过iCustom调用的,缓冲区数量变了之后,iCustom里的参数索引也要同步改,不然EA读到的就是错位的值。我那个朋友就是改完指标忘了改EA,实盘跑了两天才发现信号不对,好在是模拟仓。
其实MT4这套缓冲区机制挺老的,MT5的指标句柄模式在这方面灵活不少,但架不住现在还有大量EA和指标跑在MT4上。你们手头有没有那种开了五六个缓冲区、图表一卡就怪VPS的指标?可以贴出来一起看看能不能再砍两刀。
补充个小细节:压缩缓冲区时记得顺手把用不到的SetIndexStyle设成DRAW_NONE,不然MT4还是会分配内存去算,白忙活。
