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

 
При вызове макроса можно не указать какой-либо параметр (пропустить его), иногда хочется специально предусмотреть возможность работы макроса с неуказанным параметром.


Для таких случаев привожу несколько вспомогательных макросов.

1. Иногда возникает желание определить внутри своего макроса, был ли параметр задан или нет.  IS_PARAMETER_SET(p) задает выражение, которое возвращает true если p задан (даже если строковой переменной ==NULL).

Внимание: выражение вычисляется после препроцессинга на этапе компиляции!!!, т.е. с его помощью нельзя реализовать что-то типа #ifdef IS_PARAMETER_SET(p)  #else.   (это относится и другим макросам ниже)

2. Если надо явно преобразовать значение параметра в строку, чтобы не получить ошибку компиляции при незаданном параметре можно использовать __EVAL_STR(p).  Если p не задан или явно задан литералом NULL, возвращает "". Не применяется для массивов, структур и классов.

3. Явное преобразование параметра в число - __EVAL_NON_STR(p). Если p не задан, возвращает 0. неверно работает когда p строка!

Код и примеры использования:

//Expression returns true if macro's parameter is specified.
#define IS_PARAMETER_SET(p) ("" != #p || __hlp_macro_func(p))
bool __hlp_macro_func(const string p = NULL) {return "" == p;}
template<typename T> bool __hlp_macro_func(T p)    {return true;}
template<typename T> bool __hlp_macro_func(T& p)   {return true;}
template<typename T> bool __hlp_macro_func(T& p[]) {return true;}


//Expression returns parameter p; if parameter is not specified returns NULL; if p is string returns p
//Error for arrays and objects
#define __EVAL(p) (""==#p?NULL:p+NULL)


//Explicit conversion to string. If parameter is not specified or is constant NULL returns ""
//Error for arrays and objects
#define __EVAL_STR(p) (""==#p || "NULL"==#p? "" :(string)(p+NULL))


//Explicit conversion to number. If parameter is not specified returns 0. Works incorrect if p is string!
//Error for arrays and objects
#define __EVAL_NON_STR(p) ("" == #p? 0 : p+0)


struct S1
  {   int               a; };
class C1
  { int               a; };

void OnStart()
  {
//---
   Print(IS_PARAMETER_SET());                //false
   Print(IS_PARAMETER_SET(""));              //true
   Print(IS_PARAMETER_SET("test"));          //true
   Print(IS_PARAMETER_SET(NULL));            //true
   Print(IS_PARAMETER_SET(0));               //true
   Print(IS_PARAMETER_SET(1));               //true
   string str;
   Print(IS_PARAMETER_SET(str));             //true

   int arr[1];
   Print(IS_PARAMETER_SET(arr));             //true
   S1 _struct;
   Print(IS_PARAMETER_SET(_struct));         //true
   C1 _class;
   Print(IS_PARAMETER_SET(_class));          //true

#define  MACRO1_(a,b)  (IS_PARAMETER_SET(b)?a:-a)
   Print(MACRO1_(1, 0));                     //1
   Print(MACRO1_(1,));                       //-1

#define  MACRO2_(a,b,c)  Print(a," = ",b + c)
#define  MACRO3_(a,b,c)  Print(__EVAL_STR(a)," = ",__EVAL_NON_STR(b) + __EVAL_NON_STR(c))

 //MACRO2_(, 2,);                            // ',' - syntax error, parameter missed
   MACRO3_(, 2,);                            // = 2
   MACRO3_("a", 2, 3);                       // a = 5
  }


 
fxsaber:

Следующим кодом на демо-счете RannForex-Server можно сразу воспроизвести эту ситуацию, если запустить этот советник.


Результат.


Попутно скрипт показывает (не всегда с первого раза) баг выполнения синхронного OrderSend.

После выполнения OrderSend в течение нескольких десятков/сотен миллисекунд цена ордера старая, а не та, что успешно выставил OrderSend.


Возвращаясь к теме одинаковых тикетов, можно сделать некоторые выводы.

  1. Если висит partial-лимитник, то во вкладке "Ордера и сделки" не будет видно порожденной сделки.
  2. На хедже один ордер может породить несколько IN-сделок с разными ценами. В итоге получится дробная (относительно пунктов) цена открытия позиции.
  3. Вы можете закрыть сформированную позицию, не удаляя Partial-отложку. Но если после этого отложка сработает, то откроет сделка с тикетом, равным тикету до этого закрытой позиции. Т.е. может быть ситуация, когда вы закрываете позицию с определенными тикетом. А потом появляется позиция снова с этим же тикетом.
  4. Частичное исполнение может быть по-разному реализовано, в зависимости от софта брокера. Выше описал стандартную MT5-реализацию.

ЗЫ Если у кого-то получилось воспроизвести на другом торговом сервере, поделитесь названием.

Строка для поиска: Oshibka 010.

Опять возвращаюсь к вопросу о частичном исполнении.

1. Прошу уточнить по п.3: "Вы можете закрыть сформированную позицию, не удаляя Partial-отложку. Но если после этого отложка сработает, то откроет сделка с тикетом, равным тикету до этого закрытой позиции. Т.е. может быть ситуация, когда вы закрываете позицию с определенными тикетом. А потом появляется позиция снова с этим же тикетом."       
В этом случае POSITION_IDENTIFIER был равен POSITION_TICKET или нет?

2. Ранее в ветке "POSITION_TICKET != POSITION_IDENTIFIER" вы демонстрировали другую логику работы MT5.

https://www.mql5.com/ru/forum/227423/page2#comment_6543129

fxsaber:

Выводы

Если считать, что это штатное поведение MT5, а не особенности хака брокера, то

  • ORDER_STATE_PARTIAL у исторических ордеров не бывает.
  • Исполненнные ордера всегда имеют статус ORDER_STATE_FILLED.
  • При частичном исполнении создаются соответствующие новые маркет ордера торговым сервером (ORDER_REASON_CLIENT - даже если исходный ордер выставлен автоматом(EXPERT)).
  • Старый живой ордер (тикет не изменяется) остается висеть с уменьшенным объемом (ORDER_VOLUME_CURRENT).
  • Старый живой ордер при этом получает статус ORDER_STATE_PARTIAL. Фактически, этот флаг является результатом сравнения ORDER_VOLUME_CURRENT и ORDER_VOLUME_INITIAL.
  • Все открываемые позиции получают ID == OrderTicket. Где OrderTicket - тикеты, порождаемые торговым сервером.
  • Торговая сделка всегда имеет ровно один исторический ордер и его статус ORDER_STATE_FILLED.
  • Каждый исполненный исторический ордер имеет ровно одну сделку.
  • У любого исполненного ордера ORDER_VOLUME_INITIAL равен объему, на который он исполнился. Т.е. даже исходный раздербаненный ордер после полного исполнения имеет ORDER_VOLUME_INITITAL равный объему порожденной им сделки.
  • Время исходного ордера (который частично исполнялся) не меняется и не равно времени его сделки.
  • В исторической таблице идет сортировка по времени ордеров (ORDER_TIME_SETUP), не сделок. Поэтому если делать HistorySelect от DEAL_TIME, можно не получить в историческую таблицу соответствующий ордер.
  • HistorySelectByPosition всегда возвращает необходимое множество сделок/ордеров.
  • Для любой торговой сделки можно вычислить величину проскальзывания.

По вашему опыту, проявилась ли какая-то общая закономерность, в каких случаях/режимах работы какая схема применяется МТ5?

3. В конечном итоге, были ли когда-нибудь реальные ситуации, когда "POSITION_TICKET != POSITION_IDENTIFIER" ?

POSITION_TICKET != POSITION_IDENTIFIER
POSITION_TICKET != POSITION_IDENTIFIER
  • 2018.02.12
  • www.mql5.com
зная id позиции можно ли без перебора узнать тикет позиции...
 
mktr8591:
При вызове макроса можно не указать какой-либо параметр (пропустить его), иногда хочется специально предусмотреть возможность работы макроса с неуказанным параметром.
Получается, что неуказанный параметр в любых макросах воспринимается компилятором, как пустая строка?
 
fxsaber:
Получается, что неуказанный параметр в любых макросах воспринимается компилятором, как пустая строка?

В каком-то смысле да, хотя, может быть, лучше сказать "как пустое место". Затрудняюсь четко сформулировать :-(.

А вот #p точно превращает в строку ==""

 
mktr8591:

В каком-то смысле да, хотя, может быть, лучше сказать "как пустое место". Затрудняюсь четко сформулировать :-(.

А вот #p точно превращает в строку ==""

Спасибо, интересный нюанс.

 

@fxsaber

Посмотрите, плиз, этот вопрос: https://www.mql5.com/ru/forum/170952/page201#comment_21964923

Особенности языка mql5, тонкости и приёмы работы
Особенности языка mql5, тонкости и приёмы работы
  • 2021.04.03
  • www.mql5.com
В данной теме будут обсуждаться недокументированные приёмы работы с языком mql5, примеры решения тех, или иных задач...
 
mktr8591:

Опять возвращаюсь к вопросу о частичном исполнении.

1. Прошу уточнить по п.3: "Вы можете закрыть сформированную позицию, не удаляя Partial-отложку. Но если после этого отложка сработает, то откроет сделка с тикетом, равным тикету до этого закрытой позиции. Т.е. может быть ситуация, когда вы закрываете позицию с определенными тикетом. А потом появляется позиция снова с этим же тикетом."       
В этом случае POSITION_IDENTIFIER был равен POSITION_TICKET или нет?

2. Ранее в ветке "POSITION_TICKET != POSITION_IDENTIFIER" вы демонстрировали другую логику работы MT5.

https://www.mql5.com/ru/forum/227423/page2#comment_6543129

По вашему опыту, проявилась ли какая-то общая закономерность, в каких случаях/режимах работы какая схема применяется МТ5?

3. В конечном итоге, были ли когда-нибудь реальные ситуации, когда "POSITION_TICKET != POSITION_IDENTIFIER" ?

Обе ссылки рассказывают о разных реализациях частичного исполнения. Это определяется софтом брокера, не MT5.

Несовпадение тикета и ID не встречал.

 
Спасибо.
 

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

Библиотеки: Usage

fxsaber, 2021.05.01 14:17

GetMicrosecondCount может выдать значение меньше, чем на предыдущем вызове (без ULONG-переполнения). Примеры таких ситуаций.
2021.04.29 06:43:31.915   Alert: NewValue = 296000074313, PrevValue = 296001329284

2021.04.29 06:43:32.149   Alert: NewValue = 296086250613, PrevValue = 296087264090

2021.04.29 06:43:31.868   Alert: NewValue = 295129291901, PrevValue = 295130576710

2021.04.29 06:43:32.180   Alert: NewValue = 295955613012, PrevValue = 295956589070

2021.04.29 06:43:32.180   Alert: NewValue = 295146223171, PrevValue = 295147199454

2021.04.29 06:43:32.149   Alert: NewValue = 295065995432, PrevValue = 295067005968

2021.04.29 06:43:32.149   Alert: NewValue = 295078776581, PrevValue = 295079787357

Каждая строка получена разными советниками на трех терминалах MT4.

И на MT5 подобное происходит, но значительно реже MT4.

Будьте аккуратны.

 
Комментарии, не относящиеся к этой теме, были перенесены в "Вопросы от начинающих MQL5 MT5 MetaTrader 5".
Причина обращения: