¿Qué diseño es el correcto? - página 8

 
valenok2003:

Muchas gracias, estoy procesando los errores, viene el mensaje - precio erróneo, y no puedo averiguar lo que está mal.

entonces añade también una línea

int err = GetLastError();

al comienzo de la función - borrar el búfer de errores: a veces es posible leer el error de "otra persona", y de esta manera el búfer de errores se borrará al comienzo de la función.

Esto no es necesario, pero si los programas para el mundo real, es muy deseable para hacer todo lo más correctamente posible.

Buena suerte.

 
VladislavVG:

entonces añade también una línea

al comienzo de la función - borrar el búfer de errores: a veces es posible leer el error de "otra persona", y de esta manera el búfer de errores se borrará al comienzo de la función.

Esto no es necesario, pero si los programas para el mundo real, es muy deseable para hacer todo lo más correctamente posible.

Buena suerte.


Sí, gracias, eso es lo que hago en el software real.
 
Buenas gente, me podéis decir por qué la función devuelve 0, aunque no haya órdenes abiertas. ¿Se supone que hay algún tipo de error?
//+------------------------------------------------------------------+
//| функция закрытия ордеров по символу
//+------------------------------------------------------------------+
int Close_This_Symbol_All(string _Symbol_Name, string _Type_Order, int _Slippage, bool _Alert_ON)
{
  bool _Result;
  ERROR = 0;
//----
  if(OrdersTotal() == 0) return(-1);
  for (int _Cnt = OrdersTotal()-1; _Cnt >= 0; _Cnt--) 
  {
    if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) break;
    if(OrderSymbol() == _Symbol_Name)
    { 
      while (!IsTradeAllowed()) Sleep(1000);
      RefreshRates();
      if(OrderType() == OP_BUY   && _Type_Order == "BUY") 
      {
        _Result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_BID), _Slippage, CLR_NONE);
        ERROR = GetLastError();
      }
      if(OrderType() == OP_SELL && _Type_Order == "SELL") 
      {
        _Result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_ASK), _Slippage, CLR_NONE);
        ERROR = GetLastError();
      }
      if(_Result == true) PlaySound(Name_Sound_Close);
      else 
      {
        Error(Name_Expert," Close "+_Type_Order+": ",ERROR,_Alert_ON);
        break;
      }
    }  
  }
//----
  return(ERROR);
}
//+------------------------------------------------------------------+
 
Una vez más, ¿estamos separando las piezas?
 
valenok2003:
Buenas gente, me podéis decir por qué esta función devuelve 0 aunque no haya órdenes abiertas. ¿No debería haber algún tipo de error?
int PedidosTotal( )

Devuelve la cantidad total de órdenes abiertas y pendientes.

¿Sigue escribiendo por encargo?

 

-- Usar nombres que empiezan con un guión bajo y un doble guión bajo es una mala forma. Prefiero usar un guión bajo al final.


-- ¿Por qué la cadena _Type_Order? Creo que es irrealmente incómodo. Entonces habría que citarlo. Porque si escribes "Vender" o "vender" no funcionará.


-- Si quieres cometer un error, comete un error:

ERROR = -1;

Mejor aún.

#define ERROR_NOTHING_TO_CLOSE -1
...

...
ERROR = ERROR_NOTHING_TO_CLOSE;


--

if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) break;

¿Por qué romper? Supongamos que, hace un milisegundo, la orden ha sido cerrada por TP, ¿por qué no vamos a cerrar el resto? Esto es mejor:

if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) continue;

--

while (!IsTradeAllowed()) Sleep(1000);

La línea es peor que inútil: es perjudicial. ¿Es eso lo que debe haber querido decir?

while (IsTradeContextBusy()) Sleep(1000);


--

else 
      {
        Error(Name_Expert," Close "+_Type_Order+": ",ERROR,_Alert_ON);
        break;
      }

Es decir, si una orden no se cierra de repente, "suelta el volante, cierra los ojos y empieza a gritar".

¿No hay necesidad de cerrar los otros? ¿No es necesario volver a intentarlo?


-- ¿Por qué hay un retorno de error aquí en absoluto? Sería mucho más apropiado devolver, por ejemplo, true si todos tuvieron éxito para cerrar y false si no.


Eso es todo por ahora.

 
TheXpert:

-- El uso de nombres que comienzan con un guión bajo y un doble guión bajo es una mala forma. Prefiero usar un guión bajo al final.


