Полезные функции для MQL-4.

 
Всем доброго времени суток! Открываю собственную ветку, куда я буду скидывать полезные функции для MQL-4. При написании программ часто встречаются задачи для выполнения которых требуется написать новую функцию, а то и целую библиотеку или класс. Вот и решил делиться с другими трейдерами-программистами и коллегами. Не судите строго, если стиль написания моего кода не будет соответствовать чьему-то пониманию. Также не исключены в моем коде ошибки, возникновение которых не было учтено при определенных торговых обстоятельствах. Задавайте вопросы или свободно редактируйте мои функции под свой вкус, как Вам больше нравится.
 
Yuriy Vins:
Всем доброго времени суток! Открываю собственную ветку, куда я буду скидывать полезные функции для MQL-4. При написании программ часто встречаются задачи для выполнения которых требуется написать новую функцию, а то и целую библиотеку или класс. Вот и решил делиться с другими трейдерами-программистами и коллегами. Не судите строго, если стиль написания моего кода не будет соответствовать чьему-то пониманию. Также не исключены в моем коде ошибки, возникновение которых не было учтено при определенных торговых обстоятельствах. Задавайте вопросы или свободно редактируйте мои функции под свой вкус, как Вам больше нравится.

Может лучше не надо, а???

 
Yuriy Vins:
Всем доброго времени суток! Открываю собственную ветку, куда я буду скидывать полезные функции для MQL-4. При написании программ часто встречаются задачи для выполнения которых требуется написать новую функцию, а то и целую библиотеку или класс. Вот и решил делиться с другими трейдерами-программистами и коллегами. Не судите строго, если стиль написания моего кода не будет соответствовать чьему-то пониманию. Также не исключены в моем коде ошибки, возникновение которых не было учтено при определенных торговых обстоятельствах. Задавайте вопросы или свободно редактируйте мои функции под свой вкус, как Вам больше нравится.

Всё нормально, не слушай никого, делись с другими, кто то тоже поделится. 

Как говорится на ошибках учатся!

 

Итак первые две функции. Ловите!

//--- Факт закрытия ордера в минус по тиккету и magic-номеру -------------------+ 
bool LossClosing(int ticket,int magic,int quantity=20,int tick_status_delay=10)
{//--- Объявить массивы статических переменных. У каждого ордера своя переменная.
 static datetime loss_close_time[]; ArrayResize(loss_close_time,quantity);
 static int loss_ticket_close[]; ArrayResize(loss_ticket_close,quantity);
 static int loss_tick[]; ArrayResize(loss_tick,quantity); 
 static int loss_count[]; ArrayResize(loss_count,quantity);
 static bool loss_fact[]; ArrayResize(loss_fact,quantity);
 //--- Отследить факт закрытия ордера в минус. Вернуть true в случае убытка.
 if(magic>=quantity) Print("Функция LossClosing(). Значение мagic слишком большое! Нужно увеличить значение quantity.");
 loss_tick[magic]++; if(loss_tick[magic]>tick_status_delay) loss_fact[magic] = false;
 if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)==true && OrderCloseTime()==0 && OrderMagicNumber()==magic) 
 {
  if(loss_tick[magic]>tick_status_delay) loss_ticket_close[magic] = OrderTicket(); 
 }
 for(int i=OrdersHistoryTotal()-1; i>=0; i--)
   {
    if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderCloseTime()>loss_close_time[magic] && 
       OrderMagicNumber()==magic && OrderTicket()==loss_ticket_close[magic] && 
       loss_ticket_close[magic]>0 && OrderProfit()<0) 
       {
        loss_count[magic]++; 
        //if(OrderType()==OP_BUY) Print("Ордер BUY с тиккетом #"+IntegerToString(loss_ticket_close[magic],0)+" получил убыток!");//
        //if(OrderType()==OP_SELL) Print("Ордер SELL с тиккетом #"+IntegerToString(loss_ticket_close[magic],0)+" получил убыток!");//
        loss_close_time[magic] = OrderCloseTime(); loss_tick[magic]=0; loss_fact[magic] = true; break;
       }
   }
 return(loss_fact[magic]);
}

//--- Факт закрытия ордера в плюс по тиккету и magic-номеру --------------------+ 
bool ProfitClosing(int ticket,int magic,int quantity=20,int tick_status_delay=10)
{//--- Объявить массивы статических переменных. У каждого ордера своя переменная.
 static datetime profit_close_time[]; ArrayResize(profit_close_time,quantity);
 static int profit_ticket_close[]; ArrayResize(profit_ticket_close,quantity);
 static int profit_tick[]; ArrayResize(profit_tick,quantity); 
 static int profit_count[]; ArrayResize(profit_count,quantity);
 static bool profit_fact[]; ArrayResize(profit_fact,quantity);
 //--- Отследить факт закрытия ордера в минус. Вернуть true в случае убытка.
 if(magic>=quantity) Print("Функция ProfitClosing(). Значение мagic слишком большое! Нужно увеличить значение quantity.");
 profit_tick[magic]++; if(profit_tick[magic]>tick_status_delay) profit_fact[magic] = false;
 if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)==true && OrderCloseTime()==0 && OrderMagicNumber()==magic) 
 {
  if(profit_tick[magic]>tick_status_delay || (Ask+Bid)/2<OrderOpenPrice()-50*Point || (Bid+Ask)/2>OrderOpenPrice()+50*Point)
  profit_ticket_close[magic] = OrderTicket(); 
 }
 for(int i=OrdersHistoryTotal()-1; i>=0; i--)
   {
    if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderCloseTime()>profit_close_time[magic] && 
       OrderMagicNumber()==magic && OrderTicket()==profit_ticket_close[magic] && 
       profit_ticket_close[magic]>0 && OrderProfit()>0) 
       {
        profit_count[magic]++; 
        //if(OrderType()==OP_BUY) Print("Ордер BUY с тиккетом #"+IntegerToString(profit_ticket_close[magic],0)+" получил прибыль!");//
        //if(OrderType()==OP_SELL) Print("Ордер SELL с тиккетом #"+IntegerToString(profit_ticket_close[magic],0)+" получил прибыль!");//
        profit_close_time[magic] = OrderCloseTime(); profit_tick[magic]=0; profit_fact[magic] = true; break;
       }
   }
 return(profit_fact[magic]);
}

Функции LossClosing() и ProfitClosing() - отслеживают закрытие ордера в минус или в плюс. Возвращают true, если ордер закрылся в минус (или в плюс). При чем не важно - какой это ордер BUY или SELL, закрылся он по стопу или при других обстоятельствах. Отслеживаемый ордер определяется в параметрах по тиккету и магическому номеру. Если же после нескольких тиков, количество которых также определяется в параметрах, закрытых ордеров нет - то статус функции возвращается в положение false.

Описание параметров:

int ticket - Тиккет ордера, который надо отслеживать. Вбиваем сюда переменную тиккета, если ордеров очень много -  я например создаю массив для хранения тиккетов (к примеру buy[5] ).

int magic - Магический номер ордера. Магические номера у каждого ордера тоже (как и тиккеты) должны быть разные, иначе он будет параллельно возвращать true или false для всех ордеров.

Если же в Вашей стратегии участвует лишь один ордер, то тогда это не важно.

int quantity - Количество ордеров или же количество мэйджиков в работе советника. Это необходимо, потом объясню зачем. По умолчанию стоит 20. Если указать слишком мало - то будет ошибка.

int tick_status_delay - Задержка возвращаемого статуса true в тиках. По умолчанию стоит 10. Спросите: Для чего это нужно? Вот закрывается Ваш ордер к примеру по стопу, затем функция возвращает true и только по "истечению" 10-ти тиков становится обратно в false. Дело в том что одного тика оказалось не достаточно для выполнения каких-нибудь команд при условии true в данных функциях, поэтому пришлось добавить и этот параметр. Дальше уж придется самим что-то "химичить". Ну надеюсь Вы понимаете о чем идет речь.

Параметры обоих функций LossClosing() и ProfitClosing() - идентичны.

Теперь кратко о том, как они работают: Итак - открывается ордер . Тут-же в переменную  ticket записывается тиккет рыночного ордера, а через определенное количество тиков в другую статическую переменную тоже записывается этот же тиккет, что и обеспечивает задержку статуса true при закрытии этого ордера. Как только ордер закрывается, происходит следующее: обновляется значение  переменной loss_close_time (или profit_close_time)  в которую записывается время закрытия ордера, затем обнуляется переменная - которая считает тики, после чего функция возвращает true.

Вот как то так. Пытался сделать как-то попроще, но получилось только так. Приятного использования! 

 
А еще.,Тут код очень сжат и не использован стилизатор, так-что кому-то будет не легко с первого раза понять что да как. Зато работают безупречно. Было протестировано мною много раз. Ну надеюсь разберетесь! )
 

Следующие две функции Max_Equity() и Max_Balance().

//--- Функция возвращает Максимально достигнутый уровень Эквити , который был с начала запуска советника.
double Max_Equity()
  {
   static double maxeq=AccountBalance(); 
    
   if(NormalizeDouble(AccountEquity(),2)>NormalizeDouble(maxeq,2))
      maxeq=NormalizeDouble(AccountEquity(),2);
   return(maxeq);
  } 
//--- Функция возвращает Максимально достигнутый уровень Баланса , который был с начала запуска советника.
double Max_Balance()
  {
   static double maxbal;
   static int mc=0;
   
   for(; mc<1; mc++)
   maxbal=NormalizeDouble(AccountBalance(),2);
    
   if(NormalizeDouble(AccountBalance(),2)>NormalizeDouble(maxbal,2))
   mc=0;
   return(maxbal);
  }       

Думаю, тут даже и описание не требуется. Итак все понятно. )

 
Yuriy Vins:

Следующие две функции Max_Equity() и Max_Balance().

Думаю, тут даже и описание не требуется. Итак все понятно. )

Зачем использовать дорогую функцию NormalizeDouble() там, где не нужно? И особенно при сравнении - два раза?

Если нужно нормализованное сравнение, то нужно сравнивать нормализованную разницу двух вещественных чисел с нулём или с минимальным значением.

 
Artyom Trishkin:

Зачем использовать дорогую функцию NormalizeDouble() там, где не нужно? И особенно при сравнении - два раза?

Аа, ну да.

//--- Функция возвращает Максимально достигнутый уровень Эквити , который был с начала запуска советника.
double Max_Equity()
  {
   static double maxeq=AccountBalance(); 
    
   if(NormalizeDouble(AccountEquity(),2)>NormalizeDouble(maxeq,2))
      maxeq=AccountEquity();
   return(maxeq);
  } 
//--- Функция возвращает Максимально достигнутый уровень Баланса , который был с начала запуска советника.
double Max_Balance()
  {
   static double maxbal;
   static int mc=0;
   
   for(; mc<1; mc++)
   maxbal=AccountBalance();
    
   if(NormalizeDouble(AccountBalance(),2)>NormalizeDouble(maxbal,2))
   mc=0;
   return(maxbal);
  }       
 
Yuriy Vins:

Аа, ну да.

Вот это что?

if(NormalizeDouble(AccountEquity(),2)>NormalizeDouble(maxeq,2))
 

А так не проще

maxbal=MathMax(maxbal,AccountBalance());
Причина обращения: