Discussão do artigo "LifeHack para traders: "amassando" ForEach com os define (#define)" - página 6

 

Como você imagina um artigo? Pego meu código-fonte da KB e começo a descrever no artigo por que decidi aplicar uma macro neste local e por que ela é exatamente assim?

Para cada trabalho na KB, há um tópico de discussão. Lá você pode fazer perguntas sobre os códigos-fonte.

 
fxsaber:

Como você imagina um artigo? Eu pego meu código-fonte da KB e começo a descrever no artigo por que decidi aplicar uma macro neste lugar e por que ela é exatamente assim?

Para cada trabalho na KB, há um tópico de discussão. Lá você pode fazer perguntas sobre os códigos-fonte.

Por exemplo, aqui eu não bato nas cavidades de forma alguma).

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

Não seria ruim descrever essas coisas!

 
Vitaly Muzichenko:

Por exemplo, aqui é onde eu não me esvazio de forma alguma)

Seria bom descrever essas coisas!

Essa é uma macro de várias linhas com cinco parâmetros de entrada. Observe o texto, com quais parâmetros ela é chamada.

Ela cria métodos correspondentes denominados MT4OrderTicket, MT4OrderClosePrice, etc. Os métodos são 95% idênticos no texto e há muitos deles. Para não fazer um enorme copypaste, onde um erro pode facilmente aparecer, é criada uma macro. Tudo é compacto e imediatamente visível.

Além disso, esse código enfatiza o fato de que as funções são 95% iguais. Ou seja, ao lê-lo, você percebe isso imediatamente. Mas se você fosse escrever de forma clássica, só poderia chegar a essa conclusão lendo e analisando o código de 20 métodos (há muitos deles). E isso é uma grande dor de cabeça. Assim, todos os 20 métodos estão em uma tela e tudo é enfatizado para que os métodos quase coincidam. E somente os parâmetros de entrada das macros informam sobre as diferenças. Ao ler, você presta atenção a essas diferenças e não aos enfeites. Ou seja, o código mostra o principal de uma só vez - o núcleo e não uma casca mundana.

 
Vasiliy Sokolov:

As coisas que ele está fazendo são fora do comum e esse é um conhecimento valioso que deve ser compartilhado com o público!

Bem, ele está compartilhando. Algumas de suas postagens e descrições de código na KB são mais informativas do que metade dos artigos aqui.

Também não entendo por que existe um livro de referência artificial, se há respostas ao vivo dele para todas as perguntas feitas.

Seria melhor se Renat se livrasse de seu hábito de bani-lo a cada declaração dura.

 

O desenvolvedor poderia criar um comando adicional "fazer uma cópia do arquivo, substituir as macros sem compilação e abrir o arquivo" para o botão "Compilar" no editor. Especialmente para estudar macros do fxsaber.

Ou você pode usar o comando no menu de contexto. Coloque o mouse sobre a chamada de macro, selecione o comando e o código obtido após a substituição da macro será copiado para o buffer.

 

Em geral, as macros podem ser entendidas da seguinte forma:

1. É necessário separar o nome da macro de seu valor. Primeiro na linha vai #define, depois um espaço, depois esse nome (pode ser com parâmetros), depois outro espaço ou transição para uma nova linha e o valor da macro.

2. Vemos como a macro é chamada no código e quais são seus parâmetros. Faça uma cópia do valor da macro e substitua os parâmetros pelos parâmetros com os quais ela é chamada em algum lugar do código.

3) Onde a macro é chamada no código, substitua-a pelo que obtivemos na etapa 2.

Mais ou menos assim.

Há algumas coisas que você precisa saber: \ - significa continuação em uma nova linha. ## - é uma conexão de linhas.
 
A macro usada com mais frequência por mim

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Recursos da linguagem mql5, sutilezas e técnicas de trabalho

fxsaber, 2017.12.05 11:39 pm.

No modo de depuração, não é possível descobrir o valor que uma função ou expressão retorna.

Por exemplo

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

Por exemplo, o que as funções destacadas retornaram.


Eu uso (não apenas no modo de depuração) desta forma

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

// se (IsDebug)
  {
// DebugBreak(); // se você quiser ver por meio de depuração

    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

Eu o formatei como mqh.

Script de plataforma cruzada como exemplo

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

void OnStart()
{
  // Abre e fecha uma posição de COMPRA
  if (OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, 0), SELECT_BY_TICKET))
    OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100);
}


Digamos que queremos saber o que OrderClosePrice() retorna nesse código. Vamos fazer isso da seguinte forma

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


E aqui está o código se você quiser saber quase tudo (isso acontece quando você não entende onde está o problema em seu próprio código ou no código de outra pessoa).

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

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

void OnStart()
{
  // Abre e fecha uma posição 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));
}

Ou seja, qualquer lugar cujo valor você queira ver, nós o colocamos em _P(). O 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


Ou, por exemplo, existe uma expressão desse tipo

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

Precisamos descobrir rapidamente por que 19602 é a saída. Colocamos as partes que queremos descobrir rapidamente em nossa macro

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


E podemos ver o resultado do cálculo passo a passo

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 Em vez de um pedaço de artigo...

 
#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))

Há um erro: o primeiro processo de símbolo está com o índice de posição 0, o próximo está com o índice de posição 2. Está faltando o índice_de_posição 1 e o loop é executado apenas os_total-1 vezes.

#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))
//+------------------------------------------------------------------+
//| Função de início do programa de script|
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachOrder(orderticket,index)
     {
      Print(index,": #",orderticket," ",OrderGetString(ORDER_SYMBOL)," ",
            EnumToString((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)));
     }
/* Exemplo de saída 
 1: 13965457 CADJPY ORDER_TYPE_SELL_LIMIT
 2: 14246567 AUDNZD ORDER_TYPE_SELL_LIMIT
*/ 
  }

Nesse caso, há o mesmo erro que o anterior.

Além disso, você está misturando funções para trabalhar com ordens abertas e seleção de histórico. Se sua intenção era trabalhar com ordens abertas, não há necessidade de usar HistorySelect().


A propósito, esses bugs demonstram bem o problema com a ausência de macro. É difícil ou impossível 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".

Parei de ler depois disso, desculpe.

 
Talvez você tenha pensado em adicionar mais duas definições para o mql4, OrderCalcProfit() e OrderCalcMargin()
 
daengrani #:
Talvez você tenha pensado em adicionar mais duas definições para mql4, OrderCalcProfit() e OrderCalcMargin()
Não. O terminal antigo não é suportado há muito tempo.