Al utilizar nombres que comienzan con guiones bajos dentro de las funciones, elimino el riesgo de sobreescritura de variables. Así, puedo utilizar los mismos nombres en start() pero sin guiones bajos, lo que aumenta la transparencia del código.

- ¿Por qué la cadena _Type_Order? Un inconveniente poco realista, en mi opinión. Entonces se debe dar. Porque si escribimos "Vender" o "vender" nada funcionará.

Tienes razón, por supuesto. Sin embargo, el uso de una cadena aumenta la transparencia del código y con la cantidad de código que tengo en este momento, no hay necesidad de un subrayado. Cuando me encuentre con este problema de verdad, lo haré, pero por ahora no es necesario. Simplemente escribo VENDER o COMPRAR.


¿Por qué romper? Supongamos que una orden ha sido cerrada por TP hace un milisegundo, ¿por qué no vamos a cerrar todas las demás? Esto es mejor:

if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) continue;

Desde luego, tiene usted razón, gracias.


La línea es peor que inútil: es perjudicial. ¿Es eso lo que creo que quieres decir?

La función IsTradeContextBusy() sólo informa sobre la ocupación de los hilos, IsTradeAllowed() es algo más amplia


Es decir, si de repente la orden no se puede cerrar, "suelta el volante, cierra los ojos y empieza a gritar"...


sí, para el período de depuración es

¿Por qué habría un retorno de error? Sería mucho más apropiado devolver true si todo se puede cerrar y false si no.


Gracias, creo que he descubierto cuál es el error. Lo comprobaré e informaré.
 

El error fue el siguiente:

la variable bool _Resultado no está inicializada, por lo que contendrá false; por tanto, al no cumplirse ninguna de las condiciones, no hemos modificado la variable _Resultado, y ya contiene false. Y la función procede a la gestión de errores que realmente no se produjeron.

He arreglado la función y la cuelgo aquí, creo que a alguien le puede ser útil.

//+------------------------------------------------------------------+
//| функция закрытия ордеров по символу
//+------------------------------------------------------------------+
int Close_This_Symbol_All(string _Symbol_Name, string _Type_Order, int _Slippage, bool _Alert_ON)
{
int _Cnt_Close_Orders = 0;
//----
  if(OrdersTotal() == 0) return(_Cnt_Close_Orders);
  for (int _Cnt = OrdersTotal()-1; _Cnt >= 0; _Cnt--) 
  {
    if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) continue;
    if(OrderSymbol() == _Symbol_Name)
    { 
      while (!IsTradeAllowed()) Sleep(1000);
      RefreshRates();
      if(OrderType() == OP_BUY   && _Type_Order == "BUY") 
      {
        if(OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_BID), _Slippage, CLR_NONE))
        {
          _Cnt_Close_Orders++;
          PlaySound(Name_Sound_Close);        
        } 
        else 
        {
          Error(Name_Expert," Close "+_Type_Order+": ",GetLastError(),_Alert_ON);
          continue;
        }
      }
      if(OrderType() == OP_SELL && _Type_Order == "SELL") 
      {
        if(OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_ASK), _Slippage, CLR_NONE))
        {
          _Cnt_Close_Orders++;
          PlaySound(Name_Sound_Close);        
        } 
        else 
        {
          Error(Name_Expert," Close "+_Type_Order+": ",GetLastError(),_Alert_ON);
          continue;
        }
      }
    }  
  }
//----
  return(_Cnt_Close_Orders);
}
//+------------------------------------------------------------------+

P.D. a los moderadores. He creado una rama de este tipo por accidente - auto-tutorial completo sobre cómo cerrar las órdenes correctamente. Tal vez debería ser renombrado como - cómo cerrar correctamente las órdenes con ejemplos.

PPS Muchas gracias a todos los que han participado. Probablemente habrá más preguntas.

 
valenok2003:

El error fue el siguiente:

la variable bool _Resultado no está inicializada, por lo que contendrá false; por tanto, al no cumplirse ninguna de las condiciones, no hemos modificado la variable _Resultado, y ya contiene false. Y la función procede a la gestión de errores que realmente no se produjeron.

He arreglado la función y la cuelgo aquí, creo que a alguien le puede ser útil.

P.D. a los moderadores. He creado una rama de este tipo por accidente - auto-tutorial completo sobre cómo cerrar las órdenes correctamente. Tal vez debería ser renombrado como - cómo cerrar correctamente las órdenes con ejemplos.

PPS Muchas gracias a todos los que han participado. Probablemente habrá más preguntas.


Si miras en el CodeBase y lees atentamente el foro - hay más de cien ejemplos de cierre de orden correcto, pero eso no significa que todas las ramas deban ser renombradas a la vez. Hay suficientes héroes.
 
valenok2003:

El error fue el siguiente:

la variable bool _Resultado no está inicializada, por lo que contendrá false; por tanto, al no cumplirse ninguna de las condiciones, no hemos modificado la variable _Resultado, y ya contiene false. Y la función procede a la gestión de errores que realmente no se produjeron.

He arreglado la función y la cuelgo aquí, creo que a alguien le puede ser útil.

P.D. a los moderadores. He creado una rama de este tipo por accidente - auto-tutorial completo sobre cómo cerrar las órdenes correctamente. Tal vez debería ser renombrado como - cómo cerrar correctamente las órdenes con ejemplos.

PPS Muchas gracias a todos los que han participado. Probablemente habrá más preguntas.

IMHO: Esta función no es clara en su lógica. Si es para un probador, es demasiado innecesario, si es para el mundo real, los errores deben ser manejados. El valor devuelto no tiene ningún significado porque estás diciendo en el nivel externo (en el nivel de la llamada) que la llamada terminó con un error, estás perdiendo el error en sí, bueno, el experto escribió en el registro - ¿cómo cuenta?

Lo que sería mejor: (de nuevo, IMHO)

1. Lee y guarda el número de error.

2. Dividir los errores en reparables y no reparables. Para ello, debemos crear un manejador - aquellos errores, a la aparición de los cuales la orden puede ser cerrada (un hilo está ocupado, fallo de conexión ..., etc.) debe ser manejado inmediatamente en el sitio. Yo lo he hecho así (primero los errores irrecuperables y luego los que se pueden "arreglar"):

#define MAXCYKLESCNT 20

int ErrReaction(int err)
{
    switch(err)
    {
        case ERR_TRADE_NOT_ALLOWED    :
                 Print("TRADE NOT ALLOWED ! SWITCH ON option \' Allow live trading\' (Необходимо включить опцию \'Разрешить советнику торговать\')");
        case ERR_INVALID_FUNCTION_PARAMSCNT :    
        case ERR_INVALID_FUNCTION_PARAMVALUE :    
        case ERR_INVALID_STOPS        : 
        case ERR_INVALID_TRADE_VOLUME : 
        case ERR_MARKET_CLOSED        : 
        case ERR_TRADE_DISABLED       : 
        case ERR_NOT_ENOUGH_MONEY     : 
                 return(-err);
        case ERR_NO_CONNECTION        :
                 ReScanServers();
        case ERR_BROKER_BUSY          : 
        case ERR_TRADE_CONTEXT_BUSY   : 
        case ERR_ORDER_LOCKED         :
                 int n=0;
                 while((!IsTradeAllowed())&&(n<20)){ Sleep(500);n++;}
        case ERR_PRICE_CHANGED : 
        case ERR_OFF_QUOTES    : 
        case ERR_REQUOTE       : 
                 RefreshRates();
                 break;
        default: break;
    }//switch(err)
    return(0);
}//int ErrReaction(int err)

3. Cuando se produce un error intratable, devolver no una bandera de error, sino su número, para que esta situación pueda ser manejada en un módulo externo. Al analizar el resultado de una operación:

bool res    = false;
int  ncykls =     0;

    while((!res)&&(ncykls<MAXCYKLESCNT))
    {
        res = ...............
        if(!res)
        { 
            ncykls++;
            err=GetLastError();
            Print(ncykls," Err(",err,") : ",ErrorDescription(err)); 
            err_res = ErrReaction(err); 
            if(err_res<0) return(err_res);
        } 
    }//while((!res)&&(ncykls<MAXCYKLESCNT))

Buena suerte.

SZ sobre la pausa/continuación

if( !OrderSelect(i,SELECT_BY_POS,MODE_TRADES) ) break;    // No more Orders
la cuestión es discutible. Si todavía hay órdenes, cuando se activa una toma/parada la numeración de la orden cambiará, es decir, la orden seguirá siendo seleccionada: se selecciona por número de orden, no por ticket. Si la orden no está seleccionada, significa que no hay orden. Como no se comprueba el número de pedidos cada vez, se ejecutará el ciclo en blanco un cierto número de veces.