Asesores Expertos: Programación en MQL5 para tráders: códigos fuente del libro: Parte 7 - página 2

 
Denis Kirichenko #:

En general, para un libro de texto sería mejor escribir entre paréntesis:

Todos los operadores de la forma @=, donde perrito significa el símbolo de cualquier operación, se ejecutan siempre sobre el operando derecho, contado completamente antes de ejecutar la operación. Esto se trata en la parte 2, en Operaciones de modificación.

El fichero de cálculo de márgenes se describe en la sexta parte, donde se supone que se dominan las partes anteriores. La complejidad aumenta hacia el final del libro - no discuto eso, por lo que traté de hacer referencias a los grandes conceptos y principios de las secciones anteriores de las secciones siguientes, donde se utilizaron como bloques de construcción (para refrescar la memoria), pero no para cosas tan pequeñas.

 
Stanislav Korotky #:

...La complejidad aumenta hacia el final del libro - no hay discusión con eso, así que para los grandes conceptos y principios de las secciones pasadas, traté de hacer referencias de las secciones siguientes donde se utilizó como bloques de construcción (para refrescar mi memoria), pero no para cosas tan pequeñas.

Stanislav, yo tengo un nivel más modesto en programación a diferencia del tuyo. Intento escribir código de forma que sea más fácil comprobarlo en el depurador. Por eso no suelo utilizar el operador ternario. Y si lo hago, lo uso con paréntesis... Hay gente muy hábil que escribe varios operadores ternarios incluidos unos en otros. Esto es algo cercano al estilo de programación de macros de mi colega fxsaber. Probablemente cada enfoque tiene derecho a la vida. Y ya es cuestión de gustos...

¡Gran respeto y respeto por el tutorial! Algunas cosas interesantes se describen con más detalle que en la Documentación.

 
Aleksandr Slavskii #:

De todas formas sirve de poco, porque al final sigue contando mal el margen si el volumen es superior a tres.

Cálculo del margen para diez contratos.

Adjunto el script para comprobarlo. Ahora lo he ejecutado en toda la visión general del mercado - coincide con la función estándar independientemente del volumen.

 
Denis Kirichenko #:

Y el compilador está cabreado:

Probablemente algo cambió en el compilador. En el momento de la publicación del libro, todos los fuentes compilaban sin advertencias ni errores, salvo en los casos en que había irregularidades deliberadas con fines de demostración.

 
Denis Kirichenko #:

Intento escribir código de forma que sea más fácil comprobarlo en el depurador. Por eso no suelo usar el operador ternario. Y si lo hago, lo uso con paréntesis....

Estoy de acuerdo. Yo también sigo esta regla, excepto en casos sencillos, pero aquí cada uno tiene su propia barrera de sencillez. La legibilidad del código se trata de forma individual, por lo general buscamos un "término medio" entre el enfoque "todo en una línea" y "cada token en una línea separada". Con paréntesis - de forma similar. Las empresas de software suelen tener una serie de normas sobre la disposición del código fuente - en este caso no había ninguna.

 
Se han publicado en la base de código más correcciones de errores y mejoras para la lectura del calendario económico y su exportación a CSV. En concreto, se ha corregido el algoritmo de ordenación para el caso de matrices grandes ordenadas en su mayoría (que suelen recibirse de la API de calendario MQL5), de modo que se eliminan las ralentizaciones y los desbordamientos de pila.
Economic Calendar CSV
Economic Calendar CSV
  • www.mql5.com
This script saves a predefined set of economic events from the MetaTrader's built-in economic calendar into CSV file.
 
Stanislav Korotky #:

Adjunto el script para su verificación. Ahora lo he ejecutado en toda la visión general del mercado - coincide con la función estándar independientemente del volumen.

Vaya. No puedo creer que no viera ese mensaje. Vaya.

En realidad, nada ha cambiado para mí.

Servidor Metaquot, terminal versión 4420.

El código es así

#include "MarginProfitMeter.mqh"
//+------------------------------------------------------------------+
int OnInit(void)
  {
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
void OnTimer()
  {
   double margin = 0;
   double volume = 10;
   ENUM_ORDER_TYPE type = ORDER_TYPE_BUY;
   double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   if(_OrderCalcMargin(type, _Symbol, volume, price, margin))
      Print("Symbol ", _Symbol, "; volume ", volume, "; MarginProfitMeter margin = ", margin);

   margin = 0;
   if(OrderCalcMargin(type, _Symbol, volume, price, margin))
      Print("Symbol ", _Symbol, "; volume ", volume, "; OrderCalcMargin margin = ", margin);
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+

El resultado es este.

18:53:40.877    11 (EURUSD,H1)  Symbol EURUSD; volume 10.0; MarginProfitMeter margin = 10421.6
18:53:40.877    11 (EURUSD,H1)  Symbol EURUSD; volume 10.0; OrderCalcMargin margin = 23264.8

Alguien está contando mal.


Puede que me haya deshecho del namespace MPM incorrectamente. No sé qué es y por qué es necesario, pero no me dejó compilar el EA.

En realidad, acabo de quitar la línea namespace MPM , llaves después de él y renombrado OrderCalcMargin, añadió el guión bajo.

En general, el archivo compilado en esta forma. ¿Es posible que este es el error?

//+------------------------------------------------------------------+
//|MarginProfitMeter.mqh
//|Copyright (c) 2018-2022, Marketeer ||
//| https://www.mql5.com/en/users/marketeer |
//|| Un conjunto de funciones para calcular el margen, el beneficio/pérdida potencial, ||
//| valor en puntos y tasas de cobertura.|
//+------------------------------------------------------------------+
// Análogo del OrderCalcMargin incorporado que no está permitido en los indicadores
bool _OrderCalcMargin(const ENUM_ORDER_TYPE action, const string symbol,
                     double volume, double price, double &margin)
  {
   double marginInit, marginMain;
   MqlTick ticks;

// comprueba los parámetros dados
   if((action != ORDER_TYPE_BUY && action != ORDER_TYPE_SELL) || volume < 0 || price < 0)
      return false;

// solicitar todas las propiedades utilizadas en las fórmulas
   if(!SymbolInfoTick(symbol, ticks))
      return false;
   if(!SymbolInfoMarginRate(symbol, action, marginInit, marginMain))
      return false;
   const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   long leverage = AccountInfoInteger(ACCOUNT_LEVERAGE);
   if(volume == 0)
      volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   if(price == 0)
      price = action == ORDER_TYPE_BUY ? ticks.ask : ticks.bid;

   if(margin == DBL_MAX)
      marginInit = marginMain;
   margin = 0;

   const ENUM_SYMBOL_CALC_MODE m = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);

   switch(m)
     {
      case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
         leverage = 1;

      case SYMBOL_CALC_MODE_FOREX:
         margin = volume * contract / leverage * marginInit;
         break;

      case SYMBOL_CALC_MODE_CFD:
         margin = volume * contract * price * marginInit;
         break;

      case SYMBOL_CALC_MODE_CFDINDEX:
         margin = volume * contract * price * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)
                  / SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE) * marginInit;
         break;

      case SYMBOL_CALC_MODE_CFDLEVERAGE:
         margin = volume * contract * price / leverage * marginInit;
         break;

      case SYMBOL_CALC_MODE_EXCH_STOCKS:
      case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
         if(price == 0)
            price = ticks.last;
         margin = volume * contract * price * marginInit;
         break;

      case SYMBOL_CALC_MODE_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
         margin = volume * SymbolInfoDouble(symbol, SYMBOL_MARGIN_INITIAL) * marginInit;
         break;
      default:
         PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
     }

   string account = AccountInfoString(ACCOUNT_CURRENCY);
   string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_MARGIN);
   if(current != account)
     {
      if(!_Convert(current, account, action == ORDER_TYPE_SELL, margin))
         return false;
     }

   return true;
  }

// Búsqueda de símbolos disponibles para un único construido de las monedas "corriente" y "cuenta".
int _FindExchangeRate(const string current, const string account, string &result)
  {
   for(int i = 0; i < SymbolsTotal(true); i++)
     {
      const string symbol = SymbolName(i, true);
      const ENUM_SYMBOL_CALC_MODE m = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
      if(m == SYMBOL_CALC_MODE_FOREX || m == SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE)
        {
         string base = SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE);
         string profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
         if(base == current && profit == account)
           {
            result = symbol;
            return +1;
           }
         else
            if(base == account && profit == current)
              {
               result = symbol;
               return -1;
              }
        }
     }
   return 0;
  }

// Estimar una tasa de símbolo especificada en un momento dado en el pasado
double GetHistoricPrice(const string symbol, const datetime moment, const bool ask)
  {
   const int offset = iBarShift(symbol, _Period, moment);
// Nota: iClose puede contener el último precio en lugar del precio de oferta para los símbolos de bolsa.
// no hay manera rápida de manejar esto, sólo el análisis de la historia de los ticks
   return iClose(symbol, _Period, offset) +
          (ask ? iSpread(symbol, _Period, offset) * SymbolInfoDouble(symbol, SYMBOL_POINT) : 0);
  }

// _Convertir la cantidad de dinero 'actual' en dinero 'de la cuenta
bool _Convert(const string current, const string account,
             const bool ask, double &margin, const datetime moment = 0)
  {
   string rate;
   int dir = _FindExchangeRate(current, account, rate);
   if(dir == +1)
     {
      margin *= moment == 0 ?
                SymbolInfoDouble(rate, ask ? SYMBOL_BID : SYMBOL_ASK) :
                GetHistoricPrice(rate, moment, ask);
     }
   else
      if(dir == -1)
        {
         margin /= moment == 0 ?
                   SymbolInfoDouble(rate, ask ? SYMBOL_ASK : SYMBOL_BID) :
                   GetHistoricPrice(rate, moment, ask);
        }
      else
        {
         static bool once = false;
         if(!once)
           {
            Print("Can't convert ", current, " -> ", account);
            once = true;
           }
        }
   return true;
  }

// Devuelve el valor en puntos (en la moneda de la cuenta) de un símbolo específico
double PointValue(const string symbol, const bool ask = false, const datetime moment = 0)
  {
   const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   const ENUM_SYMBOL_CALC_MODE m = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
   double result = 0;

   switch(m)
     {
      case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
      case SYMBOL_CALC_MODE_FOREX:
      case SYMBOL_CALC_MODE_CFD:
      case SYMBOL_CALC_MODE_CFDINDEX:
      case SYMBOL_CALC_MODE_CFDLEVERAGE:
      case SYMBOL_CALC_MODE_EXCH_STOCKS:
      case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
         result = point * contract;
         break;

      case SYMBOL_CALC_MODE_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
         result = point * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE) / SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
         break;
      default:
         PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
     }

   string account = AccountInfoString(ACCOUNT_CURRENCY);
   string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);

   if(current != account)
     {
      if(!_Convert(current, account, ask, result, moment))
         return 0;
     }

   return result;
  }
//+------------------------------------------------------------------+
 
Aleksandr Slavskii #:

El código es el siguiente

El resultado es el siguiente

Alguien está contando mal.


Aquí se encuentra en las noticias para el comienzo de 2024 (es decir, después de la escritura del libro) sobre build 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342.

Margen flotante por volumen

En la configuración del servidor y en la interfaz de especificación de símbolos han añadido la dependencia del margen del volumen.

No he encontrado la manera de llegar a estas propiedades de MQL5.

En un determinado broker/instrumento esta configuración de margen flotante puede no estar activada, por lo que no he visto ninguna diferencia al comprobar que no en MQ demo.

MetaTrader 5 build 4150: Trading report export and new machine learning methods in MQL5
MetaTrader 5 build 4150: Trading report export and new machine learning methods in MQL5
  • 2024.01.18
  • MetaQuotes
  • www.metatrader5.com
Added export of trading reports to HTML and PDF files. With this option, you can easily share your trading achievements with colleagues and investors. New export commands are available in the File menu and in the report menu. Added ability to save the current state of the Market Watch window to a CSV file. To do this, select Export in the...
 
Stanislav Korotky #:

Se ha añadido la dependencia del margen de volumen a la configuración del servidor y a la interfaz de especificación de símbolos.

No he encontrado cómo llegar a estas propiedades desde MQL5.

También lo he buscado y tampoco lo he encontrado)
Pensaba que era un error de mi cabeza, pero resultó no serlo.
Gracias.
 

@Renat Fatkhullin

¿Hay algún plan para añadir la capacidad de obtener estas propiedades de MQL5?

Foro sobre trading, sistemas automatizados de trading y testeo de estrategias de trading

Asesores Expertos: Programación MQL5 para Traders - códigos fuente del libro. Parte 7

Stanislav Korotky, 2024.11.23 20:26

Aquí he encontrado en las noticias de principios de 2024 (es decir, después de que el libro fue escrito) sobre build 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342.

Margen flotante por volumen

En la configuración del servidor y en la interfaz de especificación de símbolos han añadido la dependencia del margen en el volumen.

No he encontrado la manera de llegar a estas propiedades de MQL5.

En un determinado broker/instrumento esta configuración de margen flotante puede no estar activada, por lo que no he visto ninguna diferencia al comprobar que no en MQ demo.