MQL5循环数组越界求助:计算资产收益率时触发数组越界错误
首先看你遇到的array out of range错误,根源在Returns函数的循环逻辑和Series模式下的数组索引匹配问题,咱们一步步拆解:
错误原因分析
循环边界越界
你设置的循环是for(int i=1;i<=a_size;i++),而rates数组的大小是a_size(比如传入的100)。因为你给rates开启了ArraySetAsSeries(true),数组索引范围是0到a_size-1(也就是0到99)。当i=a_size时,访问rt[a_size]就会超出数组的最大索引,触发越界错误。Series模式下的索引逻辑混淆
开启Series模式后,数组的0索引对应最新的K线数据,而你原来的计算rt[i].close/rt[i-1].close在i=1时,rt[0]是最新K线,rt[1]是前一根,逻辑是反的;更关键的是,你给rtacao也开启了Series模式,但循环从i=1开始赋值,会直接跳过rtacao[0],同时当i达到a_size-1时,rtacao[i]会超出它的数组范围(因为rtacao的大小是a_size-1,索引范围是0到a_size-2)。局部变量的无用性
额外提一句:rtacao是Returns函数的局部变量,函数执行完就会被销毁,你计算的收益率根本无法在OnStart中使用,这也是一个需要修正的点。
修正后的代码
第一步:修复Returns函数
我们调整循环逻辑,匹配Series模式的索引,同时把rtacao作为参数传入(方便外部获取计算结果):
void Returns(MqlRates &rt[], int a_size, double &rtacao[]) { ArraySetAsSeries(rtacao, true); // 100根K线对应99个收益率,所以数组大小设为a_size-1 ArrayResize(rtacao, a_size - 1); // 循环从0到a_size-2,共a_size-1次迭代 for(int i = 0; i < a_size - 1; i++) { // Series模式下,rt[i]是最新的第i根K线,rt[i+1]是它的前一根(更早的) rtacao[i] = MathLog(rt[i].close / rt[i+1].close); } }
第二步:修改OnStart中的调用
在OnStart里,需要提前声明rtacao数组,传入Returns函数来获取结果:
void OnStart() { int nacoes=144; string acao[]; count_instr("ativos.txt",nacoes); ArrayResize(acao,nacoes); load_instr("ativos.txt",nacoes,acao,100); MqlRates rates[]; ArraySetAsSeries(rates,true); ArrayResize (rates,100); // 声明收益率数组,用于接收每个资产的计算结果 double rtacao[]; for (int i=0;i<nacoes;i++) { SymbolSelect(acao[i],true); if(CopyRates(acao[i],APeriod,0,100,rates)!=100) { Print("CopyRates of ",acao[i]," failed, no history"); //Erase(acao, i); //nacoes=nacoes-1; } else { // 传入rtacao数组获取收益率结果 Returns(rates, 100, rtacao); // 这里可以添加代码使用rtacao,比如打印或存储 Print("收益率数组大小:", ArraySize(rtacao)); } } }
关键修改点说明
- 循环范围改为
i从0到a_size-2:确保只访问rates数组的有效索引(0到99),同时给rtacao的每个索引(0到98)都赋值,不会越界。 - 调整收益率计算的K线索引:在Series模式下,用
rt[i].close / rt[i+1].close计算当前K线相对于前一根的对数收益率,逻辑更准确。 - 将
rtacao作为参数传入:解决局部变量无法传递结果的问题,让你在OnStart中可以使用计算好的收益率数据。
内容的提问来源于stack exchange,提问作者Maverick13




