凌晨快一点了,镑美M15刚收完一根,我这边EA日志又刷出一行报错,本来想直接关电脑,结果还是坐下来把这段数组排序的坑记一下,省得后面再翻旧账 😅
先说问题。上周改一个多货币对的信号汇总模块,本来想把EURUSD、GBPUSD、USDJPY这几个品种最近N根K线的ATR值塞进一个二维数组,按波动率从大到小排一遍,再决定给哪个品种分配仓位。结果代码跑起来,前几根数据看着正常,后面直接乱序,甚至有几行是0。查了半天才发现两个坑:一是ArrayResize之后没重新初始化,旧数据残留;二是排序循环里把ArraySize写在条件判断里,每次循环都重新算,边界一抖就越界了。
解决方案我按实操顺序列一下,都是我自己跑通的:
还有个细节,ArraySort默认是升序,我要波动率从大到小,就在排序后倒着遍历,或者对ATR值取负再排,看个人习惯。另外提醒一句,MQL4里ArrayCopy做数组间拷贝时,目标数组一定要先Resize到足够长度,否则只拷过去一部分,而且不报错,这个坑我吃了不止一次。
现在这套逻辑在VPS上跑了三个交易日,信号汇总没再出过乱序。你们平时处理多品种数据排序,是习惯用索引数组回查,还是直接上结构体数组?有更稳的写法贴出来交流。
先说问题。上周改一个多货币对的信号汇总模块,本来想把EURUSD、GBPUSD、USDJPY这几个品种最近N根K线的ATR值塞进一个二维数组,按波动率从大到小排一遍,再决定给哪个品种分配仓位。结果代码跑起来,前几根数据看着正常,后面直接乱序,甚至有几行是0。查了半天才发现两个坑:一是ArrayResize之后没重新初始化,旧数据残留;二是排序循环里把ArraySize写在条件判断里,每次循环都重新算,边界一抖就越界了。
解决方案我按实操顺序列一下,都是我自己跑通的:
- 第一步,声明数组时明确维度。比如double atrBuf[][2]; 第二维固定放“品种编号+ATR值”,别图省事用一维数组硬编码偏移,后面维护很痛苦。
- 第二步,用ArrayResize(atrBuf, count)扩容后,务必跟一句ArrayInitialize或者手动清零,尤其是EA在OnTick里反复调用的时候,残留数据会让排序结果完全失真。
- 第三步,排序别自己手写冒泡,直接上ArraySort对一维索引数组排,再按索引回查二维数据。我试过对二维数组直接排,MQL4对第二维的支持很有限,容易踩坑。
- 第四步,循环边界用int total = ArraySize(arr);先存成局部变量,循环里只引用total,别在for条件里反复调ArraySize,这点在回测里看不出问题,实盘Tick一密集就暴露。
还有个细节,ArraySort默认是升序,我要波动率从大到小,就在排序后倒着遍历,或者对ATR值取负再排,看个人习惯。另外提醒一句,MQL4里ArrayCopy做数组间拷贝时,目标数组一定要先Resize到足够长度,否则只拷过去一部分,而且不报错,这个坑我吃了不止一次。
现在这套逻辑在VPS上跑了三个交易日,信号汇总没再出过乱序。你们平时处理多品种数据排序,是习惯用索引数组回查,还是直接上结构体数组?有更稳的写法贴出来交流。
