![Qué comprobaciones debe superar un robot comercial antes de ser publicado en el Mercado](https://c.mql5.com/i/articles/overlay.png)
Qué comprobaciones debe superar un robot comercial antes de ser publicado en el Mercado
Por qué es necesaria la comprobación antes de publicar un producto en el Mercado
Todos los productos del Mercado deben superar una comprobación preliminar antes de su publicación, ya que un pequeño error en la lógica del asesor o indicador podría causar pérdidas en la cuenta comercial. Precisamente por ello, hemos desarrollado una serie de comprobaciones para garantizar que los productos del Mercado tengan el nivel necesario de calidad.
- Cómo detectar y corregir con rapidez los errores en un robot comercial
- Falta de recursos para realizar una operación comercial
- Volúmenes incorrectos en las operaciones comerciales
- Limitación en el número de órdenes pendientes
- Limitación en el número de lotes de un símbolo
- Establecer los niveles de TakeProfit y StopLoss dentro de los límites del nivel mínimo SYMBOL_TRADE_STOPS_LEVEL
- Intento de modificación de una orden o posición en los límites del nivel de congelamiento SYMBOL_TRADE_FREEZE_LEVEL
- Errores que surgen al trabajar con los símbolos con una historia de cotizaciones insuficiente
- Salida de los límites de la matriz (array out of range)
- División entre cero (zero divide)
- Envío de una solicitud de modificación de niveles sin cambiarlos de hecho
- Intento de importación de los archivos compilados (EX4/EX5 inclusive) y DLL
- Recurrir a los indicadores de usuario a través de iCustom()
- Transmisión de un parámetro no permitido a la función (error de tiempo de ejecución)
- Access violation
- Consumo de recursos del procesador y la memoria
- Artículos recomendados sobre el tema
Si los Moderadores detectan errores durante la comprobación de su producto, será ncecesario que usted los corrija. En este artículo hablaremos de los errores más frecuentes que cometen los desarrolladores en sus robots comerciales e indicadores técnicos. Asimismo, le recomendamos que lea los artículos siguientes:
- Cómo preparar la descripción de un producto para el Mercado
- ¿Cómo presentar correctamente un producto a la venta en el Mercado?
Cómo detectar y corregir con rapidez los errores en un robot comercial
El simulador de estrategias permite, no solo poner a prueba sistemas comerciales basándose en la historia, sino también detectar errores lógicos y algorítmicos cometidos al escribir el robot comercial. Durante la simulación, todos los mensajes sobre operaciones comerciales y errores detectados se muestran en el Registro del simulador. A la hora de analizarlos, estos mensajes se ven con facilidad en el Visor de archivos log, que se llama con el comando del menú contextual.
Abra el Visor después de la simulación del asesor y active el modo "Solo errores", como se muestra en la figura. Si en su robot comercial hay errores, los verá enseguida. Si los errores no han sido detectados a la primera, realice una serie de simulaciones cambiando los instrumentos/marcos temporales/parámetros de entrada y con diferentes valores de depósito inicial. El 99% de los errores se descubrirán con estos sencillos métodos, y será precisamente de ellos de los que hablaremos en este artículo.
Para estudiar detalladamente los errores detectados, use en el MetaEditor la Depuración en la historia, de esta forma, en el modo de simulación visual usted podrá observar no solo los gráficos de precio y los valores de los indicadores utilizados, sino también seguir los valores de cada variable del programa en cada tick. Esto le permitirá depurar su estrategia comercial sin necesidad de gastar semanas en el modo de tiempo real.
Falta de recursos para realizar una operación comercial
Antes de cada envío de una orden comercial, es necesario comprobar que los recursos en su cuenta sean suficientes. La insuficiencia de recursos para una futura posición u orden abierta se considera un error grave.
Tenga en cuenta que incluso para colocar una orden pendiente podría ser necesario proporcionar una fianza para el margen.
Recomendamos simular su robot comercial como prueba con un depósito inicial premeditadamente pequeño, por ejemplo, 1 USD o 1 Euro.
Si la prueba muestra que los recursos para ejecutar la operación comercial son insuficientes, en lugar de la llamada de la función OrderSend() se emitirá en el registro un mensaje de error. Ejemplos de comprobación:
MQL5
bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type) { //--- obtenemos el precio de apertura MqlTick mqltick; SymbolInfoTick(symb,mqltick); double price=mqltick.ask; if(type==ORDER_TYPE_SELL) price=mqltick.bid; //--- valores del margen libre imprescindible double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE); //--- llamamos a la función de comprobación if(!OrderCalcMargin(type,symb,lots,price,margin)) { //--- algo no ha salido bien, informamos y retornamos false Print("Error in ",__FUNCTION__," code=",GetLastError()); return(false); } //--- si los recursos para ejecutar una operación son insuficientes if(margin>free_margin) { //--- informamos sobre el error y retornamos false Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError()); return(false); } //--- la comprobación ha tenido éxito return(true); }
MQL4
bool CheckMoneyForTrade(string symb, double lots,int type) { double free_margin=AccountFreeMarginCheck(symb,type,lots); //-- si no hay dinero 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); } //-- la comprobación ha tenido éxito return(true); }
Volúmenes incorrectos en las operaciones comerciales
Antes de enviar órdenes comerciales también es necesario comprobar que los volúmenes indicados en la orden sean correctos. El número de lotes que tiene previsto indicar en la orden del asesor debe ser comprobado antes de llamar a la función OrderSend(). Para los instrumentos financieros en las Especificaciones se indican los volúmenes mínimos y máximos permitidos para el comercio, así como la gradación del volumen. Se pueden obtener estos valores en MQL5 de la enumeración ENUM_SYMBOL_INFO_DOUBLE con la ayuda de la función SymbolInfoDouble()
SYMBOL_VOLUME_MIN | Volumen mínimo para ejecutar una operación |
SYMBOL_VOLUME_MAX | Volumen máximo para ejecutar una operación |
SYMBOL_VOLUME_STEP | Salto mínimo del cambio de volumen para ejecutar una operación |
Ejemplo de una función para la comprobación de volumen correcto
//+------------------------------------------------------------------+ //| Comprobar si el volumen de una orden es correcto | //+------------------------------------------------------------------+ bool CheckVolumeValue(double volume,string &description) { //--- volumen mínimo permitido para las operaciones comerciales double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN); if(volume<min_volume) { description=StringFormat("El volumen es inferior al mínimo permitido SYMBOL_VOLUME_MIN=%.2f",min_volume); return(false); } //--- volumen máximo permitido para las operaciones comerciales double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); if(volume>max_volume) { description=StringFormat("El volumen es superior al máximo permitido SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); } //--- obtenemos la gradación mínima del volumen 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("El volumen no es múltiplo de la gradación mínima SYMBOL_VOLUME_STEP=%.2f, el volumen correcto más cercano es %.2f", volume_step,ratio*volume_step); return(false); } description="Valor correcto del volumen"; return(true); }
Limitación en el número de órdenes pendientes
Asimismo, existe una limitación en la cantidad de órdenes pendientes que pueden ser colocadas en esta cuenta. Ejemplo de la función IsNewOrderAllowed(), que comprueba si se puede colocar una orden pendiente más.
//+------------------------------------------------------------------+ //| comprueba si se puede colocar una orden pendiente más | //+------------------------------------------------------------------+ bool IsNewOrderAllowed() { //--- obtenemos el número de órdenes pendientes permitidas en la cuenta int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); //--- si no existe limitación, retornamos true, es posible enviar la orden if(max_allowed_orders==0) return(true); //--- si hemos llegado hasta este lugar, significa que hay limitaciones, vemos cuántas órdenes hay ya en acción int orders=OrdersTotal(); //--- retornamos el resultado de la comparación return(orders<max_allowed_orders); }La función es sencilla: en la varibale max_allowed_orders obtenemos la cantidad permitida de órdenes pendientes, y si este valor no es igual a cero, lo comparamos con el número actual de órdenes. Bien es cierto que con esta función no se tiene en cuenta una posible limitación: el volumen conjunto máximo permitido de la posición abierta y de las órdenes abiertas de un símbolo concreto.
Limitación en el número de lotes de un símbolo
Para obtener el tamaño del volumen de una posición abierta del símbolo establecido, es necesario elegir de antemano la posición con la ayuda de la función PositionSelect(). Y solo después de ello se podrá solicitar el volumen de la posición elegida con la ayuda de la función PositionGetDouble(), que retorna las diferentes propiedades de la posición elegida, que tengan el tipo double. Para obtener el volumen de la posición, escribiremos la función PositionVolume().
//+------------------------------------------------------------------+ //| Retorna el tamaño de la posición del símbolo indicado | //+------------------------------------------------------------------+ double PositionVolume(string symbol) { //--- probamos a elegir la posición del símbolo bool selected=PositionSelect(symbol); //--- la posición existe if(selected) //--- retornamos el volumen de la posición return(PositionGetDouble(POSITION_VOLUME)); else { //--- informamos sobre el intento fallido de elegir posición Print(__FUNCTION__," No se ha logrado ejecutar PositionSelect() para el símbolo ", symbol," Error ",GetLastError()); return(-1); } }
Para las cuentas con soporte de cobertura, hay que pasar por todas las posiciones en este instrumento.
Antes de hacer una solicitud comercial para colocar una orden pendiente de un símbolo, es necesario comprobar las limitaciones en el volumen conjunto para posiciones abiertas y órdenes pendientes de un símbolo, con SYMBOL_VOLUME_LIMIT. Si no existen limitaciones, entonces el volumen para la orden pendiente no podrá superar el volumen máximo establecido, que es posible obtener con la ayuda de la función SymbolInfoDouble().
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT); if(max_volume==0) volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
Pero este enfoque no tiene en cuenta el volumen en las órdenes pendientes actuales del símbolo indicado. Vamos a mostrar un ejemplo de una función que calcula este valor:
//+-------------------------------------------------------------------------------+ //| devuelve el volumen de las ordenes pendientes de acuerdo con el símbolo | //+-------------------------------------------------------------------------------+ double PendingsVolume(string symbol) { double volume_on_symbol=0; ulong ticket; //--- obtenemos el número de todas las ordenes activas en todos los símbolos int all_orders=OrdersTotal(); //--- pasamos por el ciclo de todas las ordenes for(int i=0;i<all_orders;i++) { //--- obtenemos o tícket de la orden de acurdo con su posición en la lista if(ticket=OrderGetTicket(i)) { //--- si está especificado nuestro símbolo en la orden, adicionamos el volumen de esta orden if(symbol==OrderGetString(ORDER_SYMBOL)) volume_on_symbol+=OrderGetDouble(ORDER_VOLUME_INITIAL); } } //--- devolvemos el volumen total de las ordenes pendientes actuales para el símbolo especificado return(volume_on_symbol); }
Teniendo en cuenta el volumen de la posición abierta y el volumen de las órdenes abiertas, la comprobación definitiva tendrá la forma siguiente:
//+------------------------------------------------------------------+ //| Retorna el volumen máximo permitido para una orden del símbolo | //+------------------------------------------------------------------+ double NewOrderAllowedVolume(string symbol) { double allowed_volume=0; //--- obtenemos la limitación del volumen máximo en la orden double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); //--- obtenemos la limitación del símbolo en cuanto a volumen double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT); //--- Obtenemos el volumen de la posición abierta del símbolo double opened_volume=PositionVolume(symbol); if(opened_volume>=0) { //--- si ya hemos agotado el volumen if(max_volume-opened_volume<=0) return(0); //--- el volumen de la posición abierta no supera 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); }
Establecer los niveles de TakeProfit y StopLoss dentro de los límites del nivel mínimo SYMBOL_TRADE_STOPS_LEVEL
Muchos asesores comercian usando órdenes TakeProfit y StopLoss, cuyos niveles se calculan de forma dinámica en el momento en que se realiza la compra o la venta. Una orden TakeProfit sirve para cerrar una posición cuando el precio se mueve en una dirección rentable, mientras que una orden StopLoss se usa para limitar las pérdidas cuando el precio se mueve en una dirección no rentable.
Por eso los niveles de TakeProfit y StopLoss se deben comparar con el precio actual, conforme al cual se puede ejecutar una operación en la dirección opuesta:
- La compra se realiza al precio Ask: los niveles de TakeProfit y StopLoss se deben comparar con el precio actual de venta Bid.
- La venta se realiza al precio Bid: los niveles de TakeProfit y StopLoss se deben comparar con el precio actual de compra Ask.
La compra tiene lugar al precio Ask | La venta tiene lugar al precio Bid |
---|---|
TakeProfit >= Bid StopLoss <= Bid | TakeProfit <= Ask StopLoss >= Ask |
Para los instrumentos financieros, en los ajustes del símbolo se puede establecer el parámetro SYMBOL_TRADE_STOPS_LEVEL. Este indica en puntos la distancia mínima de los niveles de StopLoss y TakeProfit con respecto al precio de cierre de la posición abierta. Si el valor de esta propiedad es igual a cero, significa que no se establecido distancia mínima para las órdenes SL/TP para compras y ventas.
En general, la comprobación de los niveles de TakeProfit y StopLoss teniendo en cuenta la distancia SYMBOL_TRADE_STOPS_LEVEL tiene el aspecto que sigue:
- La compra se realiza al precio Ask: los niveles de TakeProfit y StopLoss deberán estar del precio actual de venta Bid a una distancia no inferior a SYMBOL_TRADE_STOPS_LEVEL puntos.
- La venta se realiza al precio Bid: los niveles de TakeProfit y StopLoss deberán estar del precio actual de compra Ask a una distancia no inferior a SYMBOL_TRADE_STOPS_LEVEL puntos.
La compra tiene lugar al precio Ask | La venta tiene lugar al precio 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 eso se puede crear la función de comprobación CheckStopLoss_Takeprofit(), que exige que la distancia desde el TakeProfit y el StopLoss hasta el precio de cierre no sea inferior a SYMBOL_TRADE_STOPS_LEVEL puntos:
bool CheckStopLoss_Takeprofit(ENUM_ORDER_TYPE type,double SL,double TP) { //--- obtenemos el nivel SYMBOL_TRADE_STOPS_LEVEL int stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); if(stops_level!=0) { PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: el StopLoss y el TakeProfit deberán estar"+ " no más cerca de %d puntos del precio de cierre",stops_level,stops_level); } //--- bool SL_check=false,TP_check=false; //--- comprobamos solo dos tipos de órdenes switch(type) { //--- operación de compra case ORDER_TYPE_BUY: { //--- comprobamos el 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 puntos)", EnumToString(type),SL,Bid-stops_level*_Point,Bid,stops_level); //--- comprobamos el 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 puntos)", EnumToString(type),TP,Bid+stops_level*_Point,Bid,stops_level); //--- retornamos el resultado de la comprobación return(SL_check&&TP_check); } //--- operación de venta case ORDER_TYPE_SELL: { //--- comprobamos el 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 puntos)", EnumToString(type),SL,Ask+stops_level*_Point,Ask,stops_level); //--- comprobamos el 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 puntos)", EnumToString(type),TP,Ask-stops_level*_Point,Ask,stops_level); //--- retornamos el resultado de la comprobación return(TP_check&&SL_check); } break; } //--- para las órdenes pendientes se necesita una función un tanto distinta return false; }
La comprobación en sí tiene este aspecto:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- obtenemos de forma aleatoria el tipo de operación int oper=(int)(GetTickCount()%2); // el resto de la división entre dos es o bien 0 o bien 1 switch(oper) { //--- compramos case 0: { //--- obtenemos el precio de apertura y establecemos TP/SL incorrectos de antemano double price=Ask; double SL=NormalizeDouble(Bid+2*_Point,_Digits); double TP=NormalizeDouble(Bid-2*_Point,_Digits); //--- realizamos comprobación PrintFormat("Buy at %.5f SL=%.5f TP=%.5f Bid=%.5f",price,SL,TP,Bid); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_BUY,SL,TP)) Print("¡El nivel de StopLoss o TakeProfit ha sido indicado de forma incorrecta!"); //--- de todas formas intentamos comprar, para ver el resultado de la ejecución Buy(price,SL,TP); } break; //--- vendemos case 1: { //--- obtenemos el precio de apertura y establecemos TP/SL incorrectos de antemano double price=Bid; double SL=NormalizeDouble(Ask-2*_Point,_Digits); double TP=NormalizeDouble(Ask+2*_Point,_Digits); //--- realizamos comprobación PrintFormat("Sell at %.5f SL=%.5f TP=%.5f Ask=%.5f",price,SL,TP,Ask); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_SELL,SL,TP)) Print("¡El nivel de StopLoss o TakeProfit ha sido indicado de forma incorrecta!"); //--- de todas formas intentamos vender, para ver el resultado de la ejecución Sell(price,SL,TP); } break; //--- } }
Encontrará un ejemplo de la función en los scripts adjuntos Check_TP_and_SL.mq4 y Check_TP_and_SL.mq5. Ejemplo de ejecución:
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: El StopLoss y el TakeProfit deberán estar no más cerca de 30 puntos del precio de cierre Check_TP_and_SL (EURUSD,H1) Para la orden ORDER_TYPE_BUY StopLoss=1.11425 debe ser inferior a 1.11393 (Bid=1.11423 - SYMBOL_TRADE_STOPS_LEVEL=30 puntos) Check_TP_and_SL (EURUSD,H1) Para la orden ORDER_TYPE_BUY TakeProfit=1.11421 debe ser superior a 1.11453 (Bid=1.11423 + SYMBOL_TRADE_STOPS_LEVEL=30 puntos) Check_TP_and_SL (EURUSD,H1) ¡El nivel de StopLoss o TakeProfit se ha indicado de forma incorrecta! 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: El StopLoss y el TakeProfit deberán estar no más cerca de 1 punto del precio de cierre Check_TP_and_SL EURUSD,H1: Para la orden ORDER_TYPE_SELL StopLoss=1.11445 debe ser superior a 1.11448 (Ask=1.11447 + SYMBOL_TRADE_STOPS_LEVEL=1 puntos) Check_TP_and_SL EURUSD,H1: Para la orden ORDER_TYPE_SELL TakeProfit=1.11449 debe ser menor a 1.11446 (Ask=1.11447 - SYMBOL_TRADE_STOPS_LEVEL=1 puntos) Check_TP_and_SL EURUSD,H1: ¡El nivel de StopLoss o TakeProfit se ha indicado de forma incorrecta! Check_TP_and_SL EURUSD,H1: OrderSend error 130
Para modelar la situación con valores de TakeProfit y StopLoss incorrectos se han adjuntado al artículo los asesores Test_Wrong_TakeProfit_LEVEL.mq5 y Test_Wrong_StopLoss_LEVEL.mq5. Solo se los puede iniciar en la cuenta demo. Estudie estos ejemplos para comprobar por sí mismo en qué condiciones es posible realizar compras con éxito.
Ejemplo de ejecución del asesor 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á prohibido modificar la orden o posición si quedan 20 puntos hasta el precio de activación SYMBOL_TRADE_STOPS_LEVEL=30: El StopLoss y el TakeProfit deberán estar no más cerca de 30 puntos del precio de cierre 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)
Ejemplo de ejecución del asesor 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á prohibido modificar la orden o posición si quedan 20 puntos hasta el precio de activación SYMBOL_TRADE_STOPS_LEVEL=30: El StopLoss y el TakeProfit deberán estar no más cerca de 30 puntos del precio de cierre 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)
La comprobación de los niveles de StopLoss y TakeProfit en las órdenes pendientes es bastante más simple, estos niveles deberán colocarse de forma separada con respecto al precio de apertura de la orden. Es decir, la comprobación de los niveles teniendo en cuenta la distancia mínima SYMBOL_TRADE_STOPS_LEVEL tiene el aspecto siguiente: los niveles de TakeProfit y StopLoss deberán encontrarse del precio de activación de la orden a una distancia no inferior a SYMBOL_TRADE_STOPS_LEVEL puntos.
BuyLimit y BuyStop | SellLimit y 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 |
En el asesor Test_StopLoss_Level_in_PendingOrders.mq5 se hace una serie de intentos de colocar las órdenes BuyStop y BuyLimt hasta que la operación no se realice con éxito. Con cada intento, el nivel de StopLoss o TakeProfit se desplaza en 1 punto en la dirección correcta. Ejemplo de ejecución de este asesor:
Test_StopLoss_Level_in_PendingOrders.mq5 SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT SYMBOL_TRADE_FREEZE_LEVEL=20: está prohibido modificar la orden o posición si quedan 20 puntos hasta el precio de activación SYMBOL_TRADE_STOPS_LEVEL=30: El StopLoss y el TakeProfit deberán estar no más cerca de 30 puntos del precio de cierre 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)
Podrá encontrar ejemplos de comprobación de los niveles de TakeProfit y StopLoss en órdenes pendientes en los códigos fuente adjuntos: Check_TP_and_SL.mq4 y Check_TP_and_SL.mq5.
Intento de modificación de una orden o posición en los límites del nivel de congelamiento SYMBOL_TRADE_FREEZE_LEVEL
En los ajustes del símbolo se puede establecer el parámetro SYMBOL_TRADE_FREEZE_LEVEL, que indica en puntos la distancia de congelamiento de las operaciones comerciales para las órdenes pendientes y las posiciones abiertas. Por ejemplo, si una operación de un instrumento financiero es redirigida para el procesamiento a un sistema comercial externo, entonces la orden pendiente BuyLimit puede encontrarse en este momento demasiado cerca del precio Ask actual. Y si nosotros enviamos una orden de modificación de esta orden en el momento en el que el precio de apertura está los suficientemente cerca del precio Ask, entonces puede darse el caso de que la orden ya habrá sido ejecutada y la modificación resultará imposible.
Por eso, para las órdenes pendientes y las posisicones abiertas es posible indicar en los ajustes la distancia de congelamiento, en cuyos límites no se podrán modificar. En general, antes de intentar enviar la orden de modificación, es necesario realizar una comprobación teniendo en cuenta SYMBOL_TRADE_FREEZE_LEVEL:
Tipo de orden/posición | Activación al precio | Comprobación |
---|---|---|
Orden Buy Limit | Ask | Ask-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL |
Buy Stop ордер | Ask | OpenPrice-Ask >= SYMBOL_TRADE_FREEZE_LEVEL |
Sell Limit ордер | Bid | OpenPrice-Bid >= SYMBOL_TRADE_FREEZE_LEVEL |
Sell Stop ордер | Bid | Bid-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL |
Posición Buy | Bid | TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL Bid-StopLoss >= SYMBOL_TRADE_FREEZE_LEVEL |
Posición Sell | Ask | Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL StopLoss-Ask >= SYMBOL_TRADE_FREEZE_LEVEL |
Podrá encontrar ejemplos completos de las funciones de comprobación de las órdenes a nivel de SYMBOL_TRADE_FREEZE_LEVEL en los scripts adjuntos Check_FreezeLevel.mq5 y Check_FreezeLevel.mq4.
//--- comprobamos el tipo de orden switch(type) { //--- orden pendiente BuyLimit case ORDER_TYPE_BUY_LIMIT: { //--- comprobamos la distancia desde el precio de apertura hasta el precio de activación check=((Ask-price)>freeze_level*_Point); if(!check) PrintFormat("La orden %s #%d no puede ser modificada: Ask-Open=%d puntos < SYMBOL_TRADE_FREEZE_LEVEL=%d puntos", EnumToString(type),ticket,(int)((Ask-price)/_Point),freeze_level); return(check); } //--- orden pendiente BuyLimit case ORDER_TYPE_SELL_LIMIT: { //--- comprobamos la distancia desde el precio de apertura hasta el precio de activación check=((price-Bid)>freeze_level*_Point); if(!check) PrintFormat("La orden %s #%d no puede ser modificada: Open-Bid=%d puntos < SYMBOL_TRADE_FREEZE_LEVEL=%d puntos", EnumToString(type),ticket,(int)((price-Bid)/_Point),freeze_level); return(check); } break; //--- orden pendiente BuyStop case ORDER_TYPE_BUY_STOP: { //--- comprobamos la distancia desde el precio de apertura hasta el precio de activación check=((price-Ask)>freeze_level*_Point); if(!check) PrintFormat("La orden %s #%d no puede ser modificada: Ask-Open=%d puntos < SYMBOL_TRADE_FREEZE_LEVEL=%d puntos", EnumToString(type),ticket,(int)((price-Ask)/_Point),freeze_level); return(check); } //--- orden pendiente SellStop case ORDER_TYPE_SELL_STOP: { //--- comprobamos la distancia desde el precio de apertura hasta el precio de activación check=((Bid-price)>freeze_level*_Point); if(!check) PrintFormat("La orden %s #%d no puede ser modificada: Bid-Open=%d puntos < SYMBOL_TRADE_FREEZE_LEVEL=%d puntos", EnumToString(type),ticket,(int)((Bid-price)/_Point),freeze_level); return(check); } break; }
Usted puede modelar de forma autónoma la situación en la que tiene lugar el intento de modificación de la orden pendiente dentro del nivel de congelamiento. Para ello, abra una cuenta demo en la que haya instrumentos financieros con un nivel cero de SYMBOL_TRADE_FREEZE_LEVEL, inicie en el gráfico el asesor Test_SYMBOL_TRADE_FREEZE_LEVEL.mq5 (Test_SYMBOL_TRADE_FREEZE_LEVEL.mq4) y coloque manualmente cualquier orden pendiente. El asesor acercará al máximo al mercado la orden y comenzará a realizar intentos prohibidos de modificación. Además, se reproducirá un sonido con la ayuda de la función PlaySound().
Errores que surgen al trabajar con los símbolos con una historia de cotizaciones insuficiente
Si el asesor o indicador se inicia en el gráfico con una historia insuficiente, surgen dos casos posibles:
- el programa realiza una comprobación de la existencia de la historia necesaria en toda la profundidad exigida. Si el número de barras alcanzadas es menor al necesario, entonces el programa solicita los datos que faltan y finaliza su trabajo hasta que llegue el siguiente tick. Este método es el más correcto y ayuda a evitar multitud de errores, como por ejemplo la salida fuera de los límites de la matriz o la división entre cero;
- el programa no realiza ninguna comprobación y comienza directamente su trabajo, como si toda la historia necesaria de todos los instrumentos y marcos temporales imprescindibles hubiera estado disponible en el primer requerimiento. Este enfoque está colmado de errores impredecibles.
Usted puede intentar modelar esa situación por su propia cuenta. Para ello, inicie el indicador o asesor testado en el gráfico, después cierre el terminal y elimine toda la historia y de nuevo inicie el terminal. Si después de reiniciar no han aparecido errores en el Registro, comience a cambiar los símbolos y marcos temporales en los gráficos en los que está iniciado su programa. Muchos indicadores dan errores al iniciarse en los marcos temporales de semanas y meses, para los que como norma general la cantidad de barras suele estar limitada. Asimismo, al cambiar bruscamente el símbolo del gráfico, por ejemplo, de EURUSD a CADJPY, el indicador o asesor iniciado en el gráfico puede incurrir en un error que se relaciona con la ausencia de la historia necesaria para sus cálculos.
Salida de los límites de la matriz (array out of range)
Al trabajar con las matrices, el acceso a sus elementos se realiza según el número del índice, que no puede ser negativo y debe ser menor que el tamaño de la matriz. Es posible obtener el tamaño de la matriz con la ayuda de la función ArraySize().
Este error puede surgir al trabajar con una matriz dinámica, cuando su tamaño no ha sido distribuido claramente por la función ArrayResize(), o bien por usar esta matriz en funciones que establecen por sí solas el tamaño de las matrices dinámicas que se les han transmitido. Por ejemplo, la función CopyTicks() intenta grabar en la matriz la cantidad solicitada de ticks, pero si hay menos ticks de los solicitados, el tamaño de la matriz recibida será menor del esperado.
Otro método bastante probable de obtener este error es tratar de recurrir a los datos del búfer de indicador cuando su tamaño aún no ha sido inicializado. Recordemos que los búferes de indicador son matrices dinámicas y sus dimensiones son establecidas por el sistema ejecutivo del terminal solo después de la inicialización del gráfico. Por eso, por ejemplo, el intento de recurrir a los datos de este búfer en la función OnInit() provocará el error "array out of range".
Un ejemplo sencillo de un indicador que da este error se adjunta en el archivo Test_Out_of_range.mq5.
División entre cero (zero divide)
Otro error crítico es el intento de división entre cero. En este caso, la ejecución del programa se detiene de inmediato, el simulador muestra en el Registro el nombre de la función y el número de línea en el código fuente en la que ha sucedido el error.
Normalmente, la división entre cero tiene lugar como consecuencia de una situación imprevista por los programadores, por ejemplo, cuando se obtiene una cierta propiedad o bien por la división del valor entre datos "malos".
Podrá reproducir con facilidad la división entre cero con la ayuda del sencillo asesor TestZeroDivide.mq5, cuyo código fuente se muestra en la captura de pantalla. Otro error crítico es el uso de un puntero a objeto incorrecto. La Depuración en la historia le ayudará a aclarar los motivos de este error.
Envío de una solicitud de modificación de niveles sin cambiarlos de hecho
Si, según las normas del sistema comercial, se deben modificar las órdenes pendientes o posiciones abiertas, antes de enviar la solicitud comercial para que se realice la transacción hay que asegurarse de que la operación solicitada en realidad va a cambiar los parámetros de la orden o posición. El envío de una solicitud comercial que en realidad no introduce cambios se considera un error. Como respuesta a semejante acción, el servidor comercial retornará el código de respuesta TRADE_RETCODE_NO_CHANGES=10025 (MQL5) o el código ERR_NO_RESULT=1 (MQL4)
Un ejemplo de comprobación para MQL5 se muestra en el script Check_OrderLevels.mq5:
//--- clase para realizar operaciones comerciales #include <Trade\Trade.mqh> CTrade trade; #include <Trade\Trade.mqh> //--- clase para trabajar con órdenes #include <Trade\OrderInfo.mqh> COrderInfo orderinfo; //--- clase para trabajar con posiciones #include <Trade\PositionInfo.mqh> CPositionInfo positioninfo; //+------------------------------------------------------------------+ //| comprobación de los nuevos valores de los niveles antes de la modificación de la orden | //+------------------------------------------------------------------+ bool OrderModifyCheck(ulong ticket,double price,double sl,double tp) { //--- elegimos la orden según el ticket if(orderinfo.Select(ticket)) { //--- tamaño del punto y nombre del símbolo del que se coloca la orden pendiente string symbol=orderinfo.Symbol(); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- comprobamos si hay cambios en el precio de apertura bool PriceOpenChanged=(MathAbs(orderinfo.PriceOpen()-price)>point); //--- comprobamos si hay cambios en el nivel de StopLoss bool StopLossChanged=(MathAbs(orderinfo.StopLoss()-sl)>point); //--- comprobamos si hay cambios en el nivel de Takeprofit bool TakeProfitChanged=(MathAbs(orderinfo.TakeProfit()-tp)>point); //--- comprobamos si hay cambios en los niveles if(PriceOpenChanged || StopLossChanged || TakeProfitChanged) return(true); // la orden puede ser modificada //--- no hay cambios en los niveles de apertura, StopLoss y Takeprofit else //--- comunicamos el error PrintFormat("La orden #%d ya tiene los niveles Open=%.5f SL=%.5f TP=%.5f", ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit()); } //--- hemos llegado al final, no hay cambios para la orden return(false); // no tiene sentido modificarla } //+------------------------------------------------------------------+ //| comprobación de los nuevos valores de los niveles antes de la modificación de la orden | //+------------------------------------------------------------------+ bool PositionModifyCheck(ulong ticket,double sl,double tp) { //--- elegimos la orden según el ticket if(positioninfo.SelectByTicket(ticket)) { //--- tamaño del punto y nombre del símbolo del que se coloca la orden pendiente string symbol=positioninfo.Symbol(); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); //--- comprobamos si hay cambios en el nivel de StopLoss bool StopLossChanged=(MathAbs(positioninfo.StopLoss()-sl)>point); //--- comprobamos si hay cambios en el nivel de Takeprofit bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point); //--- comprobamos si hay cambios en los niveles if(StopLossChanged || TakeProfitChanged) return(true); // la posición puede ser modificada //--- no hay cambios en los niveles de StopLoss y Takeprofit else //--- comunicamos el error PrintFormat("La orden #%d ya tiene los niveles Open=%.5f SL=%.5f TP=%.5f", ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit()); } //--- hemos llegado al final, no hay cambios para la orden return(false); // no tiene sentido modificarla } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- niveles de precio para las órdenes y posiciones double priceopen,stoploss,takeprofit; //--- ticket de la orden o posición actual ulong orderticket,positionticket; /* ... obtenemos el ticket de la orden y los nuevos niveles de StopLoss/Takeprofit/PriceOpen */ //--- comprobamos los niveles antes de modificar la orden pendiente if(OrderModifyCheck(orderticket,priceopen,stoploss,takeprofit)) { //--- la comprobación ha tenido éxito trade.OrderModify(orderticket,priceopen,stoploss,takeprofit, orderinfo.TypeTime(),orderinfo.TimeExpiration()); } /* ... obtenemos el ticket de la posición y los nuevos niveles de StopLoss/Takeprofit */ //--- comprobamos los niveles antes de modificar la posición if(PositionModifyCheck(positionticket,stoploss,takeprofit)) { //--- la comprobación ha tenido éxito trade.PositionModify(positionticket,stoploss,takeprofit); } //--- }
Encontrará un ejemplo de comprobación en el lenguaje MQL4 en el script Check_OrderLevels.mq4:
#property strict //+------------------------------------------------------------------+ //| comprobación de los nuevos valores de los niveles antes de la modificación de la orden | //+------------------------------------------------------------------+ bool OrderModifyCheck(int ticket,double price,double sl,double tp) { //--- elegimos la orden según el ticket if(OrderSelect(ticket,SELECT_BY_TICKET)) { //--- tamaño del punto y nombre del símbolo del que se coloca la orden pendiente string symbol=OrderSymbol(); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); //--- comprobamos si hay cambios en el precio de apertura bool PriceOpenChanged=true; int type=OrderType(); if(!(type==OP_BUY || type==OP_SELL)) { PriceOpenChanged=(MathAbs(OrderOpenPrice()-price)>point); } //--- comprobamos si hay cambios en el nivel de StopLoss bool StopLossChanged=(MathAbs(OrderStopLoss()-sl)>point); //--- comprobamos si hay cambios en el nivel de Takeprofit bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point); //--- comprobamos si hay cambios en los niveles if(PriceOpenChanged || StopLossChanged || TakeProfitChanged) return(true); // la orden puede ser modificada //--- no hay cambios en los niveles de apertura, StopLoss y Takeprofit else //--- comunicamos el error PrintFormat("La orden #%d ya tiene los niveles Open=%.5f SL=%.5f TP=%.5f", ticket,OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit()); } //--- hemos llegado al final, no hay cambios para la orden return(false); // no tiene sentido modificarla } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- niveles de precio para las órdenes y posiciones double priceopen,stoploss,takeprofit; //--- ticket de la orden actual int orderticket; /* ... obtenemos el ticket de la orden y los nuevos niveles de StopLoss/Takeprofit/PriceOpen */ //--- comprobamos los niveles antes de modificar la orden if(OrderModifyCheck(orderticket,priceopen,stoploss,takeprofit)) { //--- la comprobación ha tenido éxito OrderModify(orderticket,priceopen,stoploss,takeprofit,OrderExpiration()); } }
Recomendamos leer los artículos:
- Cómo hacer más fácil la detección y recuperación de errores en el código de un asesor experto
- Cómo crear un robot de trading fiable y seguro en MQL4
Intento de importación de los archivos compilados (EX4/EX5 inclusive) y DLL
Los programas difundidos por el Mercado deberán ser seguros con toda garantía para los usuarios. Por eso, cualquier intento de uso de DLL o de funciones de los archivos compilados EX4/EX5 se considera erróneo. Este tipo de productos no se publicará en el Mercado.
Si su programa necesita del uso de indicadores adicionales no incluidos en el paquete, use los Recursos.
Recurrir a los indicadores de usuario a través de iCustom()
Si para que su programa funcione es necesario recurrir a los datos de un indicador de usuario, entonces deberá ubicar todos los indicadores necesarios en los Recursos. Los productos del Mercado deberán estar listos para funcionar en cualquier entorno sin preparación, por eso deberán contener todo lo necesario en su archivo EX4/EX5. Artículos recomendados sobre el tema:
Transmisión de un parámetro no permitido a la función (error de tiempo de ejecución)
Este tipo de errores se encuentra rara vez, para muchos de ellos hay códigos preparados, que deberían ayudar a encontrar el motivo.
Constante | Valor | Descripción |
---|---|---|
ERR_INTERNAL_ERROR | 4001 | Error interno inesperado |
ERR_WRONG_INTERNAL_PARAMETER | 4002 | Parámetro erróneo durante la llamada built-in a la función del terminal de cliente |
ERR_INVALID_PARAMETER | 4003 | Parámetro erróneo durante la llamada a la función de sistema |
ERR_NOTIFICATION_WRONG_PARAMETER | 4516 | Parámetro incorrecto para el envío de notificaciones: a la función SendNotification() le ha sido transmitida una cadena vacía o NULL |
ERR_BUFFERS_WRONG_INDEX | 4602 | Índice erróneo de su búfer de indicadores |
ERR_INDICATOR_WRONG_PARAMETERS | 4808 | Número erróneo de parámetros al crear un indicador |
ERR_INDICATOR_PARAMETERS_MISSING | 4809 | No hay parámetros cuando se crea un indicador |
ERR_INDICATOR_CUSTOM_NAME | 4810 | El primer parámetro en la matriz tiene que ser el nombre del indicador personalizado |
ERR_INDICATOR_PARAMETER_TYPE | 4811 | Tipo erróneo del parámetro en la matriz al crear un indicador |
ERR_NO_STRING_DATE | 5030 | No hay fecha en la cadena |
ERR_WRONG_STRING_DATE | 5031 | Fecha errónea en la cadena |
ERR_TOO_MANY_FORMATTERS | 5038 | Hay más especificadores de formato que parámetros |
ERR_TOO_MANY_PARAMETERS | 5039 | Hay más parámetros que especificadores de formato |
En el recuadro no se han enumerado ni mucho menos todos los errores que se pueden encontrar durante el funcionamiento del programa iniciado.
Access violation
Este error surge al intentar recurrir a la memoria cuyo acceso está prohibido. En cada caso semejante es necesario que se dirija a los desarrolladores en la Mesa de Ayuda a través de su Perfil o de la página Contactos. Una descripción detallada de los pasos necesarios para reproducir los errores, además de adjuntar el código fuente, acelerarán la búsqueda de este error y le ayudarán a mejorar el compilador de código fuente.
Consumo de recursos del procesador y la memoria
A la hora de escribir programas, es importante usar los algorítmos óptimos en cuanto al tiempo de ejecución, pues en el caso contrario, el trabajo con otros programas iniciados en el terminal puede dificultarse o volverse imposible.
Es importante recordar que cada símbolo en la Observación del mercado reserva un hilo común para el funcionamiento del terminal. En dicho hilo trabajan todos los indicadores y gráficos abiertos de él.
Esto significa que si usted tiene abiertos 5 gráficos de EURUSD en diferentes marcos temporales y en estos gráficos se han iniciado 15 indicadores, entonces todos estos gráficos e indicadores tienen a su disposición un hilo único para calcular y representar información en los gráficos. Por eso, si un indicador que es ineficaz y gasta muchos recursos está iniciado en el gráfico, puede ralentizar el funcionamiento del resto de los indicadores e incluso frenar el dibujado de los precios en el resto de los gráficos de este símbolo.
Usted podrá comprobar con facilidad el tiempo invertido por su algoritmo con la ayuda de la función GetMicrosecondCount(). Midiendo el tiempo entre dos líneas de código es fácil obtener el tiempo de ejecución en microsegundos. Para pasarlo a milisegundos (ms), se debe dividir el tiempo entre 1000 (en 1 milisegundo hay 1000 microsegundos). Para los indicadores, un lugar crítico en lo que respecta al tiempo de ejecución suele ser el procesador OnCalculate(). Normalmente, el primer cálculo del indicador depende mucho del parámetro Máx. de barras en la ventana. Indique en este el valor "Unlimited" e inicie su indicador en un símbolo con una historia superior a 10 años en el marco temporal M1. Si el primer inicio ocupa mucho tiempo (por ejemplo, más de 100 ms), entonces es necesario optimizar el código.
Aquí tenemos un ejemplo de cómo medir el tiempo de ejecución del procesador OnCalculate() en el indicador ROC, incluido en el paquete del terminal, en el código fuente. Las inserciones se destacan con fondo amarillo:
//+------------------------------------------------------------------+ //| 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); //--- tiempo de comienzo de los 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; } //--- tiempo de finalización de los cálculos ulong finish=GetMicrosecondCount(); PrintFormat("La función %s en %s ha invertido %.1f ms",__FUNCTION__,__FILE__,(finish-start)/1000.); //--- OnCalculate done. Return new prev_calculated. return(rates_total); }
La memoria utilizada se puede medir con la ayuda de la función MQLInfoInteger(MQL_MEMORY_USED). Y, por supuesto, use el Perfilador de código para buscar las funciones que más memoria gastan en su programa. Asimismo, le recomendamos leer el artículo Los principios del cálculo económico de los indicadores y Depuración de programas en MQL5.
Los expertos funcionan en sus propios hilos, pero todo lo dicho más arriba se relaciona igualmente con ellos. Es imprescindible que escriba el código óptimo en cualquier tipo de programa: asesores, indicadores, bibliotecas y scripts.
Las comprobaciones nunca están de más
Todos los consejos expuestos en lo que respecta a la comrpobación de indicadores y asesores se recomiendan no solo para la publicación de productos en el Mercado, sino también como práctica habitual cuando usted escriba para sí mismo. En este artículo no hemos analizado ni mucho menos todos los errores que se pueden encontrar al comerciar en cuentas reales. Aquí no se han estudiado las normas de procesamiento de los errores comerciales surgidos al vender la conexión a un servidor comercial, las recotizaciones, las negativas a la ejecución de operaciones y muchos más factores que pueden romper las reglas ideales de un sistema comercial. Para estos casos, cada procesador de robots tiene sus recetas preparadas y elaboradas por la experiencia.
A los principiantes les recomendamos leer todos los artículos dedicados al procesamiento de errores, y también les recomendamos hacer preguntas en el foro y en los comentarios a este artículo. Otros miembros con más experiencia de la comunidad MQL5.community le ayudarán con las cuestiones más complicadas. Esperamos que la información reunida en el artículo le sirva de ayuda para crear robots comerciales más fiables y en un plazo más corto.
Artículos recomendados sobre el tema:
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/2555
![Interfaces gráficas VIII: Control "Lista jerárquica" (Capítulo 2)](https://c.mql5.com/2/23/av8__1.png)
![LifeHack para tráders: indicadores de balance, reducción, carga y ticks durante la simulación](https://c.mql5.com/2/23/avac18.png)
![Interfaces gráficas VIII: Control "Explorador de archivos" (Capítulo 3)](https://c.mql5.com/2/23/av8__2.png)
![Experto comercial universal: integración con los módulos estándar de señales de MetaTrader (parte 7)](https://c.mql5.com/2/23/zapvwy5wjkj_54w2.png)
![MQL5 - Lenguaje de estrategias comerciales para el terminal de cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso