Restricciones y permisos para las operaciones de la cuenta

Entre las propiedades de la cuenta existen restricciones en las operaciones de trading, entre las que se incluyen la completa deshabilitación del trading. Todas estas propiedades pertenecen a la enumeración ENUM_ACCOUNT_INFO_INTEGER y son banderas booleanas, excepto ACCOUNT_LIMIT_ORDERS.

Identificador

Descripción

ACCOUNT_TRADE_ALLOWED

Permiso para operar en una cuenta corriente

ACCOUNT_TRADE_EXPERT

Permiso para el trading algorítmico mediante Asesores Expertos y scripts

ACCOUNT_LIMIT_ORDERS

Número máximo permitido de órdenes pendientes válidas

ACCOUNT_FIFO_CLOSE

Obligación de cerrar las posiciones sólo según la regla FIFO

Dado que nuestro libro trata sobre la programación MQL5, que incluye el trading algorítmico, debe tenerse en cuenta que el permiso ACCOUNT_TRADE_EXPERT desactivado es tan crítico como la prohibición general de operar cuando ACCOUNT_TRADE_ALLOWED es igual a false. El bróker tiene la capacidad de prohibir el trading utilizando Asesores Expertos y scripts mientras que permite el trading manual.

La propiedad ACCOUNT_TRADE_ALLOWED suele ser igual a false si la conexión a la cuenta se realizó utilizando la contraseña de inversión.

Si el valor de la propiedad ACCOUNT_FIFO_CLOSE es true, las posiciones de cada símbolo sólo se pueden cerrar en el mismo orden en que se abrieron, es decir, primero se cierra la orden más antigua, luego la más nueva, y así sucesivamente hasta la última. Si intenta cerrar posiciones en un orden diferente, recibirá un error. Para las cuentas sin cobertura de posiciones, es decir, si la propiedad ACCOUNT_MARGIN_MODE no es igual a ACCOUNT_MARGIN_MODE_RETAIL_HEDGING, la propiedad ACCOUNT_FIFO_CLOSE es siempre false.

En las secciones Permisos y Horarios de sesiones de trading y cotización ya empezamos a desarrollar una clase para detectar las operaciones de trading disponibles para el programa MQL. Ahora podemos complementarlo con comprobaciones de permisos de cuentas y llevarlo a la versión final (Permissions.mqh).

Los niveles de restricción se proporcionan en la enumeración TRADE_RESTRICTIONS, que, tras añadir dos nuevos elementos relacionados con las propiedades de las cuentas, adopta la siguiente forma:

class Permissions
{
   enum TRADE_RESTRICTIONS
   {
      NO_RESTRICTIONS = 0,
      TERMINAL_RESTRICTION = 1// user's restriction for all programs
      PROGRAM_RESTRICTION = 2,  // user's restriction for a specific program
      SYMBOL_RESTRICTION = 4,   // the symbol is not traded according to the specification
      SESSION_RESTRICTION = 8,  // the market is closed according to the session schedule
      ACCOUNT_RESTRICTION = 16// investor password or broker restriction
      EXPERTS_RESTRICTION = 32// broker restricted algorithmic trading
   };
   ...

Durante la comprobación, el programa MQL puede detectar varias restricciones por diversos motivos, por lo que los elementos se codifican mediante bits separados. El resultado final puede representar su superposición.

Las dos últimas restricciones sólo corresponden a las nuevas propiedades y se establecen en el método getTradeRestrictionsOnAccount. La máscara de bits general de las restricciones detectadas (si las hay) se forma en la variable lastRestrictionBitMask.

private:
   static uint lastRestrictionBitMask;
   static bool pass(const uint bitflag
   {
      lastRestrictionBitMask |= bitflag;
      return lastRestrictionBitMask == 0;
   }
   
public:
   static uint getTradeRestrictionsOnAccount()
   {
      return (AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) ? 0 : ACCOUNT_RESTRICTION)
         | (AccountInfoInteger(ACCOUNT_TRADE_EXPERT) ? 0 : EXPERTS_RESTRICTION);
   }
   
   static bool isTradeOnAccountEnabled()
   {
      lastRestrictionBitMask = 0;
      return pass(getTradeRestrictionsOnAccount());
   }
   ... 

Si el código de llamada no está interesado en el motivo de la restricción, sino que sólo necesita determinar la posibilidad de realizar operaciones de trading, es más conveniente utilizar el método isTradeOnAccountEnabled, que devuelve un signo booleano (true/false).

Las comprobaciones de las propiedades de los símbolos y los terminales se han reorganizado siguiendo un principio similar. Por ejemplo, el método getTradeRestrictionsOnSymbol contiene el código fuente ya conocido de la versión anterior de la clase (comprobación de las sesiones de trading y los modos de trading del símbolo), pero devuelve una máscara de banderas. Si al menos un bit está activado, describe el origen de la restricción.

   static uint getTradeRestrictionsOnSymbol(const string symboldatetime now = 0,
      const ENUM_SYMBOL_TRADE_MODE mode = SYMBOL_TRADE_MODE_FULL)
   {
      if(now == 0now = TimeTradeServer();
      bool found = false;
      // checking the symbol trading sessions and setting 'found' to 'true',
      // if the 'now' time is inside one of the sessions
      ...
      
      // in addition to sessions, check the trading mode
      const ENUM_SYMBOL_TRADE_MODE m = (ENUM_SYMBOL_TRADE_MODE)SymbolInfoInteger(symbolSYMBOL_TRADE_MODE);
      return (found ? 0 : SESSION_RESTRICTION)
         | (((m & mode) != 0) || (m == SYMBOL_TRADE_MODE_FULL) ? 0 : SYMBOL_RESTRICTION);
   }
   
   static bool isTradeOnSymbolEnabled(const string symbolconst datetime now = 0,
      const ENUM_SYMBOL_TRADE_MODE mode = SYMBOL_TRADE_MODE_FULL)
   {
      lastRestrictionBitMask = 0;
      return pass(getTradeRestrictionsOnSymbol(symbolnowmode));
   }
   ...

Por último, en los métodos getTradeRestrictions y isTradeEnabled se realiza una comprobación general de todas las posibles «instancias», incluyendo (además de los niveles anteriores) la configuración del terminal y del programa.

   static uint getTradeRestrictions(const string symbol = NULLconst datetime now = 0,
      const ENUM_SYMBOL_TRADE_MODE mode = SYMBOL_TRADE_MODE_FULL)
   {
      return (TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ? 0 : TERMINAL_RESTRICTION)
          | (MQLInfoInteger(MQL_TRADE_ALLOWED) ? 0 : PROGRAM_RESTRICTION)
          | getTradeRestrictionsOnSymbol(symbol == NULL ? _Symbol : symbolnowmode)
          | getTradeRestrictionsOnAccount();
   }
   
   static bool isTradeEnabled(const string symbol = NULLconst datetime now = 0,
      const ENUM_SYMBOL_TRADE_MODE mode = SYMBOL_TRADE_MODE_FULL)
   {
      lastRestrictionBitMask = 0;
      return pass(getTradeRestrictions(symbolnowmode));
   }

Una comprobación exhaustiva de los permisos de trading con una nueva clase se demuestra con el script AccountPermissions.mq5.

#include <MQL5Book/Permissions.mqh>
   
void OnStart()
{
   PrintFormat("Run on %s"_Symbol);
   if(!Permissions::isTradeEnabled()) // checking for current character, default
   {
      Print("Trade is disabled for the following reasons:");
      Print(Permissions::explainLastRestrictionBitMask());
   }
   else
   {
      Print("Trade is enabled");
   }
}

Si se encuentran restricciones, su máscara de bits puede mostrarse en una clara representación de cadena utilizando el método explainLastRestrictionBitMask.

A continuación se muestran algunos de los resultados del script. En los dos primeros casos, el trading estaba desactivado en la configuración global del terminal (las propiedades TERMINAL_TRADE_ALLOWED y MQL_TRADE_ALLOWED eran iguales a false, lo que corresponde a los bits TERMINAL_RESTRICTION y PROGRAM_RESTRICTION).

Cuando se ejecuta en USDRUB durante las horas en que el mercado está cerrado, recibiremos adicionalmente SESSION_RESTRICTION:

Trade is disabled for USDRUB following reasons:
TERMINAL_RESTRICTION PROGRAM_RESTRICTION SESSION_RESTRICTION 

En el caso del símbolo SP500m, para el que el trading está totalmente desactivado, aparece la bandera SYMBOL_RESTRICTION.

Trade is disabled for SP500m following reasons:
TERMINAL_RESTRICTION PROGRAM_RESTRICTION SYMBOL_RESTRICTION SESSION_RESTRICTION 

Por último, habiendo permitido el trading en el terminal pero habiendo accedido a la cuenta con la contraseña del inversor, veremos ACCOUNT_RESTRICTION en cualquier símbolo.

Run on XAUUSD
Trade is disabled for following reasons:
ACCOUNT_RESTRICTION 

La comprobación anticipada de los permisos en el programa MQL ayuda a evitar intentos fallidos en serie de enviar órdenes de trading.