Que testes deve passar o robô de negociação antes da publicação no Mercado
Por que os produtos são verificados antes de serem publicados no Mercado
Todos os produtos do Mercado, antes de serem publicados, passam uma revisão preliminar obrigatória, visto que um pequeno erro na lógica do conselheiro ou indicador pode causar perdas na conta de negociação. É por isso que temos desenvolvido uma série de verificações básicas para assegurar o nível de qualidade exigido pelos produtos do Mercado.
- Como capturar rapidamente e corrigir erros no robô de negociação
- Falta de fundos para negociar
- Volumes incorretos nas operações de negociação
- Restrição no número de ordens pendentes
- Restrição no número de lotes num símbolo
- Definindo os níveis TakeProfit e StopLoss nos limites do nível mínimo SYMBOL_TRADE_STOPS_LEVEL
- Tentativa de modificar a ordem ou posição nos limites do nível do congelamento SYMBOL_TRADE_FREEZE_LEVEL
- Erros que ocorrem quando se trabalha com símbolos nos quais o histórico de cotações é insuficiente
- Saída além dos limites da matriz (array out of range)
- Divisão por zero (zero divide)
- Envio de um pedido para modificar os níveis sem serem alterados na realidade
- Tentativa de importar arquivos compilados (mesmo EX4/EX5) e DLL
- Acessando indicadores personalizados via iCustom()
- Passando um parâmetro inválido para a função (erro de tempo de execução)
- Access violation
- Consumo de recursos da CPU e da memória
- Artigos relacionados recomendados
Se, no processo de verificação do seu produto, os moderadores do Mercado identificarem erros, você terá que corrigi-los. Neste artigo vamos falar sobre os erros mais freqüentes cometido pelos desenvolvedores nos seus robôs de negociação e indicadores técnicos. Também recomendamos que você leia os seguintes artigos:
- Como escrever uma boa descrição para um produto do mercado
- Dicas para uma apresentação eficaz do produto no mercado
Como capturar rapidamente e corrigir erros no robô de negociação
O testador de estratégias embutido na plataforma permite não só verificar com base no histórico dos sistemas de negociação, mas também identificar erros lógicos e algorítmicos, ao escrever o robô de negociação. Durante o teste, todas as mensagens sobre as operações de negociação e erros detetados são exibidos no Diário do testador. Você pode analisar convenientemente essas mensagens no Visualizador de entradas, que é chamado a partir do menu de contexto.
Após o teste do conselheiro, abra o Visualizador e ative o modo "Apenas erros", como é exibido na imagem. Se no seu robô de negociação houver erros, você vai vê-los imediatamente. Se não tiverem sido encontrados erros da primeira vez, realize uma série de testes, mudando os instrumentos/timeframes/parâmetros de entrada e diferentes valores para o depósito inicial. 99% dos erros são identificados usando estas técnicas simples, saiba sobre eles neste artigo.
Para um estudo detalhado dos erros detetados, use, no MetaEditor, a Depuração no histórico, assim, no modo de teste visual, você poderá observar não só os gráficos de preços e valores dos indicadores utilizados, mas também seguir, em cada tick, os valores de cada variável do programa. Isso permite que você depure a sua negociação sem ter que perder toda uma semana no modo de tempo real.
Falta de fundos para negociar
Antes de enviar cada pedido de negociação, é necessário verificar a quantidade de fundos na sua conta. A falta de fundos para fornecer a seguinte posição aberta ou ordem é considerada um erro crasso.
Leve em conta que inclusive colocar uma ordem pendente pode exigir uma garantia, isto é, a margem.
Recomendamos testar o seu robô de negociação com um depósito inicial deliberadamente pequeno, por exemplo, 1 USD ou 1 Euro.
Se a verificação mostrar que os fundos para a realização da operação de negociação não são suficientes, será necessário, em vez de chamar a função OrderSend(), emitir, no diário, uma mensagem de erro. Exemplos de verificação:
MQL5
bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type) { //--- obtemos o preço de abertura MqlTick mqltick; SymbolInfoTick(symb,mqltick); double price=mqltick.ask; if(type==ORDER_TYPE_SELL) price=mqltick.bid; //--- valores da margem necessária e livre double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE); //--- chamamos a função de verificação if(!OrderCalcMargin(type,symb,lots,price,margin)) { //--- algo deu errado, informamos e retornamos false Print("Error in ",__FUNCTION__," code=",GetLastError()); return(false); } //--- se não houver fundos suficientes para realizar a operação if(margin>free_margin) { //--- informamos sobre o erro e retornamos false Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError()); return(false); } //--- a verificação foi realizada com sucesso return(true); }
MQL4
bool CheckMoneyForTrade(string symb, double lots,int type) { double free_margin=AccountFreeMarginCheck(symb,type,lots); //-- se não houver dinheiro suficiente if(free_margin<0) { string oper=(type==OP_BUY)? "Buy":"Sell"; Print("Not enough money for ", oper," ",lots, " ", symb, " Error code=",GetLastError()); return(false); } //--- a verificação foi realizada com sucesso return(true); }
Volumes incorretos nas operações de negociação
Antes de enviar os pedidos de negociação, é necessário verificar a validez dos volumes indicados na ordem. Antes de chamar a função OrderSend(), é preciso verificar a quantidade de lotes que vai indicar na ordem do conselheiro. Para instrumentos financeiros, nas Especificações, são indicados os volumes mínimo e máximo permitidos para negociar, bem como gradação do volume. Na MQL5, é possível obter estes valores a partir da enumeração ENUM_SYMBOL_INFO_DOUBLE usando a função SymbolInfoDouble()
SYMBOL_VOLUME_MIN | Volume mínimo para realização da transação |
SYMBOL_VOLUME_MAX | Volume máximo para realização da transação |
SYMBOL_VOLUME_STEP | Incremento mínimo de alteração do volume para o realização da transação |
Exemplo de função para verificar a validez do volume
//+------------------------------------------------------------------+ //| Verifica a validez do volume da ordem | //+------------------------------------------------------------------+ bool CheckVolumeValue(double volume,string &description) { //--- valor mínimo permitido para operações de negociação double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN); if(volume<min_volume) { description=StringFormat("Volume inferior ao mínimo permitido SYMBOL_VOLUME_MIN=%.2f",min_volume); return(false); } //--- volume máximo permitido para operações de negociação double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); if(volume>max_volume) { description=StringFormat("Volume superior ao máximo permitido SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); } //--- obtemos a gradação mínima do volume double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP); int ratio=(int)MathRound(volume/volume_step); if(MathAbs(ratio*volume_step-volume)>0.0000001) { description=StringFormat("O volume não é múltiplo da gradação mínima SYMBOL_VOLUME_STEP=%.2f, volume mais próximo do valido %.2f", volume_step,ratio*volume_step); return(false); } description="Valor válido do volume"; return(true); }
Restrição no número de ordens pendentes
Existe também uma restrição no número de ordens pendentes que podem ser colocadas, simultaneamente, nessa conta. Exemplo da função IsNewOrderAllowed(), ela verifica se é possível colocar mais uma ordem pendente.
//+------------------------------------------------------------------+ //| verifica se é possível colocar mais uma ordem pendente | //+------------------------------------------------------------------+ bool IsNewOrderAllowed() { //--- obtemos o número de ordens pendentes permitidas na conta int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); //--- se não houver restrição, retornamos true, e poderemos enviar a ordem if(max_allowed_orders==0) return(true); //--- se chegamos até esta linha, significa que existe restrição; ficamos sabendo quantas ordens foram colocadas int orders=OrdersTotal(); //--- retornamos o resultado da comparação return(orders<max_allowed_orders); }A função é simples: na variável max_allowed_orders obtemos o número permitido de ordens pendentes, e se esse valor for diferente do zero, então comparamos com o número atual de ordens. Na verdade, com esta função não levamos em conta mais uma possibilidade de restrição, isto é, o conjunto do volume permitido da posição aberta e das ordens pendentes de acordo com um símbolo em concreto.
Restrição no número de lotes num símbolo
Para obter o tamanho do volume de uma posição aberta no símbolo definido, é necessário previamente selecionar a posição usando a função PositionSelect(). E só depois disso, pede-se o volume da posição selecionada usando a função PositionGetDouble(), que retorna as diferentes propriedades da posição selecionada e tem o tipo double. Para obter o volume da posição no símbolo, escrevemos a função PositionVolume().
//+------------------------------------------------------------------+ //| Retorna o valor da posição no símbolo indicado | //+------------------------------------------------------------------+ double PositionVolume(string symbol) { //--- tentamos selecionar a posição segundo o símbolo bool selected=PositionSelect(symbol); //--- a posição existe if(selected) //--- retornamos o volume da posição return(PositionGetDouble(POSITION_VOLUME)); else { //--- informamos sobre a tentativa vã de selecionar a posição Print(__FUNCTION__," Não foi possível executar PositionSelect() para o símbolo ", symbol," Erro ",GetLastError()); return(-1); } }
Para contas com cobertura, é preciso percorrer todas as posições nesse instrumento.
Antes de fazer o pedido de negociação, para a colocação da ordem pendente no símbolo, é necessário verificar a restrição do volume total para a posição aberta e ordens pendentes num símbolo, SYMBOL_VOLUME_LIMIT. Se não houver restrições, o volume para a ordem pendente não pode ultrapassar o o volume máximo definido, que pode ser obtido usando a função SymbolInfoDouble().
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT); if(max_volume==0) volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
Tal abordagem não tem em conta o volume nas atuais ordens pendentes no símbolo indicado. Pomos um exemplo para a função que calcula este valor:
//+------------------------------------------------------------------+ //| retorna o volume das ordens pendentes de acordo com o símbolo | //+------------------------------------------------------------------+ double PendingsVolume(string symbol) { double volume_on_symbol=0; ulong ticket; //--- obtemos o número de todas as ordens ativas em todos os símbolos int all_orders=OrdersTotal(); //--- passamos no ciclo de todas as ordens for(int i=0;i<all_orders;i++) { //--- obtemos o bilhete da ordem segundo sua posição na lista if(ticket=OrderGetTicket(i)) { //--- se na ordem especificado nosso símbolo, adicionamos o volume dessa ordem if(symbol==OrderGetString(ORDER_SYMBOL)) volume_on_symbol+=OrderGetDouble(ORDER_VOLUME_INITIAL); } } //--- retornamos o volume total das ordens pendentes atuais para o símbolo especificado return(volume_on_symbol); }
Tendo em conta o volume da posição aberta e o volume das ordens pendentes, a verificação final terá a seguinte aparência:
//+------------------------------------------------------------------+ //| Retorna o valor máximo permitido para a ordem no símbolo | //+------------------------------------------------------------------+ double NewOrderAllowedVolume(string symbol) { double allowed_volume=0; //--- obtemos a restrição do volume máximo na ordem double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); //--- obtemos a restrição do volume no símbolo double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT); //--- obtemos o volume da posição aberta no símbolo double opened_volume=PositionVolume(symbol); if(opened_volume>=0) { // --- se nós esgotamos o volume if(max_volume-opened_volume<=0) return(0); //--- o volume da posição aberta não excede o max_volume double orders_volume_on_symbol=PendingsVolume(symbol); allowed_volume=max_volume-opened_volume-orders_volume_on_symbol; if(allowed_volume>symbol_max_volume) allowed_volume=symbol_max_volume; } return(allowed_volume); }
Definindo os níveis TakeProfit e StopLoss nos limites do nível mínimo SYMBOL_TRADE_STOPS_LEVEL
Muitos conselheiros negociam com ordens TakeProfit e StopLoss, cujos níveis são calculados dinamicamente no momento da compra ou venda. A ordem TakeProfit serve para fechar a posição, quando o movimento do preço vai numa direção favorável, enquanto a ordem StopLoss é usada para restringir as perdas, quando o movimento do preço vai numa direção desfavorável
Portanto, é necessário comparar os níveis TakeProfit e StopLoss com o preço atual, com ajuda dele é possível negociar na direção oposta:
- A compra é realizada segundo o preço Ask, aqui é preciso comparar os níveis TakeProfit e StopLoss com o atual preço de venda Bid.
- A venda realiza-se segundo o preço Bid, aqui é preciso comparar os níveis TakeProfit e StopLoss com o atual preço de compra Ask.
A compra acontece segundo o preço Ask | A venda acontece segundo o preço Bid |
---|---|
TakeProfit >= Bid StopLoss <= Bid | TakeProfit <= Ask StopLoss >= Ask |
Para instrumentos financeiros, nas configurações do símbolo, é possível definir o parâmetro SYMBOL_TRADE_STOPS_LEVEL. Ele indica em pontos o recuo mínimo dos níveis StopLoss e TakeProfit a partir do preço atual para fechar a posição aberta. Se o valor dessa propriedade for igual a zero, isso significa que não foi estabelecido o recuo mínimo para ordens SL/TP ao comprar.
Em geral, a verificação dos níveis TakeProfit e StopLoss tendo em conta a distância mínima SYMBOL_TRADE_STOPS_LEVEL tem a seguinte aparência:
- A compra é realizada segundo o preço Ask, aqui os níveis TakeProfit e StopLoss devem estar a uma distância maior do que SYMBOL_TRADE_STOPS_LEVEL pontos a partir do preço atual de compra Bid.
- A venda é realizada segundo o preço Bid, aqui os níveis TakeProfit e StopLoss devem estar a uma distância maior do que SYMBOL_TRADE_STOPS_LEVEL pontos a partir do preço atual de venda Ask.
A compra acontece segundo o preço Ask | A venda acontece segundo o preço Bid |
---|---|
TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL |
É por isso que é possível criar uma função de verificação CheckStopLoss_Takeprofit(), ela exige que a distância entre o TakeProfit/StopLoss e o preço de fechamento seja maior do que SYMBOL_TRADE_STOPS_LEVEL pontos:
bool CheckStopLoss_Takeprofit(ENUM_ORDER_TYPE type,double SL,double TP) { //--- obtemos o nível SYMBOL_TRADE_STOPS_LEVEL int stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); if(stops_level!=0) { PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: StopLoss e TakeProfit devem ser"+ " pelo menos %d pontos a partir do preço de fechamento",stops_level,stops_level); } //--- bool SL_check=false,TP_check=false; //--- verificamos apenas dos tipos de ordens switch(type) { //--- operação de compra case ORDER_TYPE_BUY: { //--- verificamos o StopLoss SL_check=(Bid-SL>stops_level*_Point); if(!SL_check) PrintFormat("For order %s StopLoss=%.5f must be less than %.5f"+ " (Bid=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d pontos)", EnumToString(type),SL,Bid-stops_level*_Point,Bid,stops_level); //--- verificamos o TakeProfit TP_check=(TP-Bid>stops_level*_Point); if(!TP_check) PrintFormat("For order %s TakeProfit=%.5f must be greater than %.5f"+ " (Bid=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d pontos)", EnumToString(type),TP,Bid+stops_level*_Point,Bid,stops_level); //--- retornamos o resultado da verificação return(SL_check&&TP_check); } //--- operação de venda case ORDER_TYPE_SELL: { //--- verificamos o StopLoss SL_check=(SL-Ask>stops_level*_Point); if(!SL_check) PrintFormat("For order %s StopLoss=%.5f must be greater than %.5f "+ " (Ask=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d пунктов)", EnumToString(type),SL,Ask+stops_level*_Point,Ask,stops_level); //--- verificamos o TakeProfit TP_check=(Ask-TP>stops_level*_Point); if(!TP_check) PrintFormat("For order %s TakeProfit=%.5f must be less than %.5f "+ " (Ask=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d pontos)", EnumToString(type),TP,Ask-stops_level*_Point,Ask,stops_level); //--- retornamos o resultado da verificação return(TP_check&&SL_check); } break; } //--- para ordens pendentes é necessário utilizar uma função ligeiramente diferente return false; }
A verificação pode ter esta aparência:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- obtemos de modo aleatório o tipo de operação int oper=(int)(GetTickCount()%2); // o resto da divisão por dois é sempre 0 ou 1 switch(oper) { //--- compramos case 0: { //--- obtemos o preço de abertura e definimos deliberadamente os TP/SL incorretos double price=Ask; double SL=NormalizeDouble(Bid+2*_Point,_Digits); double TP=NormalizeDouble(Bid-2*_Point,_Digits); //--- fazemos a verificação PrintFormat("Buy at %.5f SL=%.5f TP=%.5f Bid=%.5f",price,SL,TP,Bid); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_BUY,SL,TP)) Print("Nível StopLoss ou TakeProfit inválido!"); //--- de qualquer modo, só tentamos comprar para ver o resultado da execução Buy(price,SL,TP); } break; //--- vendemos case 1: { //--- obtemos o preço de abertura e definimos deliberadamente os TP/SL incorretos double price=Bid; double SL=NormalizeDouble(Ask-2*_Point,_Digits); double TP=NormalizeDouble(Ask+2*_Point,_Digits); //--- fazemos a verificação PrintFormat("Sell at %.5f SL=%.5f TP=%.5f Ask=%.5f",price,SL,TP,Ask); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_SELL,SL,TP)) Print("Nível StopLoss ou TakeProfit inválido!"); //--- de qualquer modo, só tentamos vender para ver o resultado da execução Sell(price,SL,TP); } break; //--- } }
Encontre outro exemplo de função nos scripts anexados Check_TP_and_SL.mq4 e Check_TP_and_SL.mq5. Exemplo de execução:
MQL5 Check_TP_and_SL (EURUSD,H1) Buy at 1.11433 SL=1.11425 TP=1.11421 Bid=1.11423 Check_TP_and_SL (EURUSD,H1) SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss e TakeProfit não devem ser mais próximos do que 30 pontos a partir do preço de fechamento Check_TP_and_SL (EURUSD,H1) Para a ordem ORDER_TYPE_BUY StopLoss=1.11425 deve ser inferior a 1.11393 (Bid=1.11423 - SYMBOL_TRADE_STOPS_LEVEL=30 pontos) Check_TP_and_SL (EURUSD,H1) Para a ordem ORDER_TYPE_BUY TakeProfit=1.11421 deve ser superior a 1.11453 (Bid=1.11423 + SYMBOL_TRADE_STOPS_LEVEL=30 pontos) Check_TP_and_SL (EURUSD,H1) Nível StopLoss ou TakeProfit inválido! Check_TP_and_SL (EURUSD,H1) OrderSend error 4756 Check_TP_and_SL (EURUSD,H1) retcode=10016 deal=0 order=0 MQL4 Check_TP_and_SL EURUSD,H1: Sell at 1.11430 SL=1.11445 TP=1.11449 Ask=1.11447 Check_TP_and_SL EURUSD,H1: SYMBOL_TRADE_STOPS_LEVEL=1: o StopLoss e TakeProfit não devem ser mais próximos do que 1 pontos a partir do preço de fechamento Check_TP_and_SL EURUSD,H1: Para a ordem ORDER_TYPE_SELL StopLoss=1.11445 deve ser superior a 1.11448 (Ask=1.11447 + SYMBOL_TRADE_STOPS_LEVEL=1 pontos) Check_TP_and_SL EURUSD,H1: Para a ordem ORDER_TYPE_SELL TakeProfit=1.11449 deve ser inferior a 1.11446 (Ask=1.11447 - SYMBOL_TRADE_STOPS_LEVEL=1 pontos) Check_TP_and_SL EURUSD,H1: Nível StopLoss ou TakeProfit inválido! Check_TP_and_SL EURUSD,H1: OrderSend error 130
Para simular a situação com os valores inválidos TakeProfit e StopLoss, ao artigo foram anexados os conselheirosTest_Wrong_TakeProfit_LEVEL.mq5 e Test_Wrong_StopLoss_LEVEL.mq5. Apenas é possível executá-los na conta demo. Estude estes exemplos para ver por si mesmo sob quais condições é possível realizar uma compra com sucesso.
Exemplo de execução do conselheiro Test_Wrong_StopLoss_LEVEL.mq5:
Test_Wrong_StopLoss_LEVEL.mq5 Point=0.00001 Digits=5 SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT SYMBOL_TRADE_FREEZE_LEVEL=20: está proibido alterar a ordem ou posição, se ficarem 20 pontos antes do preço de ativação SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss e TakeProfit não devem ser mais próximos do que 30 pontos a partir do preço de fechamento 1. Buy 1.0 EURUSD at 1.11442 SL=1.11404 Bid=1.11430 ( StopLoss-Bid=-26 points )) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11442 sl: 1.11404 [invalid stops] 2. Buy 1.0 EURUSD at 1.11442 SL=1.11404 Bid=1.11431 ( StopLoss-Bid=-27 points )) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11442 sl: 1.11404 [invalid stops] 3. Buy 1.0 EURUSD at 1.11442 SL=1.11402 Bid=1.11430 ( StopLoss-Bid=-28 points )) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11442 sl: 1.11402 [invalid stops] 4. Buy 1.0 EURUSD at 1.11440 SL=1.11399 Bid=1.11428 ( StopLoss-Bid=-29 points )) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11440 sl: 1.11399 [invalid stops] 5. Buy 1.0 EURUSD at 1.11439 SL=1.11398 Bid=1.11428 ( StopLoss-Bid=-30 points )) Buy 1.0 EURUSD done at 1.11439 with StopLoss=41 points (spread=12 + SYMBOL_TRADE_STOPS_LEVEL=30)
Exemplo de execução do conselheiro Test_Wrong_TakeProfit_LEVEL.mq5:
Test_Wrong_TakeProfit_LEVEL.mq5 Point=0.00001 Digits=5 SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT SYMBOL_TRADE_FREEZE_LEVEL=20: está proibido alterar a ordem ou posição, se ficarem 20 pontos antes do preço de ativação SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss e TakeProfit não devem ser mais próximos do que 30 pontos a partir do preço de fechamento 1. Buy 1.0 EURUSD at 1.11461 TP=1.11478 Bid=1.11452 (TakeProfit-Bid=26 points) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11478 [invalid stops] 2. Buy 1.0 EURUSD at 1.11461 TP=1.11479 Bid=1.11452 (TakeProfit-Bid=27 points) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11479 [invalid stops] 3. Buy 1.0 EURUSD at 1.11461 TP=1.11480 Bid=1.11452 (TakeProfit-Bid=28 points) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11480 [invalid stops] 4. Buy 1.0 EURUSD at 1.11461 TP=1.11481 Bid=1.11452 (TakeProfit-Bid=29 points) CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11481 [invalid stops] 5. Buy 1.0 EURUSD at 1.11462 TP=1.11482 Bid=1.11452 (TakeProfit-Bid=30 points) Buy 1.0 EURUSD done at 1.11462 with TakeProfit=20 points (SYMBOL_TRADE_STOPS_LEVEL=30 - spread=10)
A verificação dos níveis StopLoss e TakeProfit nas ordens pendentes é muito mais simples, eles devem ser definidos com base no preço de abertura da ordem. Isto é, a verificação dos níveis tendo em conta a distância mínima SYMBOL_TRADE_STOPS_LEVEL tem a seguinte aparência: os níveis TakeProfit e StopLoss devem estar a uma distância maior do que SYMBOL_TRADE_STOPS_LEVEL pontos a partir do preço de ativação da ordem.
BuyLimit и BuyStop | SellLimit и SellStop |
---|---|
TakeProfit - Open >= SYMBOL_TRADE_STOPS_LEVEL Open - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | Open - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL StopLoss - Open >= SYMBOL_TRADE_STOPS_LEVEL |
No conselheiro Test_StopLoss_Level_in_PendingOrders.mq5 são feitas uma série de tentativas de instalar as ordens BuyStop e BuyLimt até que a operação seja bem sucedida. A cada tentativa, o nível StopLoss ou TakeProfit desloca-se 1 ponto na direção adequada. Exemplo de execução deste conselheiro:
Test_StopLoss_Level_in_PendingOrders.mq5 SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT SYMBOL_TRADE_FREEZE_LEVEL=20: está proibido alterar a ordem ou posição, se ficarem 20 pontos antes do preço de ativação SYMBOL_TRADE_STOPS_LEVEL=30: o StopLoss e TakeProfit não devem estar mais próximos do que 30 pontos a partir do preço de fechamento 1. BuyStop 1.0 EURUSD at 1.11019 SL=1.10993 (Open-StopLoss=26 points) CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11019 sl: 1.10993 [invalid stops] 2. BuyStop 1.0 EURUSD at 1.11019 SL=1.10992 (Open-StopLoss=27 points) CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11019 sl: 1.10992 [invalid stops] 3. BuyStop 1.0 EURUSD at 1.11020 SL=1.10992 (Open-StopLoss=28 points) CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11020 sl: 1.10992 [invalid stops] 4. BuyStop 1.0 EURUSD at 1.11021 SL=1.10992 (Open-StopLoss=29 points) CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11021 sl: 1.10992 [invalid stops] 5. BuyStop 1.0 EURUSD at 1.11021 SL=1.10991 (Open-StopLoss=30 points) BuyStop 1.0 EURUSD done at 1.11021 with StopLoss=1.10991 (SYMBOL_TRADE_STOPS_LEVEL=30) --------- 1. BuyLimit 1.0 EURUSD at 1.10621 TP=1.10647 (TakeProfit-Open=26 points) CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10621 tp: 1.10647 [invalid stops] 2. BuyLimit 1.0 EURUSD at 1.10621 TP=1.10648 (TakeProfit-Open=27 points) CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10621 tp: 1.10648 [invalid stops] 3. BuyLimit 1.0 EURUSD at 1.10621 TP=1.10649 (TakeProfit-Open=28 points) CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10621 tp: 1.10649 [invalid stops] 4. BuyLimit 1.0 EURUSD at 1.10619 TP=1.10648 (TakeProfit-Open=29 points) CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10619 tp: 1.10648 [invalid stops] 5. BuyLimit 1.0 EURUSD at 1.10619 TP=1.10649 (TakeProfit-Open=30 points) BuyLimit 1.0 EURUSD done at 1.10619 with TakeProfit=1.10649 (SYMBOL_TRADE_STOPS_LEVEL=30)
Os exemplos de verificação dos níveis TakeProfit e StopLoss nas ordens pendentes estão localizados nos códigos fonte anexados: Check_TP_and_SL.mq4 e Check_TP_and_SL.mq5.
Tentativa de modificar a ordem ou posição nos limites do nível do congelamento SYMBOL_TRADE_FREEZE_LEVEL
Nas configurações do símbolo, é possível definir o parâmetro SYMBOL_TRADE_FREEZE_LEVEL, ele mostra em pontos a distância de congelamento das operações de negociação para ordens pendentes e posições abertas. Por exemplo, se a negociação no instrumento financeiro é reencaminhada para o processamento num sistema de negociação externo, então, a ordem pendente BuyLimit pode, nesse momento, se localizar muito perto do preço Ask atual. E se nós enviarmos o pedido para alterar esta ordem quando o preço de abertura estiver suficientemente perto do preço Ask, então, pode suceder que a ordem seja executada e a modificação seja impossível.
Por isso, para ordens pendentes e posições abertas, nas configurações do símbolo, você pode indicar a distância de congelamento, em cujos limites é impossível de modificar. Em geral, antes de tentar enviar o pedido para realizar a modificação, é necessário levar a cabo uma verificação usando SYMBOL_TRADE_FREEZE_LEVEL:
Tipo de ordem/posição | Ativação segundo o preço | Verificação |
---|---|---|
Ordem Buy Limit | Ask | Ask-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL |
Ordem Buy Stop | Ask | OpenPrice-Ask >= SYMBOL_TRADE_FREEZE_LEVEL |
Ordem Sell Limit | Bid | OpenPrice-Bid >= SYMBOL_TRADE_FREEZE_LEVEL |
Ordem Sell Stop | Bid | Bid-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL |
Posição Buy | Bid | TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL Bid-StopLoss >= SYMBOL_TRADE_FREEZE_LEVEL |
Posição Sell | Ask | Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL StopLoss-Ask >= SYMBOL_TRADE_FREEZE_LEVEL |
Nos scripts anexados Check_FreezeLevel.mq5 e Check_FreezeLevel.mq4, você pode encontrar exemplos completos das funções para verificação de ordens e posições para o nível SYMBOL_TRADE_FREEZE_LEVEL.
//--- verificamos os tipos de ordem switch(type) { //--- ordem pendente BuyLimit case ORDER_TYPE_BUY_LIMIT: { //--- verificamos a distância a partir do preço de abertura para o preço de ativação check=((Ask-price)>freeze_level*_Point); if(!check) PrintFormat("Ordem %s #%d é impossível modificar: Ask-Open=%d pontos < SYMBOL_TRADE_FREEZE_LEVEL=%d pontos", EnumToString(type),ticket,(int)((Ask-price)/_Point),freeze_level); return(check); } //--- ordem pendente BuyLimit case ORDER_TYPE_SELL_LIMIT: { //--- verificamos a distância a partir do preço de abertura para o preço de ativação check=((price-Bid)>freeze_level*_Point); if(!check) PrintFormat("Ordem %s #%d é impossível modificar: Open-Bid=%d pontos < SYMBOL_TRADE_FREEZE_LEVEL=%d pontos", EnumToString(type),ticket,(int)((price-Bid)/_Point),freeze_level); return(check); } break; //--- ordem pendente BuyStop case ORDER_TYPE_BUY_STOP: { //--- verificamos a distância a partir do preço de abertura para o preço de ativação check=((price-Ask)>freeze_level*_Point); if(!check) PrintFormat("Ordem %s #%d é impossível modificar: Ask-Open=%d pontos < SYMBOL_TRADE_FREEZE_LEVEL=%d pontos", EnumToString(type),ticket,(int)((price-Ask)/_Point),freeze_level); return(check); } //--- ordem pendente SellStop case ORDER_TYPE_SELL_STOP: { //--- verificamos a distância a partir do preço de abertura para o preço de ativação check=((Bid-price)>freeze_level*_Point); if(!check) PrintFormat("Ordem %s #%d é impossível modificar: Bid-Open=%d pontos < SYMBOL_TRADE_FREEZE_LEVEL=%d pontos", EnumToString(type),ticket,(int)((Bid-price)/_Point),freeze_level); return(check); } break; }
Você pode simular por si mesmo a situação onde se tenta modificar uma ordem pendente dentro do nível de congelamento. Para fazer isso, abra uma conta demo na qual haja instrumentos financeiros com um nível zero SYMBOL_TRADE_FREEZE_LEVEL, execute o conselheiro Test_SYMBOL_TRADE_FREEZE_LEVEL.mq5 (Test_SYMBOL_TRADE_FREEZE_LEVEL.mq4) dentro do gráfico e instale manualmente qualquer ordem pendente. O próprio conselheiro aproxima a ordem ao preço do mercado tanto quanto for possível e começa a fazer tentativas proibidas de modificação. Isso irá executar o som usando a função PlaySound().
Erros que ocorrem quando se trabalha com símbolos nos quais o histórico de cotações é insuficiente
Se conselheiro ou indicador funciona num gráfico com um histórico em falta, então há duas opções:
- o programa verifica a presença do histórico exigido em toda a profundidade necessária. Se as barras disponíveis estiverem abaixo do exigido, o programa solicitará os dados ausentes e completará o seu trabalho antes da chegada do próximo tick. Este caminho é o mais correto e ajuda a evitar muitos erros, a saber: sair da matriz ou dividir por zero;
- o programa não faz verificação nenhuma e começa imediatamente o seu trabalho, como se todo o histórico, necessário para todos os símbolos e os timeframes, exigidos estivesse disponível mediante a primeira solicitação. Esta abordagem está cheia de erros imprevisíveis.
Você pode tentar por si mesmo simular essa situação. Para fazer isso, execute o indicador ou conselheiro que deseja testar no gráfico, feche o terminal e remova todo o histórico, finalmente, reinicie o terminal. Se, após essa reinicialização, não aparecerem erros nos Diários, em seguida, comece a mudar os símbolos e timeframes nos gráficos, nos quais o programa está em execução. Muitos dos indicadores dão erros ao executar nos timeframes semanais ou mensais para os quais o número de barras é geralmente limitada. Além disso, durante uma mudança brusca do símbolo do gráfico, por exemplo, de EURUSD para CADJPY, o indicador ou conselheiro executado no gráfico pode dar um erro causado pela falta do pagamento exigido para calcular o seu histórico.
Saída além dos limites da matriz (array out of range)
Ao trabalhar com matrizes, o acesso aos seus elementos é realizado de acordo com o número do índice, ele não pode ser negativo e deve ser menor do que o tamanho da matriz. Você pode obter o número da matriz usando a função ArraySize().
Este erro pode ocorrer ao trabalhar com a matriz dinâmica, quando o seu tamanho ainda não está definido claramente pela função ArrayResize(), ou ao utilizar essa matriz nas funções que definem de forma independe o tamanho das matrizes dinâmicas transferidas por ele. Por exemplo, a função CopyTicks() tenta armazenar na matriz a quantidade solicitada de ticks, mas, se houver menos ticks do que solicitou, o tamanho da matriz obtida será menor do que o esperado.
Outra forma, muito provável, para obter este erro, consiste numa tentativa de acessar os dados do buffer de indicador, quando o seu tamanho ainda não foi inicializado. Lembramos que os buffers de indicador são matrizes dinâmicos, e os seus tamanhos são estabelecidos pelo sistema de execução do terminal apenas após a inicialização do gráfico. Por tanto, por exemplo, a tentativa de acessar os dados desse buffer, na função OnInit(), causará o erro "array out of range".
Anexamos ao arquivo Test_Out_of_range.mq5 um exemplo simples do indicador que dá esse erro,
Divisão por zero (zero divide)
Outro erro crítico consiste em tentar dividir por zero. Neste caso, o programa pára imediatamente, o testador exibe no Diário o nome da função e o número da linha no código fonte onde ocorreu o erro.
Geralmente, a divisão por zero ocorre devido a uma situação imprevista pelo programador, por exemplo, receber uma propriedade ou cálculo da expressão com dados "ruins".
Você pode facilmente dividir por zero usando o conselheiro simples TestZeroDivide.mq5, cujo código fonte é exibido na capturas de tela. utro erro crítico consiste em usar um ponteiro do objeto inválido. A Depuração no histórico será útil para determinar a causa desse erro.
Envio de um pedido para modificar os níveis sem serem alterados na realidade
Se, de acordo com as regras do sistema de negociação, for necessário modificar as ordens pendentes ou as posições abertas, antes de enviar o pedido de negociação para realizar a transação, você deverá garantir que a operação solicitada realmente alterará os parâmetros da ordem ou posição. O envio do pedido de negociação que na verdade não faz alteração nenhuma é considerado como um erro. O servidor de negociação, em resposta a esta ação, retornará o código de resposta TRADE_RETCODE_NO_CHANGES=10025 (MQL5) ou o código ERR_NO_RESULT=1 (MQL4)
O exemplo de verificação para MQL5 está no script Check_OrderLevels.mq5:
//--- classe para negociação #include <Trade\Trade.mqh> CTrade trade; #include <Trade\Trade.mqh> //--- classe para trabalhar com ordens #include <Trade\OrderInfo.mqh> COrderInfo orderinfo; //--- classe para trabalhar com posições #include <Trade\PositionInfo.mqh> CPositionInfo positioninfo; //+------------------------------------------------------------------+ //| verificação de novos valores de níveis antes da modificação da ordem | //+------------------------------------------------------------------+ bool OrderModifyCheck(ulong ticket,double price,double sl,double tp) { //--- selecionamos uma ordem por bilhete if(orderinfo.Select(ticket)) { //--- O tamanho do ponto e nome do símbolo pelo qual foi colocada ordem pendente string symbol=orderinfo.Symbol(); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- verificamos se há mudança no preço de abertura bool PriceOpenChanged=(MathAbs(orderinfo.PriceOpen()-price)>point); //--- verificamos se há mudança no nível StopLoss bool StopLossChanged=(MathAbs(orderinfo.StopLoss()-sl)>point); //--- verificamos se há mudança no nível Takeprofit bool TakeProfitChanged=(MathAbs(orderinfo.TakeProfit()-tp)>point); //--- se houver quaisquer alterações nos níveis if(PriceOpenChanged || StopLossChanged || TakeProfitChanged) return(true); // é possível modificar a ordem //--- não há alterações nos níveis de abertura, StopLoss e Takeprofit else //--- informamos sobre o erro PrintFormat("A ordem #%d já tem níveis Open=%.5f SL=%.5f TP=%.5f", ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit()); } //--- chegamos ao fim, não há alterações para a ordem return(false); // não faz sentido nenhum modificar } //+------------------------------------------------------------------+ //| verificação de novos valores de níveis antes da modificação da ordem | //+------------------------------------------------------------------+ bool PositionModifyCheck(ulong ticket,double sl,double tp) { //--- selecionamos uma ordem por bilhete if(positioninfo.SelectByTicket(ticket)) { //--- O tamanho do ponto e nome do símbolo pelo qual foi colocada ordem pendente string symbol=positioninfo.Symbol(); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); //--- verificamos se há mudança no nível StopLoss bool StopLossChanged=(MathAbs(positioninfo.StopLoss()-sl)>point); //--- verificamos se há mudança no nível Takeprofit bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point); //--- se houver quaisquer alterações nos níveis if(StopLossChanged || TakeProfitChanged) return(true); // é possível modificar a ordem //--- não há alterações nos níveis StopLoss e Takeprofit else //--- informamos sobre o erro PrintFormat("A ordem #%d já tem níveis Open=%.5f SL=%.5f TP=%.5f", ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit()); } //--- chegamos ao fim, não há alterações para a ordem return(false); // não faz sentido nenhum modificar } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- níveis de preços para ordens e posições double priceopen,stoploss,takeprofit; //--- bilhete da ordem atual e posições ulong orderticket,positionticket; /* ... obtemos o bilhete da ordem e novos níveis StopLoss/TakeProfit/Priceopen */ //--- verificamos os níveis antes da modificação da ordem pendente if(OrderModifyCheck(orderticket,priceopen,stoploss,takeprofit)) { //--- a verificação foi realizada com sucesso trade.OrderModify(orderticket,priceopen,stoploss,takeprofit, orderinfo.TypeTime(),orderinfo.TimeExpiration()); } /* ... obtemos o bilhete da ordem e novos níveis StopLoss/TakeProfit */ //--- verificamos os níveis antes da modificação da posição if(PositionModifyCheck(positionticket,stoploss,takeprofit)) { //--- a verificação foi realizada com sucesso trade.PositionModify(positionticket,stoploss,takeprofit); } //--- }
O exemplo de verificação na linguagem MQL5 está no script Check_OrderLevels.mq4:
#property strict //+------------------------------------------------------------------+ //| verificação de novos valores de níveis antes da modificação da ordem | //+------------------------------------------------------------------+ bool OrderModifyCheck(int ticket,double price,double sl,double tp) { //--- selecionamos uma ordem por bilhete if(OrderSelect(ticket,SELECT_BY_TICKET)) { //--- O tamanho do ponto e nome do símbolo pelo qual foi colocada ordem pendente string symbol=OrderSymbol(); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); //--- verificamos se há mudança no preço de abertura bool PriceOpenChanged=true; int type=OrderType(); if(!(type==OP_BUY || type==OP_SELL)) { PriceOpenChanged=(MathAbs(OrderOpenPrice()-price)>point); } //--- verificamos se há mudança no nível StopLoss bool StopLossChanged=(MathAbs(OrderStopLoss()-sl)>point); //--- verificamos se há mudança no nível Takeprofit bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point); //--- se houver quaisquer alterações nos níveis if(PriceOpenChanged || StopLossChanged || TakeProfitChanged) return(true); // é possível modificar a ordem //--- não há alterações nos níveis de abertura, StopLoss e Takeprofit else //--- informamos sobre o erro PrintFormat("A ordem #%d já tem níveis Open=%.5f SL=%.5f TP=%.5f", ticket,OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit()); } //--- chegamos ao fim, não há alterações para a ordem return(false); // não faz sentido nenhum modificar } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- níveis de preços para ordens e posições double priceopen,stoploss,takeprofit; //--- bilhete da ordem atual int orderticket; /* ... obtemos o bilhete da ordem e novos níveis StopLoss/TakeProfit/Priceopen */ //--- verificamos os níveis antes da modificação da ordem if(OrderModifyCheck(orderticket,priceopen,stoploss,takeprofit)) { //--- a verificação foi realizada com sucesso OrderModify(orderticket,priceopen,stoploss,takeprofit,OrderExpiration()); } }
Também recomendamos ler o artigo:
- Como facilitar a detecção e recuperação de erros no código do expert advisor
- Como desenvolver no mql4 um robô de negociação seguro e confiável
Tentativa de importar arquivos compilados (mesmo EX4/EX5) e DLL
Os programas distribuídos através do Mercado devem ter uma garantia de segurança para os usuários. Por isso, qualquer tentativa de usar o DLL ou as funções de arquivos compilados EX4/EX5 é considerada como erro. Esse tipo de produtos não são publicados no Mercado.
Se o seu programa precisar indicadores adicionais que não estão à disposição, utilize os Recursos.
Acessando indicadores personalizados via iCustom()
Se o seu programa necessitar acessar os dados de um indicador personalizado, você precisará colocar todos os indicadores nos Recursos. Os produtos do Mercado devem estar preparados para trabalhar em qualquer ambiente despreparado, é por isso que devem conter tudo que você precisa no seu arquivo EX4/EX5. Artigos relacionados recomendados:
Passando um parâmetro inválido para a função (erro de tempo de execução)
Este tipo de erro é raro, muitos deles têm códigos prontos projetados para ajudar a encontrar a causa.
Constante | Valor | Descrição |
---|---|---|
ERR_INTERNAL_ERROR | 4001 | Erro interno inesperado |
ERR_WRONG_INTERNAL_PARAMETER | 4002 | Parâmetro não válido, ao chamar internamente as funções do terminal de cliente |
ERR_INVALID_PARAMETER | 4003 | Parâmetro errado, quando a função do sistema faz a chamada |
ERR_NOTIFICATION_WRONG_PARAMETER | 4516 | Parâmetro inválido para envio da notificação, uma linha vazia ou NULL foi passada para a função SendNotification() |
ERR_BUFFERS_WRONG_INDEX | 4602 | Índice errado do seu buffer de indicador |
ERR_INDICATOR_WRONG_PARAMETERS | 4808 | Número incorreto de parâmetros ao criar o indicador |
ERR_INDICATOR_PARAMETERS_MISSING | 4809 | Sem parâmetros ao criar o indicador |
ERR_INDICATOR_CUSTOM_NAME | 4810 | O primeiro parâmetro na matriz deve ser o nome do indicador personalizado |
ERR_INDICATOR_PARAMETER_TYPE | 4811 | Tipo de parâmetro errado na matriz ao criar o indicador |
ERR_NO_STRING_DATE | 5030 | Linha sem data |
ERR_WRONG_STRING_DATE | 5031 | Data errada na linha |
ERR_TOO_MANY_FORMATTERS | 5038 | Mais especificadores de formato do que parâmetros |
ERR_TOO_MANY_PARAMETERS | 5039 | Mais parâmetros do que especificadores de formato |
A tabela não lista todos os erros que podem ocorrer durante a execução do programa.
Access violation
Esse erro ocorre quando você tenta acessar uma memória que está restrita. Nestes casos, é necessário entrar em contato com os desenvolvedores através do Service Desk, via página de perfil ou usando Contatos. Uma descrição detalhada dos passos antes do erro acontecer e um anexo do código fonte acelerará significativamente a procura das causas deste erro e ajudará a melhorar o compilador de código fonte.
Consumo de recursos da CPU e da memória
Ao escrever o programa, é importante usar um algoritmo cujo tempo de execução seja ótimo, de outra forma, o trabalho de outros programas em execução seria difícil ou mesmo impossível, no terminal.
É importante lembrar que, na Observação do mercado, o terminal aloca um fluxo comum, no qual são processados todos os indicadores e gráficos para trabalhar com cada símbolo.
Isto significa que si você tem 5 gráficos abertos do par EURUSD em diferentes timeframes, e nestes gráficos há 15 indicadores em execução, todos estes indicadores recebem um único fluxo para cálculo e exibição de informações nos gráficos. É por isso que um indicador ineficiente ocupa muitos recursos, retardando o trabalho de outros indicadores e até congelando a exibição de preços nos outros gráficos deste símbolo.
Você pode verificar o tempo gasto pelo seu algoritmo usando a função GetMicrosecondCount(). Após medir o tempo entre as duas linhas do código, é fácil de obter o tempo de execução em microssegundos. Para converter em milissegundos (ms), é necessário dividir esse tempo por 1000 (1 milissegundo tem 1000 microssegundos). Para os indicadores, o lugar crítico no tempo de execução é geralmente o manipulador OnCalculate(). Normalmente, o primeiro cálculo do indicador é fortemente dependente do parâmetro Max. de barras na janela, indique nele o valor "Unlimited" e execute o seu indicador no símbolo com um histórico superior a 10 anos no timeframe M1. Se a primeira execução levar muito tempo (por exemplo, mais do que 100 ms), será necessário otimizar o código.
A seguir, um exemplo de como medir o tempo de execução do manipulador OnCalculate() no indicador ROC, que fornece na entrega padrão do terminal com código fonte. As inserções são destacadas em amarelo:
//+------------------------------------------------------------------+ //| Rate of Change | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[]) { //--- check for rates count if(rates_total<ExtRocPeriod) return(0); //--- hora de início dos cálculos ulong start=GetMicrosecondCount(); //--- preliminary calculations int pos=prev_calculated-1; // set calc position if(pos<ExtRocPeriod) pos=ExtRocPeriod; //--- the main loop of calculations for(int i=pos;i<rates_total && !IsStopped();i++) { if(price[i]==0.0) ExtRocBuffer[i]=0.0; else ExtRocBuffer[i]=(price[i]-price[i-ExtRocPeriod])/price[i]*100; } //--- hora final dos cálculos ulong finish=GetMicrosecondCount(); PrintFormat("Função %s em %s levou %.1f ms",__FUNCTION__,__FILE__,(finish-start)/1000.); //--- OnCalculate done. Return new prev_calculated. return(rates_total); }
A memória em uso pode ser medida usando a função MQLInfoInteger(MQL_MEMORY_USED). E, claro, use o Criador de perfil de código para encontrar as funções mais desvantajosas no seu programa. Também recomendamos ler os artigos Os princípios do cálculo econômico de indicadores e Depuração dos programas do mql5.
Os conselheiros trabalham nas suas próprias fontes, mas todo o dito acima é aplicado a eles. É necessário escrever um código ideal em todos os tipos de programas: conselheiros, indicadores, scripts e bibliotecas.
Não existe tal coisa como demasiadas verificações
Todas as anteriores dicas sobre a verificação de indicadores e conselheiros estão recomendadas não só para publicação de produtos no Mercado, mas também na prática diária, quando você escreve para si mesmo. Neste artigo, não examinamos todos os erros que podem ocorrer ao negociar em contas reais. Aqui, não são consideradas todas as regras para o processamento de erros de negociação que ocorrem durante a perda de conexão com o servidor de negociação, requotes, rejeições das transações e muitas outras coisas que podem perturbar as regras do sistema de negociação. Para estes casos, cada desenvolvedor de robôs tem as suas próprias receitas acumuladas pela experiência.
Também recomendamos que os novos leiam todos os artigos sobre o tratamento de erros e façam perguntas sobre no fórum e nos comentários deste artigo. Outros membros mais experientes da comunidade MQL5.community ajudarão a compreender as questões que ainda são confusas para você. Esperamos que as informações recolhidas no artigo seja úteis para você criar robôs de negociação mais confiáveis num curto período.
Artigos relacionados recomendados:
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2555
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso