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

 
Замечена такая не приятная проблема, если запущен скрипт и тот вылетает (закрывает платформу), то лог файл за время работы скрипта не сохраняет записи, а это довольно усложняет выявление ошибки в коде. До этого как-то не замечал такую проблему. Такое всегда было (не сохраняет записи) ?
 

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

 
fxsaber #:

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

Лет пять назад делал. У клиента уменьшали плечо в определенные часы, причем оно никак не менялось в переменной AccountInfoInteger(ACCOUNT_LEVERAGE). И ему нужно было знать об этом.

Не знаю как по научному, но для себя определил, что есть плечо по счету, которое меняется редко, а есть по символу, которое могут менять и несколько раз на дню.
Проверку делал таким образом:

//+------------------------------------------------------------------------------------------------------------------+
//| Проверяет изменение плеча и сообщает если это было
//+------------------------------------------------------------------------------------------------------------------+
void leverageCheck()
{
  if(MarketInfo(Symbol(), MODE_MARGINREQUIRED) == 0) return;

   // --- получаем текущее плечо из маржинальных требований, стоимости пункта, тек.котировки
  double leverageSymb = MarketInfo(Symbol(),MODE_TICKVALUE) * Bid / MarketInfo(Symbol(),MODE_MARGINREQUIRED) / Point;
  leverageSymb = int(MathRound(leverageSymb));
  
   // --- если плечо по символу стало меньше на 10% плеча по счету отметим это
  if(leverageSymb < percVar(AccountInfoInteger(ACCOUNT_LEVERAGE), -10))
  {
    string txt = TimeToString(TimeCurrent()) + " Leverage is reduced 1:" + (string)leverageSymb;
    Print(txt, " but account leverage = " + (string)AccountInfoInteger(ACCOUNT_LEVERAGE));

    // --- вывод информации на график
  }
}

//+-------------------------------------------------------------------------------------------------------------------+
//| Получает переменную, увеличивает или уменьшает его на переданный процент и возвращает новое значение
//| Чтобы уменьшить, нужно передать percent с минусом
//+-------------------------------------------------------------------------------------------------------------------+
double percVar(double var, double percent)
{
  return var*(1 + percent/100);
}


Иногда текущее расчетное плечо по символу leverageSymb могло вместо 200 (когда плечо 1:200) выдавать 199, 198. Поэтому от стандартного плеча приходилось отнимать определенный % и сравнивать с этим значением. Решение выше тогда помогало, может пригодиться.

 
Vasiliy Pushkaryov #:

Лет пять назад делал. У клиента уменьшали плечо в определенные часы, причем оно никак не менялось в переменной AccountInfoInteger(ACCOUNT_LEVERAGE). И ему нужно было знать об этом.

Не знаю как по научному, но для себя определил, что есть плечо по счету, которое меняется редко, а есть по символу, которое могут менять и несколько раз на дню.
Проверку делал таким образом:


Иногда текущее расчетное плечо по символу leverageSymb могло вместо 200 (когда плечо 1:200) выдавать 199, 198. Поэтому от стандартного плеча приходилось отнимать определенный % и сравнивать с этим значением. Решение выше тогда помогало, может пригодиться.

Да, с отслеживанием маржинальных требований символа нет проблема. ACCOUNT_LEVERAGE - только реконнект.

 

Очень распространена практика фильтрации истории торгов путем запоминания нужных ордеров в список тикетов. А затем SELECT_BY_TICKET по этому списку.

Вариант с запоминанием не тикета, а позиции ни разу не видел. Ниже сравнение производительности.

#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006
#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279

int Filter( TICKET_TYPE &Tickets[], int &Pos[] )
{
  const int Total = OrdersHistoryTotal();            

  ArrayResize(Tickets, Total);
  ArrayResize(Pos, Total);
  
  int Amount = 0;

  for (int i = 0; i < Total; i++)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderProfit() > 0))
    {
      Tickets[Amount] = OrderTicket();
      Pos[Amount] = i;
      
      Amount++;
    }
    
  ArrayResize(Tickets, Amount);
  ArrayResize(Pos, Amount);
  
  return(Amount);
}

template <typename T>
double Func1( int TypeSelect, const T &Array[] )
{
  double Res = 0;
  const int Total = ArraySize(Array);
  
  for (int i = 0; i < Total; i++)
    if (OrderSelect(Array[i], TypeSelect, MODE_HISTORY))
      Res += OrderProfit();
      
  return(Res);
}

void OnStart()
{   
  TICKET_TYPE Tickets[];
  int Pos[];

  Print(Filter(Tickets, Pos));
  
  const double Res1 = _B(Func1(SELECT_BY_TICKET, Tickets), 1); // Так делают почти все.
  const double Res2 = _B(Func1(SELECT_BY_POS, Pos), 1);        // Не встречал.
  
  Print(Res1);
  Print(Res2);
}


2021.10.11 01:37:08.254 Test19 EURUSD.rann,M1: 561002.61
2021.10.11 01:37:08.254 Test19 EURUSD.rann,M1: 561002.61
2021.10.11 01:37:08.254 Test19 EURUSD.rann,M1: Alert: Bench_Stack = 0, 1 <= Time[Test19.mq4 49 in OnStart: Func1(SELECT_BY_POS,Pos)] = 2827 mcs.
2021.10.11 01:37:08.251 Test19 EURUSD.rann,M1: Alert: Bench_Stack = 0, 1 <= Time[Test19.mq4 48 in OnStart: Func1(SELECT_BY_TICKET,Tickets)] = 7460 mcs.
2021.10.11 01:37:08.244 Test19 EURUSD.rann,M1: 35936

Видно, что вариант с тикетами проигрывает почти в три раза по производительности.

 
fxsaber #:

Видно, что вариант с тикетами проигрывает почти в три раза по производительности.

если будет закрыта\открыта позиция, логика с тикетом не поломается, логика с позицией может.

 
TheXpert #:

если будет закрыта\открыта позиция, логика с тикетом не поломается, логика с позицией может.

Речь только о MODE_HISTORY-режиме.

 

Существует ли теоретическая возможность, что данный код пропустит какой-то ордер, что существовал ДО и ПОСЛЕ вызова функции? Или же учтет дважды.

double GetLots()
{
  double Lots = 0;
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS))
      Lots += OrderLots();
      
  return(Lots);
}

Т.е. что происходит с индексацией, когда во время перебора какой-то ордер удалится или появится?

 
fxsaber #:

Или же учтет дважды.

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

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

Как получить пропуск на обратном проходе - не придумал

 
Andrei Trukhanovich #:

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

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

Как получить пропуск на обратном проходе - не придумал

Спасибо за подробный ответ! Вот и думаю теперь, как перебрать ВСЕ ордера по ОДНОМУ разу.