Discusión sobre el artículo "LifeHack para tráders: cocinamos ForEach usando #define" - página 6

 

¿Cómo te imaginas un artículo? Tomo mi código fuente de KB y empiezo a describir en el artículo por qué decidí aplicar una macro en este lugar y por qué es exactamente así?

Para cada trabajo en KB hay un hilo de discusión. Allí puedes hacer preguntas sobre las fuentes.

 
fxsaber:

¿Cómo te imaginas un artículo? Tomo mi código fuente de KB y empiezo a describir en el artículo por qué decidí aplicar una macro en este lugar y por qué es exactamente así?

Para cada trabajo en KB hay un hilo de discusión. Allí puedes hacer preguntas sobre las fuentes.

Por ejemplo, aquí no golpeo huecos en absoluto).

#define  MT4_ORDERFUNCTION(NAME,T,A,B,C)                               \
  static T MT4Order##NAME( void )                                     \
  {                                                                   \
    return(POSITION_ORDER((T)(A), (T)(B), MT4ORDERS::Order.NAME, C)); \
  }

¡No estaría mal describir estas cosas!

 
Vitaly Muzichenko:

Por ejemplo, aquí no me ahueco en absoluto)

¡Estaría bien describir estas cosas!

Esta es una macro de varias líneas con cinco parámetros de entrada. Mira el texto, con que parámetros se llama.

Crea métodos correspondientes llamados MT4OrderTicket, MT4OrderClosePrice, etc. Los métodos son 95% idénticos en el texto y hay muchos de ellos. Para no hacer un copypaste enorme, donde un error puede colarse fácilmente, se hace una macro. Todo es compacto e inmediatamente visible.

Además, este código pone de relieve que las funciones son iguales en un 95%. Es decir, al leerlo, te das cuenta enseguida. Pero si escribieras de forma clásica, sólo podrías llegar a esa conclusión leyendo y analizando el código de 20 métodos (que son muchos). Y esto es un gran dolor de cabeza. Así que los 20 métodos están en una pantalla y se hace hincapié en que los métodos casi coinciden. Y sólo los parámetros de entrada de las macros hablan de las diferencias. Al leer se presta atención a estas diferencias y no al oropel. Es decir, el código muestra lo principal de una vez - el núcleo y no una cáscara mundana.

 
Vasiliy Sokolov:

Las cosas que está haciendo son fuera de lo común. ¡Eso es conocimiento valioso que debería compartirse con el público!

Bueno, él lo está compartiendo. Algunos de sus posts y descripciones de código en KB son más informativos que la mitad de los artículos de aquí.

Tampoco entiendo por qué hay un libro de referencia artificial, si hay respuestas en vivo de él a todas las preguntas formuladas.

Sería mejor si Renat se deshiciera de su costumbre de banearlo por cada declaración dura.

 

¿Podría el desarrollador hacer un comando adicional "hacer una copia del archivo, reemplazar las macros sin compilación y abrir el archivo" al botón "Compilar" en el editor. Especialmente para el estudio de las macros de fxsaber.

O puede utilizar el comando en el menú contextual. Ponga el ratón sobre la llamada de macro, seleccione el comando, el código obtenido después de la sustitución de macros se copia en el búfer.

 

En general, las macros pueden entenderse así:

1. Es necesario separar el nombre de la macro de su valor. Primero en la línea va #define, luego un espacio, tras él este nombre (puede ser con parámetros), luego otro espacio o transición a una nueva línea y el valor de la macro.

2. Vemos cómo se llama a la macro en el código, cuáles son sus parámetros. Haz una copia del valor de la macro y sustituye los parámetros por aquellos parámetros con los que se llama en alguna parte del código.

3. En el lugar del código donde se llama a la macro, sustitúyela por lo que obtuvimos en el paso 2.

Aproximadamente así.

Hay algunas cosas que necesitas saber \ - significa continuación en una nueva línea. ## - es una conexión de líneas.
 
La macro más utilizada por mí

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

Características del lenguaje mql5, sutilezas y técnicas de trabajo

fxsaber, 2017.12.05 11:39 pm.

En modo depuración no se puede averiguar el valor que devuelve una función o expresión.

Por ejemplo.

void OnStart()
{
  double Angle = 1;
  double d = MathSin(Angle / 2) * MathSin(Angle * 2);
}

Por ejemplo, lo que devuelven las funciones resaltadas.


Yo uso (no sólo en modo depuración) de esta manera

template <typename T>
T MyPrint( const T Value, const string Str )
{
  static const bool IsDebug = MQLInfoInteger(MQL_DEBUG);

// if (IsDebug)
  {
// DebugBreak(); // si desea ver por medios de depuración

    Print(Str + " = " + (string)Value);
  }
  
  return(Value);
}

#define _P(A) MyPrint(A, __FUNCSIG__ ", Line = " + (string)__LINE__ + ": " + #A)

void OnStart()
{
  double Angle = 1;
  double d = _P(MathSin(Angle / 2)) * _P(MathSin(Angle * 2));
}


Resultado

void OnStart(), Line = 21: MathSin(Angle/2) = 0.479425538604203
void OnStart(), Line = 21: MathSin(Angle*2) = 0.9092974268256817

Lo he formateado como mqh.

Script multiplataforma como ejemplo

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

void OnStart()
{
  // Abre y cierra una posición de COMPRA
  if (OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, 0), SELECT_BY_TICKET))
    OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100);
}


Supongamos que queremos saber qué devuelve OrderClosePrice() en este código. Hagámoslo así

OrderClose(OrderTicket(), OrderLots(), _P(OrderClosePrice()), 100);


Y aquí está el código por si quieres saberlo casi todo (pasa cuando no entiendes en absoluto dónde está el problema en tu código o en el de otro).

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

#include <Debug.mqh> // https://c.mql5.com/3/173/Debug.mqh

void OnStart()
{
  // Abre y cierra una posición de COMPRA
  if (_P(OrderSelect(_P(OrderSend(_P(_Symbol), _P(OP_BUY), 1, _P(Ask), 100, 0, 0)), _P(SELECT_BY_TICKET))))
    _P(OrderClose(_P(OrderTicket()), _P(OrderLots()), _P(OrderClosePrice()), 100));
}

Es decir, cualquier lugar cuyo valor quieras ver, lo ponemos en _P(). El resultado

void OnStart(), Line = 10: SELECT_BY_TICKET = 1
void OnStart(), Line = 10: Ask = 1.16688
void OnStart(), Line = 10: OP_BUY = 0
void OnStart(), Line = 10: _Symbol = EURUSD
void OnStart(), Line = 10: OrderSend(_P(_Symbol),_P(OP_BUY),1,_P(Ask),100,0,0) = 293785198
void OnStart(), Line = 10: OrderSelect(_P(OrderSend(_P(_Symbol),_P(OP_BUY),1,_P(Ask),100,0,0)),_P(SELECT_BY_TICKET)) = true
void OnStart(), Line = 11: OrderClosePrice() = 1.16678
void OnStart(), Line = 11: OrderLots() = 1.0
void OnStart(), Line = 11: OrderTicket() = 293785198
void OnStart(), Line = 11: OrderClose(_P(OrderTicket()),_P(OrderLots()),_P(OrderClosePrice()),100) = true


O, por ejemplo, existe una expresión de este tipo

void OnStart()
{
  int a = 137;
  double b = 1.37;
  
  int Num = ((a = (int)(a / b)) << 1) * a; // 19602
}

Necesitamos averiguar rápidamente por qué sale 19602. Ponemos las piezas que queremos averiguar rápidamente en nuestra macro

int Num = _P(_P(((a = _P((int)(_P(a / b)))) << 1)) * _P(a));


Y podemos ver el resultado del cálculo paso a paso

void OnStart(), Line = 8: a/b = 99.99999999999999
void OnStart(), Line = 8: (int)(_P(a/b)) = 99
void OnStart(), Line = 8: ((a=_P((int)(_P(a/b))))<<1) = 198
void OnStart(), Line = 8: a = 99
void OnStart(), Line = 8: _P(((a=_P((int)(_P(a/b))))<<1))*_P(a) = 19602


ZY En lugar de un artículo...

 
#define  ForEachSymbol(s,i)  string s=SymbolName(0,true); int os_total=SymbolsTotal(true); for(int i=1;i<os_total;i++,s=SymbolName(i,true))

Hay un error, el primer proceso de símbolo es con position_index 0, el siguiente es con position_index 2. Le falta el position_index 1 y su bucle se ejecuta sólo os_total-1 veces.

#define  ForEachOrder(ticket,i)    HistorySelect(0,TimeCurrent());  ulong ticket=OrderGetTicket(0); int or_total=OrdersTotal();   for(int i=1;i<or_total;i++,ticket=OrderGetTicket(i))
//+------------------------------------------------------------------+
//| Función de inicio del programa de script|
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachOrder(orderticket,index)
     {
      Print(index,": #",orderticket," ",OrderGetString(ORDER_SYMBOL)," ",
            EnumToString((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)));
     }
/* Ejemplo de salida 
 1: 13965457 CADJPY ORDER_TYPE_SELL_LIMIT
 2: 14246567 AUDNZD ORDER_TYPE_SELL_LIMIT
*/ 
  }

En este hay el mismo bug que anteriormente.

Y además estas mezclando funciones para trabajar con ordenes abiertas y selección de histórico. Si tu intención era trabajar con órdenes abiertas, no hay necesidad de usar HistorySelect().


Por cierto estos bugs demuestran bien el problema con sin macro. Es dificil o imposible de depurar.

The most strongest criticism of using #define is the fact that macro substitutions do not allow for code debugging. I agree with this, although, as fxsaber says, "A reliably fixed patient requires no anesthesia debugged macro requires no debugging".

He dejado de leer después de esto, lo siento.

 
MetaQuotes:

Nuevo artículo LifeHack para comerciantes: Mezclando ForEach con defines (#define) ha sido publicado:

Autor: Vladimir Karputov

quizás consideraste añadir 2 defines más para mql4, OrderCalcProfit() y OrderCalcMargin()
 
daengrani #:
quizás consideraste añadir 2 defines más para mql4, OrderCalcProfit() y OrderCalcMargin()
No. El antiguo terminal no se soporta desde hace mucho tiempo.