Ваши вопросы по языку MQL4

AlexeyVik

Программист mql4 mql5
Я вот призадумался. Ведь многие функции, которые используются один раз за определённый момент времени(иногда довольно длинный), чтобы код эксперта работал быстрее, нужно в плане оптимизации вызывать как можно меньше. Но это и так понятно. Я хотел сказать, что, буквально вчера думал над некоторыми вариантами. Начал с функции модификации ордеров(первоначальной установки тейки и стопа). Для краткости назовём её ФМО, что бы ниже по контексту не писать больше, чем можно.
Я вижу 2 варианте реализации (если кто-нибудь может добавить.. буду очень рад!):

1. ФМО можно вызывать сразу из функции посыла ордера, неважно рыночного или отложенного, при условии, что ордер послан успешно и выбран его тикет:
PHP:
if (ticket > 0)
{  
                if (SL != 0.0 || TP != 0.0)
                {
                    double ld_SL = 0.0, ld_TP = 0.0;
                    if (OrderSelect (li_Ticket, SELECT_BY_TICKET))
                    {
                        fOrderModify (ticket, OrderOpenPrice(), SL, TP, 0, 0);
                    }
                }
            }
Но при торговле на реале ордер может не модифицироваться, и, значится, нужно в старте снова вызывать функцию ФМО, чтобы установить стопы и теки ордерам, у которых ещё они не установлены.
2. Как-вариант, можно вообще в функции посылающей ордера не ставить ничего, а всё вызывать из старта.
В любом случает, приходится вызывать ФМО из старта постоянно, и, на каждом тике, а не, например, раз за бар или какое-то время. А удобно было как-то оптимизировать код, чтобы не вызывать ФМО из старта постоянно. Т.к. это экономия ресурсов, и выполнение лишних операции.

Есть какие-нибудь варианты решения данной ситуации?
Я думаю и у тебя есть функция проверки наличия ордеров этого советника. И вызывается она в любом случае с каждым тиком, ну мало-ли... может и закрылся какой-то ордер. Вот в эту проверку и поставь если(сл == 0 или тп == 0) ФМО;
 

hoz

Активный участник
Я думаю и у тебя есть функция проверки наличия ордеров этого советника.
Конечно есть! И очень качественная.

И вызывается она в любом случае с каждым тиком, ну мало-ли... может и закрылся какой-то ордер. Вот в эту проверку и поставь если(сл == 0 или тп == 0) ФМО;
Просто мне иногда кажется, что если на каждом тике выполнять кучу операций, может быть больше реквот.
Может это от того, что нет опыта торговли в реале именно совами(т.к. руками торгуя реквот точно не было..)
Получается лучше в старте запускать цикл перебора ордеров и в нём по очерёдно всё делать?

Кстати. Не будет ли самым верным решением создать глобальный флаг, который будет после посыла ордера становится например в какой-то режим, а пока он в таком режиме, это значит, что он поднят. А пока он поднят, модификацию запускать... Если он в другом режиме, а сменяться режим будет только в случае успешной модификации ордера, то значит больше пока новые ордера не появятся, не нужно модифицировать ничего.
Как Вам такая ситуация? Только вот тут есть момент, опять же.. нужно перебирать все ордера, и через счётчик проверять условия (типа сл != 0 или тп != 0 или равны нуля, в зависимости от условия..)
 
Последнее редактирование:

jib07

Местный житель
Конечно есть! И очень качественная.


Просто мне иногда кажется, что если на каждом тике выполнять кучу операций, может быть больше реквот.
Вообще непонятно на какой стадии Вы модите ордер, при его постановке или при каком то условии, почему на каждом тике выполняется модификация. Есть вариант долбить сервер пока он не поставит все что надо, конечно с интервалами и фильтрацией все возможных ошибок, при этом сова будет занята только этой проблемой, после постановки сова продолжит свою работу без всяких модифакаций на каждом тике)))
А проверка типа (sl+tp > 0) не многовариантна, а если у меня есть ордера которым СЛ и ТП не нужны, к чему геморой такой не понятно)))
 

qqmber

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

Тут полезно понимать, что функции, выполняющиеся локально в терминале (OrderSelect(), OrderStopLoss() и т.п.), а также вся математика, исполняются ГОРАЗДО быстрее торговых функций, требующих обращения к серверу (OrderSend(), OrderModify() ... ). Так что проход по всем ордерам в цикле не займет и сотой доли времени, нужного для OrderModify() и этой долей обычно можно смело пренебречь.
Только в особо тяжелых случаях, если например надо всю историю из десятков тысяч ордеров перелопатить или большую матрицу, к примеру, обращать на каждом тике, тогда есть смысл думать об оптимизациях.
 

hoz

Активный участник
Вообще непонятно на какой стадии Вы модите ордер, при его постановке или при каком то условии, почему на каждом тике выполняется модификация. Есть вариант долбить сервер пока он не поставит все что надо, конечно с интервалами и фильтрацией все возможных ошибок, при этом сова будет занята только этой проблемой, после постановки сова продолжит свою работу без всяких модифакаций на каждом тике)))
А проверка типа (sl+tp > 0) не многовариантна, а если у меня есть ордера которым СЛ и ТП не нужны, к чему геморой такой не понятно)))

Я имел ввиду первоначальную модификацию. Если иная, то это уже другое дело же. Там уже по сигналу какому-то.. Каждый тик тут не причём.
Как-раз таки, чтоб не долбить сервер до потери пульса своей текущей задачей (модификацией) я и задал вопрос.

У меня вот сейчас не удаляет отложку. В старте так:

PHP:
if (isCloseByTakeLastOpenPos(2))
      {
          Print("Вошли в функцию isCloseByTakeLastOpenPos");
          ClosePosBySortLots();
          Print("Функция ClosePosBySortLots закрыла все рыночные ордера");
          DeletePendingOrders();
          Print("Функция DeletePendingOrders завершена");
      }


Условие if (isCloseByTakeLastOpenPos(2)) выполняется... Когда она выполнилась, это значит, что нужно закрыть всё (отложенники и рыночные ордера). Срабатывает функция ClosePosBySortLots()
Она закрывает все рыночные ордера.
Дальше DeletePendingOrders() должна удалить все отложки. Но отложка не закрывается почему-то. Вот данная функция:

PHP:
//+-------------------------------------------------------------------------------------+
//| Удаление несработанных отложенные ордеров                                           |
//+-------------------------------------------------------------------------------------+
void DeletePendingOrders()
{
    int delCount = 0,
        err,
        ticket;

   for (int i=OrdersTotal()-1; i>=0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS,MODE_TRADES)) continue;
      if (OrderMagicNumber() != i_magic) continue;
      if (OrderSymbol() != Symbol()) continue;
      if (OrderType() > 1)
      {
         ticket = OrderTicket();
      
         while(delCount < 3)
         {
            while (!IsTradeAllowed()) Sleep(5000);
      
            if (OrderDelete(ticket, Red))
                delCount = 3;
            else
                err = GetLastError();
      
            if (err > 0)
            { 
              Print(delCount," #",ticket," Error modifing order: (", err , ") ");
              Sleep(5000); RefreshRates(); delCount++;
            }
         }
      }
   }
}


В чём может быть загвоздка?

В журнале написало типа функция удаления отложек отработала:




Значит всё-таки функция косячит. Но канкретно я не нашёл сам ошибки.
 
Последнее редактирование модератором:

hoz

Активный участник
Добавил обнуление счётчика попыток. По прежнему не работает:
PHP:
void DeletePendingOrders()
{
    int numberOfTry = 0,
        err,
        ticket;

   for (int i=OrdersTotal()-1; i>=0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if (OrderMagicNumber() != i_magic) continue;
      if (OrderSymbol() != Symbol()) continue;
      if (OrderType() > 1 && OrderType() < 6)
      {
         ticket = OrderTicket();
         numberOfTry = 0;
      
         while (numberOfTry < 3)
         {
            while (!IsTradeAllowed()) Sleep(5000);
                err = 0;
              Print("IsTradeAllowed() = ", IsTradeAllowed());
              Print("err = ", err);

            if (OrderDelete(ticket, Red))
            {
                numberOfTry = 3;
                Print("numberOfTry = ", numberOfTry);
            }
            else
            {
                err = GetLastError();
                Print("err = ", err);
            }
      
            if (err > 0)
            { 
              Print(numberOfTry," #",ticket," Error modifing order: (", err , ") ");
              Sleep(5000); RefreshRates(); numberOfTry++;
            }
         }
      }
   }
}
 
Последнее редактирование модератором:

jib07

Местный житель
Код:
if (DeletePendingOrders() == 0)
  Print("Функция DeletePendingOrders завершена");
else
  Print("Ошибка удаления отложек!");
void DeletePendingOrders() 
{ 
    int delCount = 0, 
        err, 
        ticket,
        kolord=0; 

   for (int i=OrdersTotal()-1; i>=0; i--) 
   { 
      if (!OrderSelect(i, SELECT_BY_POS,MODE_TRADES)) continue; 
      if (OrderMagicNumber() != i_magic) continue; 
      if (OrderSymbol() != Symbol()) continue; 
      if (OrderType() > 1) 
      { 
         ticket = OrderTicket(); 
       
         while (delCount < 3) 
         { 
            while (!IsTradeAllowed()) Sleep(5000); 
       
            if (OrderDelete(ticket, Red)) 
                delCount = 3; 
            else 
                err = GetLastError(); 
       
            if (err > 0) 
            {  
              Print(delCount," #",ticket," Error modifing order: (", err , ") "); 
              Sleep(5000); RefreshRates(); delCount++; 
            } 
         } 
      } 
   } 
  for (int i=OrdersTotal()-1; i>=0; i--) 
   { 
      if (!OrderSelect(i, SELECT_BY_POS,MODE_TRADES)) continue; 
      if (OrderMagicNumber() != i_magic) continue; 
      if (OrderSymbol() != Symbol()) continue; 
      if (OrderType() > 1) 
      { 
         kolord++;
      }
  return(kolord);
}

вот с проверкой отсутствия отложек, но по скрину видно что 10я отложка поставилась после функции удаления, так что проблема не в закрытии, а в логики постановки)))
Немного не так, подправил))
 
Последнее редактирование модератором:
  • Like
Реакции: hoz

hoz

Активный участник
Есть функция для определения минимальной разрядности лота:

PHP:
int LotDecimal()
{return (MathCeil (MathAbs (MathLog (bd_LOTSTEP) / MathLog (10))));}


Мне вот интересно, зачем тут логарифм, и, причём натуральный. Зачем деление одно на другое? Что вообще автор хотел этой функций реализовать?
 

eevviill

Заблокирован
...
Дальше DeletePendingOrders() должна удалить все отложки. Но отложка не закрывается почему-то. Вот данная функция:
...

Хочу дать тебе совет. Я понимаю что ты не новичок в програмировании. Но надо писать чем по проще. Чесно говоря мне твой код читать так же сложно как дэкомпил.

Почему например не использовать что то типа
PHP:
////////////////////////////////////////////////////////////////////////////////
void Close_all()
{
for(int i=OrdersTotal()-1; i>=0; i--)
 {
 if(OrderSelect(i, SELECT_BY_POS))
 {
 if(OrderMagicNumber()==magic)
 {
 if(OrderSymbol()==Symbol())
 {
 bool ticket_ex=false;
 for (int j_ex = 0;j_ex < попытки закрыть; j_ex++)
 {
 while(IsTradeContextBusy()) Sleep(пауза перед повторной попыткой*1000);
 RefreshRates();
 
 if(OrderType()==OP_SELLSTOP || OrderType()==OP_BUYSTOP || OrderType()==OP_SELLLIMIT || OrderType()==OP_BUYLIMIT) ticket_ex=OrderDelete(OrderTicket(),CLR_NONE);
 if(ticket_ex==true)break;
 }
 }
 }
 }
 }
 
}
 

ansol

Местный знаток
Есть функция для определения минимальной разрядности лота:

PHP:
int LotDecimal()
{return (MathCeil (MathAbs (MathLog (bd_LOTSTEP) / MathLog (10))));}


Мне вот интересно, зачем тут логарифм, и, причём натуральный. Зачем деление одно на другое? Что вообще автор хотел этой функций реализовать?

А вы в школе математику учили? ;)
Вычисляется логарифм по основанию 10 от bd_LOTSTEP, автор предполагает, что будет либо 2, либо 1, т.к. берется модуль и он, автор, думает, что лотстеп бывает 0.1 или 0.01
 

hoz

Активный участник
...
Дальше DeletePendingOrders() должна удалить все отложки. Но отложка не закрывается почему-то. Вот данная функция:
...

Хочу дать тебе совет. Я понимаю что ты не новичок в програмировании. Но надо писать чем по проще. Чесно говоря мне твой код читать так же сложно как дэкомпил.

Почему например не использовать что то типа
PHP:
////////////////////////////////////////////////////////////////////////////////
void Close_all()
{
for(int i=OrdersTotal()-1; i>=0; i--)
 {
 if(OrderSelect(i, SELECT_BY_POS))
 {
 if(OrderMagicNumber()==magic)
 {
 if(OrderSymbol()==Symbol())
 {
 bool ticket_ex=false;
 for (int j_ex = 0;j_ex < попытки закрыть; j_ex++)
 {
 while(IsTradeContextBusy()) Sleep(пауза перед повторной попыткой*1000);
 RefreshRates();
 
 if(OrderType()==OP_SELLSTOP || OrderType()==OP_BUYSTOP || OrderType()==OP_SELLLIMIT || OrderType()==OP_BUYLIMIT) ticket_ex=OrderDelete(OrderTicket(),CLR_NONE);
 if(ticket_ex==true)break;
 }
 }
 }
 }
 }
 
}

Ты прав. Но тут есть один момент. Я начинал изучать язык с таких жёстких кодов, что для меня это уже типа нормально. Хотя, опять же, периодически не понимаю, что происходит у меня в коде, и, всё потому, что он не всегда очевиден.
Буду стараться упрощать..
 

hoz

Активный участник
А вы в школе математику учили? ;)
Вычисляется логарифм по основанию 10 от bd_LOTSTEP, автор предполагает, что будет либо 2, либо 1, т.к. берется модуль и он, автор, думает, что лотстеп бывает 0.1 или 0.01

Да вроде как учил.. было дело:facepalm:
Давайте разложим всё по полочкам...
Есть функция:

PHP:
int LotDecimal()
{
    return (MathCeil (MathAbs (MathLog (bd_LOTSTEP) / MathLog (10))));
}

Тут:

PHP:
 bd_LOTSTEP = MarketInfo (Symbol(), MODE_LOTSTEP);


Идём дальше..

PHP:
MathLog (bd_LOTSTEP) / MathLog (10) = MathLog bd_LOTSTEP по основанию 10

PHP:
MathLog bd_LOTSTEP по основанию 10 = -4.605

Теперь первоначальное выражение будет иметь вид:

PHP:
int LotDecimal()
{
    return (MathCeil (MathAbs (-4.605)));
}


Дальше:

PHP:
int LotDecimal()
{
    return (MathCeil (4.605));
}

А оно возвратит нам 5.

Что это даёт? Логики я не нахожу тут..
 

ansol

Местный знаток
Десятичный логарифм от лотстеп будет -1 или -2 для лотсттеп равного 0.1 и 0.01 соответственно.
0.01 = 10**(-2) так понятнее?
 

ansol

Местный знаток
_http://ru.wikipedia.org/wiki/Логарифм
Формула в разделе "Замена основания логарифма"
 
Последнее редактирование модератором:

hoz

Активный участник
Десятичный логарифм от лотстеп будет -1 или -2 для лотсттеп равного 0.1 и 0.01 соответственно.
0.01 = 10**(-2) так понятнее?


Хм. Я подумал, в принципе да, так и получается. Но а есть в такой функции толк? По-моему, если есть вариант получить шаг из маркетинфо, то это вообще бред какой-то.

Это я так от любопытства капал библиотеки одного программиста. Вот думаю, то ли он совсем завёрнутый в никуда, либо есть в его коде рациональное зерно..
 
Последнее редактирование:

ansol

Местный знаток
Хм. Я подумал, в принципе да, так и получается. Но а есть в такой функции толк? По-моему, если есть вариант получить шаг из маркетинфо, то это вообще бред какой-то.

Это я так от любопытства капал библиотеки одного программиста. Вот думаю, то ли он совсем завёрнутый в никуда, либо есть в его коде рациональное зерно..

Если вы рассчитываете лот по ММ, то потом его нужно нормализовать:
Lot = NormalizeDouble(Lot, циферка_какая-то)
если шаг лота 0.01, то циферка 2, а если 0.1 - единичка. ;)
Если считать размер лота в процентах от эквити, к примеру, то получится много знаков после запятой и в функцию OrderSend такую шнягу напрямую втыкать нельзя.

Ну, это моё объяснение, ИМХО, так сказать
 
  • Like
Реакции: hoz

eevviill

Заблокирован
Если вы рассчитываете лот по ММ, то потом его нужно нормализовать:
Lot = NormalizeDouble(Lot, циферка_какая-то)
если шаг лота 0.01, то циферка 2, а если 0.1 - единичка. ;)
Если считать размер лота в процентах от эквити, к примеру, то получится много знаков после запятой и в функцию OrderSend такую шнягу напрямую втыкать нельзя.

Ну, это моё объяснение, ИМХО, так сказать
Да. Именно для того.
Я пользуюсь таким способом.
PHP:
int nor_lot;

//////////////////////////////////////////////////////////////
void init()
{  
if(MarketInfo(Symbol(),MODE_LOTSTEP)==0.1) nor_lot=1;
if(MarketInfo(Symbol(),MODE_LOTSTEP)==0.01) nor_lot=2;
}
 
  • Like
Реакции: hoz

ansol

Местный знаток
Да. Именно для того.
Я пользуюсь таким способом.
PHP:
int nor_lot;

//////////////////////////////////////////////////////////////
void init()
{  
if(MarketInfo(Symbol(),MODE_LOTSTEP)==0.1) nor_lot=1;
if(MarketInfo(Symbol(),MODE_LOTSTEP)==0.01) nor_lot=2;
}

Один if наверное лишний?
PHP:
void init()
{  
nor_lot=2;
if(MarketInfo(Symbol(),MODE_LOTSTEP)==0.1) nor_lot=1;
}
;)
 
Верх