通过注释确定代码中错误的方法
简介
本文介绍了在 MQL 代码中搜索错误的简单算法。由于代码错误导致的编译问题经常在编写程序后出现。错误类型可能各种各样,但无论如何,有必要快速识别发生错误的代码块。
通常,人们花费大量时间和精力搜索一些多余的括号。但是,有一种方法可以利用注释快速定位错误。这就是我要在本文讲述的方法。
概念
编写大段代码而不出现错误自然很好。但不幸的是这并不经常出现。甚至有人笑称,不存在没有错误的程序。这里我所说的并非是导致代码执行错误的错误。而是导致无法编译的错误。
非常普遍的错误有:在复杂条件中插入一个多余括号、缺少括号、没有写冒号以及逗号(在声明变量时)等。通常我们可以在编译时立即看出哪一个条目包含错误。但有时候没那么容易发现这种错误。无论是编译器还是好眼力都无法帮我们立即发现错误。在这种情况下,编程新手(以及非新手)通常开始浏览所有代码,试图凭目力找出错误。屡次三番,精力耗尽,感叹道:“重新编写倒更容易一些”!
但是,跟其他编程语言一样,MQL 也提供了一个非常好的工具 - 注释。你可以用它“移除”、“禁用”一些代码部分。通常,这种评论用于插入注释,或禁用代码的未使用部分。评论也可以成功用于搜索错误。
搜索错误的算法
搜索错误通常用于确定发生错误的代码部分,然后在其中以目力搜索出错误。检查 5-10 条代码跟 100-150 条代码相比,“使用肉眼”显然更加容易和快捷。
使用注释可以使问题迎刃而解。首先,需要注释代码的一些不同部分(有时几乎是整个代码),将其“禁用”。然后从代码的那些部分移除注释。在对注释进行正常移除后,尝试编译代码。如果编译成功,说明错误不在这部分代码内。然后打开另一部分代码,以此类推。当发现代码的问题部分后,进行目力找出并纠正。再次尝试进行编译。如果一切成功通过,说明错误已经消除。
如果出现新错误,则重复以上步骤直到错误完全消除。该方法在编写大型程序时非常有用,在编写相对较小的代码时较少使用。
正确的确定要注释的代码块非常重要。如果它是一个条件(或另一个逻辑结构),则应该完全注释。如果注释了声明变量的代码块,则注意务必闭合涉及这些变量的代码块。也就是说注释应该按照编程逻辑使用。违反该方式将导致编译时出现新的误报错误。
示例
我将以在代码中实际搜索错误为例。假设我们有以下代码:
#property copyright "" #property link "" extern int Level1=6; extern int Level2=2; extern double Lots=0.1; extern int TP=7; extern int SL=5000; extern int Profit_stop=10; int start() { //+--------------------------------------------------------------------------------------------------+ //| search for opened orders by symbol int pos_sell=0; for (int i_op_sell=OrdersTotal()-1; i_op_sell>=0; i_op_sell--) { if (!OrderSelect(i_op_sell,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_SELLSTOP||OrderType()==OP_SELL) &&(OrderComment()=="sar_ao")) { pos_sell=1; break; } } int pos_buy=0; for (int i_op_buy=OrdersTotal()-1; i_op_buy>=0; i_op_buy--) { if (!OrderSelect(i_op_buy,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_BUYSTOP||OrderType()==OP_BUY) &&(OrderComment()=="sar_ao")) { pos_buy=1; break; } } //| search for opened orders by symbol | //+-------------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------------+ //| stop for break-even double stop_open; for (int ia=OrdersTotal()-1; ia>=0; ia--) { if (!OrderSelect(ia,SELECT_BY_POS,MODE_TRADES)) break; if ((OrderType()==OP_BUY)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (NormalizeDouble(Bid,Digits)-stop_open<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } if ((OrderType()==OP_SELL)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (stop_open-NormalizeDouble(Ask,Digits)<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } } //| stop for break-even | //+-------------------------------------------------------------------------------------------------+ int i; bool trend_UP=true,trend_DOWN=true; //+------------------------------------------------------------------------------- if(!pos_buy) { for(i=Level1; i>=0; i--) { if(Open[i]<iSAR(NULL,0,0.02,0.1,i)) { trend_UP=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_UP=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_UP=false; break; } } } } else { trend_UP=false; } //*************************************************************************** if(!pos_sell) { for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } } } else { trend_DOWN=false; } if(Open[0]>iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("sell"); } if(Open[0]<iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("buy"); } double MA_1; MA_1=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); if(trend_UP && MA_1<50 && Open[1]<Close[1] && !pos_buy && ObjectFind("buy") != 0) { OrderSend(Symbol(),OP_BUY, Lots,Ask,2,Ask-SL*Point,Ask+TP*Point,"sar_ao",0,0,Blue); ObjectCreate("buy", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("buy", OBJPROP_STYLE, STYLE_DOT); ObjectSet("buy", OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet("buy", OBJPROP_COLOR, LightSeaGreen); } if(trend_DOWN && MA_1>50 && Open[1]>Close[1] && !pos_sell && ObjectFind("sell") != 0) { OrderSend(Symbol(),OP_SELL, Lots,Bid,2,Bid+SL*Point,Bid-TP*Point,"sar_ao",0,0,Red); ObjectCreate("sell", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("sell", OBJPROP_STYLE, STYLE_DOT); ObjectSet("sell", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet("sell", OBJPROP_COLOR, Red); } //+------------------------------------------------------------------------------- //---- return(0); } //+------------------------------------------------------------------+
在编译时我们发现了以下错误信息:
无法快速检测到发生错误的代码块。我们求助于注释。对所有逻辑结构进行注释:
#property copyright "" #property link "" extern int Level1=6; extern int Level2=2; extern double Lots=0.1; extern int TP=7; extern int SL=5000; extern int Profit_stop=10; int start() { /* //+-----------------------------------------------------------------------------------------------+ //| search for opened orders by symbol | int pos_sell=0; for (int i_op_sell=OrdersTotal()-1; i_op_sell>=0; i_op_sell--) { if (!OrderSelect(i_op_sell,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_SELLSTOP||OrderType()==OP_SELL) &&(OrderComment()=="sar_ao")) { pos_sell=1; break; } } int pos_buy=0; for (int i_op_buy=OrdersTotal()-1; i_op_buy>=0; i_op_buy--) { if (!OrderSelect(i_op_buy,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_BUYSTOP||OrderType()==OP_BUY) &&(OrderComment()=="sar_ao")) { pos_buy=1; break; } } //| search for opened orders by symbol | //+----------------------------------------------------------------------------------------------+ */ /* //+----------------------------------------------------------------------------------------------+ //| stop for break-even | double stop_open; for (int ia=OrdersTotal()-1; ia>=0; ia--) { if (!OrderSelect(ia,SELECT_BY_POS,MODE_TRADES)) break; if ((OrderType()==OP_BUY)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (NormalizeDouble(Bid,Digits)-stop_open<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } if ((OrderType()==OP_SELL)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (stop_open-NormalizeDouble(Ask,Digits)<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } } //| stop for break-even | //+---------------------------------------------------------------------------------------------+ */ /* int i; bool trend_UP=true,trend_DOWN=true; //+------------------------------------------------------------------------------- if(!pos_buy) { for(i=Level1; i>=0; i--) { if(Open[i]<iSAR(NULL,0,0.02,0.1,i)) { trend_UP=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_UP=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_UP=false; break; } } } } else { trend_UP=false; } */ //*************************************************************************** /* if(!pos_sell) { for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } } } else { trend_DOWN=false; } */ /* if(Open[0]>iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("sell"); } if(Open[0]<iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("buy"); } */ double MA_1; MA_1=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); /* if(trend_UP && MA_1<50 && Open[1]<Close[1] && !pos_buy && ObjectFind("buy") != 0) { OrderSend(Symbol(),OP_BUY, Lots,Ask,2,Ask-SL*Point,Ask+TP*Point,"sar_ao",0,0,Blue); ObjectCreate("buy", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("buy", OBJPROP_STYLE, STYLE_DOT); ObjectSet("buy", OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet("buy", OBJPROP_COLOR, LightSeaGreen); } */ /* if(trend_DOWN && MA_1>50 && Open[1]>Close[1] && !pos_sell && ObjectFind("sell") != 0) { OrderSend(Symbol(),OP_SELL, Lots,Bid,2,Bid+SL*Point,Bid-TP*Point,"sar_ao",0,0,Red); ObjectCreate("sell", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("sell", OBJPROP_STYLE, STYLE_DOT); ObjectSet("sell", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet("sell", OBJPROP_COLOR, Red); } */ //+------------------------------------------------------------------------------- //---- return(0); } //+------------------------------------------------------------------+
你可以轻松确保该代码可以毫无问题的编译。这意味着发生错误的代码部分被“隐藏”了。轮流打开代码 /* ...*/ 的部分并尝试编译。
直到下面的代码块之前,编译都很成功:
//*************************************************************************** if(!pos_sell) { for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } } } else { trend_DOWN=false; }
因此,错误位于该逻辑结构内。在对该代码部分进行详细检查后,我们可以看到结构内有多余的圆括号:
for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } }
如果将其移除,就可以成功编译代码。
通过移除剩余的注释,就可以确定代码中没有其他错误了。说明我们实现了目标 - 即快速找出代码中的错误。
总结
通过一个实际示例演示了如何使用该算法来搜索错误。本例中使用的代码并不小(194 条),所以其“调查”要花费一些时间。当遇到搜索错误的问题时,注释的可能性本身就为程序员节省了大量时间。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1547