Обсуждение статьи "LifeHack для трейдера: замешиваем ForEach на дефайнах (#define)" - страница 6

 
fxsaber:

Как представляете себе статью?! Беру свой исходник из КБ и начинаю в статье расписывать, почему решил применить в этом месте макрос и почему он именно такой?

К каждой работе в КБ есть ветка обсуждений. Там можно задавать вопросы и по исходникам.

К примеру, вот здесь Я вообще дупля не отбиваю)

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

Было-бы не плохо описать вот такие вещи!

 
Vitaly Muzichenko:

К примеру, вот здесь Я вообще дупля не отбиваю)

Было-бы не плохо описать вот такие вещи!

Это многостроковый макрос с пятью входными параметрами. Посмотрите по тексту, с какими параметрами он вызывается.

Он создает соответствующие методы с названиями MT4OrderTicket, MT4OrderClosePrice и т.д. Методы на 95% совпадают по тексту и их много. Чтобы не городить огромную копипасту, где может легко закрасться ошибка, делается макрос. Все компактно и сразу видно.

Более того, такой код подчеркивает, что функции на 95% одинаковые. Т.е. при чтении сразу об этом понимаешь. А вот если бы написать классически, то такой вывод можно было бе сделать только прочитав и проанализировав код 20-ти (там столько их) методов. А это нехилая головная боль. А так все 20 методов на одном экране и все подчеркнуто, что методы почти совпадают. И только входные параметры макросов говорят об отличиях. Вот на эти отличия, а не на мишуру при чтении и обращаешь внимание. Т.е. код сразу показывает главное - ядро, а не муторную оболочку.

 
Vasiliy Sokolov:

Те штуки, которые он проделывает дают нестандартные фишки. Это ценные знания, которыми надо делиться с общественностью! 

Ну так он делится. Некоторые его посты и описания к коду в КБ содержательнее половины здешних статей.

Тоже не понимаю, зачем искусственный справочник, если есть живые ответы от него на все задаваемые вопросы.

Лучше бы Ренат избавился от привычки банить его за каждое резкое высказывание.

 

Сделали бы разработчик в редактор к кнопке "Компилировать" дополнительную команду "сделать копию файла, заменить макросы без компиляции и открыть файл". Специально для изучения макросов от  fxsaber. 

Ну или же в контекстное меню команду. Ставим мышку на вызов макроса, выбираем команду, в буфер копируется код, получаемый после замены макроса. 

 

Вообще макросы вот так можно понять:

1. Надо отделить имя макроса от его значения. Сначала в строке идет #define, потом пробел, после него это имя (оно с параметрами может быть), потом еще пробел или переход на новую строку и значение макроса.

2. Смотрим как макрос вызывается в коде, какие у него параметры. Делаем себе копию значения макроса и делаем замену параметров на те параметры, с которыми он вызывается где-то в коде.

3. Там, где в коде вызывается макрос заменяем его на то что получилось в п.2.

Примерно так.

Тут нужно кое-что знать: \ - это означает продолжение на новой строке. ## - это соединение строк.
 
Самый часто применяемый мною макрос

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

fxsaber, 2017.12.05 11:39

В дебаг-режиме нельзя узнать значение, которое возвращает функция или выражение.

Например

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

Например, что вернули выделенные функции.


Использую (не только в дебаг-режиме) такой способ

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

//  if (IsDebug)
  {
//    DebugBreak(); // если хочется посмотреть средствами дебага

    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));
}


Результат

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

Оформил его в виде mqh.

В качестве примера кроссплатформенный скрипт

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

void OnStart()
{
  // Открывает и закрывает BUY-позицию
  if (OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, 0), SELECT_BY_TICKET))
    OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100);
}


Ну и захотелось, допустим, узнать, что возвращает в этом коде OrderClosePrice(). Делаем так

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


А вот код, если захотелось узнать почти все (такое бывает, когда совсем не понимаешь, где проблема в своем или чужом коде)

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

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

void OnStart()
{
  // Открывает и закрывает BUY-позицию
  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));
}

Т.е. любое место, значение которого хочется увидеть, облачаем в _P(). Результат

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


Или, например, есть такое выражение

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

Нужно быстро врубиться, почему же 19602 выходит. Облачаем быстро интересуемые куски в наш макрос

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


И видим пошагово результат вычисления

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


ЗЫ За вместо куска статьи...

Причина обращения: