Рекомендуемый ДЦ - Forex4you !

Как я и обещал, сегодня мы займемся написанием эксперта Hedge Hog на языке MQL, но сначала давайте объединим уже полученные ранее знания и напишем собственные функции на MQL4.

Сразу возникает вопрос: «Что это нам даст?»

Ну во первых это уменьшит количество строк в нашем советнике для Metatrader 4. Во вторых можно не тратить время при написании следующих советников форекс, а просто использовать ранее написанные функции в новом коде.

Функции MQL4 — это кирпичики из которых можно легко сложить рабочий эксперт MT4, не отвлекаясь каждый раз на одну и ту-же работу.

Расчет лота в MT4, поместим в функцию — "Функция расчета лота":
double GetLot(int Risk)
{double Free    =AccountFreeMargin();
 double One_Lot =MarketInfo(Symbol(),MODE_MARGINREQUIRED);
 double Min_Lot =MarketInfo(Symbol(),MODE_MINLOT);
 double Max_Lot =MarketInfo(Symbol(),MODE_MAXLOT);
 double Step    =MarketInfo(Symbol(),MODE_LOTSTEP);
 double Lot     =MathFloor(Free*Risk/100/One_Lot/Step)*Step;
 if(Lot<Min_Lot) Lot=Min_Lot;
 if(Lot>Max_Lot) Lot=Max_Lot;
 if(Lot*One_Lot>Free) return(0.0);
return(Lot);}

Обратите внимание на строчку: if(Lot*One_Lot>Free) return(0.0);

В ней мы производим проверку на достаточность средств на торговом счету форекс. И если их окажется недостаточно, возвращаем 0.

Для открытия ордера Metatrader 4, при помощи советника форекс,  напишем функцию — "Функция открытия ордера":
int NewOrder(int Cmd,double Lot)
{double TP=0; //тейкпрофит
 double SL=0; //стоплосс
 double PR=0; //Цена
 while(!IsTradeAllowed()) Sleep(100);
 if(Cmd==OP_BUY)
   {PR=Ask;
    if(TakeProfit>0) TP=Ask+TakeProfit*Point;
    if(StopLoss>0) SL=Ask-StopLoss*Point;}
 if(Cmd==OP_SELL)
   {PR=Bid;
    if(TakeProfit>0) TP=Bid-TakeProfit*Point;
    if(StopLoss>0) SL=Bid+StopLoss*Point;}
 int tic=OrderSend(Symbol(),Cmd,Lot,PR,3,SL,TP,"«,0,0,CLR_NONE);
 if(tic<0) Print(»Ошибка открытия ордера: «,GetLastError());
return(tic);}

В этой функции на языке MQL мы использовали новые для нас команды MQL4:

Print() — Выдать сообщение в журнал.

GetLastError() — Номер последней ошибки.

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

Функция start() нашего скрипта сильно упростится:

 double Lot=GetLot(MaxRisk);
 if(Lot==0) {Alert(»Недостаточно средств!");return(0);}
 RefreshRates();
 if(Buy)  NewOrder(OP_BUY,Lot);
 if(Sell) NewOrder(OP_SELL,Lot);

Новая функция RefreshRates() — функция обновления данных в предопределенных переменных (Ask, Bid и т.д.) При запуске нашего скрипта в окне терминала Metatrader появляется окошко с параметрами. Пока мы их изменяем цена может изменится. Вот мы и обновим ее значение в переменных.

Теперь займемся советником Hedge Hog.

Для начала изучим: Стратегию Hedge Hog.

На первый взгляд — все просто. Нужно открывать каждый торговый день ан форекс, с понедельника по пятницу в 00:00 по GMT, два рыночных ордера в противоположные стороны (один на покупку, второй на продажу) без стоп-лоссов и с тейк-профитами в 14 пунктов равным объемом по валютной паре EURUSD.

Итак, для создания советника MT4, запускаем мастер в редакторе MetaEditor:

Мастер создания экспертов в редакторе MetaEditor

выбираем «Советник» и нажимаем «Далее>»

Вводим имя нашего советника форекс и добавляем параметры аналогичные нашему скрипту MT4, написанному ранее:

Параметры эксперта МТ4

После нажатия кнопочки «Готово» получаем пустой шаблон советника форекс:
//±-----------------------------------------------------------------+
//| expert1.mq4 |
//| Copyright © 2009, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//±-----------------------------------------------------------------+

#property copyright "Copyright © 2009, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
extern int  MaxRisk=2;
extern int  TakeProfit=14;
extern int  StopLoss=0;
//±-----------------------------------------------------------------+
int init() {return(0);}
//±-----------------------------------------------------------------+
int deinit() {return(0);}
//±-----------------------------------------------------------------+
int start()
{
return(0);}
//±-----------------------------------------------------------------+

я удалил лишние комментарии (так легче читается).
Добавим в конец кода MQL4 наши готовые функции: GetLot() и NewOrder(), а в функцию start():

if(DayOfWeek()==0 || DayOfWeek()==6) return(0); // в выходные не работаем
if(!IsTradeAllowed()) return(0); // пропустим тик если терминал занят

здесь, я думаю, все понятно из комментариев в коде. Дальше нам необходимо определить текущее время и если наступило время «Ч» — открыть рыночные ордера. Время открытия ордеров предлагаю вынести в параметры (а вдруг в другое время результат будет лучше)
extern int StartTime=0;

double Lot=GetLot(MaxRisk);
if(Lot==0) {Alert("Недостаточно средств!");return(0);}
if(TimeHour(TimeCurrent())==StartTime)
  {NewOrder(OP_BUY,Lot);
   NewOrder(OP_SELL,Lot);}

Вот как красиво получилось. Но когда мы компилируем и запускаем нашего эксперта форекс, то видим страшную картину:
В 0 часов по терминальному времени Metatrader 4 начинает открываться огромное количество ордеров. Надеюсь вы запускали на демосчете или в тестере стратегий MT4 🙂

Что же мы сделали не так? А ларчик просто открывается: мы забыли сделать проверку что «сегодня» мы ордера уже открывали. Делается это просто. Добавим глобальную переменную int Today=0. В условии на открытие ордеров будем проверять ее, а после открытия ордеров присваивать ей текущий день.

extern int StartTime=0;
int Today=0;

double Lot=GetLot(MaxRisk);
if(Lot==0) {Alert("Недостаточно средств!");return(0);}
if(TimeHour(TimeCurrent())==StartTime && Today!=TimeDay(TimeCurrent()))
  {NewOrder(OP_BUY,Lot);
   NewOrder(OP_SELL,Lot);
   Today=TimeDay(TimeCurrent());}

Компилируем эксперт, запускаем его — все работает!

В стратегии форекс Hedge Hog сказано, что не закрытые ордера через 48 часов надо закрыть по рыночной цене. Для начала напишем свою функцию закрытия ордера:

void CloseOrder()
{double PR=0;
 while(!IsTradeAllowed()) Sleep(100);
 if(OrderType()==OP_BUY)  PR=Bid;
 if(OrderType()==OP_SELL) PR=Ask;
 if(!OrderClose(OrderTicket(),OrderLots(),PR,3,CLR_NONE))
   Print("Ошибка закрытия ордера: «,GetLastError());
return;}

Здесь используется новая функция OrderClose(). Описывать ее не буду. Пора уже самим научиться заглядывать в справку Metatrader 4. Для этого достаточно в редакторе MetaEditor выделить интересующую функцию и нажать клавишу F1. В нижнем окне редактора высветится справка по этой функции. 

В функцию start() запишем:

 for(int i=OrdersTotal() −1;i>=0;i--)
   if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
     if(TimeCurrent() -OrderOpenTime()>=48*60*60) CloseOrder();

Этот цикл пробегает по всем открытым ордерам в нашем торговом терминале по данной стратегии и проверяет время их открытия. Если текущее время — время открытия ордера больше либо равно 48 часов (время расчитывается в секундах. Для перевода в часы мы умножили на кол-во секунд в часе), то закрываем такие открытые ордера.

Компилируем советник Hedge Hog, запускаем и замечаем что не выполняется условие „ВАЖНО: Если хотя бы одна из позиций не закрылась в течении торговых суток — на следующие сутки новые ордера не открываются вообще !“

Ну чтож, изменим наш эксперт Hedge Hog и выполним это условие:
//±-----------------------------------------------------------------+
//| expert1.mq4 |
//| Copyright © 2009, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//±-----------------------------------------------------------------+
#property copyright »Copyright © 2009, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
extern int  MaxRisk=2;
extern int  TakeProfit=14;
extern int  StopLoss=0;
extern int  StartTime=0;
int Today=0;
//±-----------------------------------------------------------------+
int init() {return(0);}
//±-----------------------------------------------------------------+
int deinit() {return(0);}
//±-----------------------------------------------------------------+
int start()
{if(DayOfWeek()==0 || DayOfWeek()==6) return(0); // в выходные не работаем
 if(!IsTradeAllowed()) return(0); // пропустим тик если терминал занят
 int Count=0;
//...подсчитаем количество ордеров и закроем их через 48 часов
 for(int i=OrdersTotal() −1;i>=0;i--)
   if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
     {if(TimeCurrent() -OrderOpenTime()>=48*60*60) CloseOrder();
      Count++;}
//...откроем ордера в StartTime если нет открытых и сегодня не торговали
 double Lot=GetLot(MaxRisk);
 if(Lot==0) {Alert("Недостаточно средств!");return(0);}
 if(TimeHour(TimeCurrent())==StartTime && Today!=TimeDay(TimeCurrent()) && Count==0)
   {NewOrder(OP_BUY,Lot);
    NewOrder(OP_SELL,Lot);
    Today=TimeDay(TimeCurrent());}
return(0);}
//±-----------------------------------------------------------------+
double GetLot(int Risk)
{double Free    =AccountFreeMargin();
 double One_Lot =MarketInfo(Symbol(),MODE_MARGINREQUIRED);
 double Min_Lot =MarketInfo(Symbol(),MODE_MINLOT);
 double Max_Lot =MarketInfo(Symbol(),MODE_MAXLOT);
 double Step    =MarketInfo(Symbol(),MODE_LOTSTEP);
 double Lot     =MathFloor(Free*Risk/100/One_Lot/Step)*Step;
 if(Lot<Min_Lot) Lot=Min_Lot;
 if(Lot>Max_Lot) Lot=Max_Lot;
 if(Lot*One_Lot>Free) return(0.0);
return(Lot);}
//±-----------------------------------------------------------------+
int NewOrder(int Cmd,double Lot)
{double TP=0; //тейкпрофит
 double SL=0; //стоплосс
 double PR=0; //Цена
 while(!IsTradeAllowed()) Sleep(100);
 if(Cmd==OP_BUY)
   {PR=Ask;
    if(TakeProfit>0) TP=Ask+TakeProfit*Point;
    if(StopLoss>0) SL=Ask-StopLoss*Point;}
 if(Cmd==OP_SELL)
   {PR=Bid;
    if(TakeProfit>0) TP=Bid-TakeProfit*Point;
    if(StopLoss>0) SL=Bid+StopLoss*Point;}
 int tic=OrderSend(Symbol(),Cmd,Lot,PR,3,SL,TP,"«,0,0,CLR_NONE);
 if(tic<0) Print(»Ошибка открытия ордера: «,GetLastError());
return(tic);}
//±-----------------------------------------------------------------+
void CloseOrder()
{double PR=0;
 while(!IsTradeAllowed()) Sleep(100);
 if(OrderType()==OP_BUY)  PR=Bid;
 if(OrderType()==OP_SELL) PR=Ask;
 if(!OrderClose(OrderTicket(),OrderLots(),PR,3,CLR_NONE))
   Print(»Ошибка закрытия ордера: ",GetLastError());
return;}
//±-----------------------------------------------------------------+

Компилируем советник, запускаем — Работает. Перечитываем еще раз стратегию форекс и замечаем, что при закрытии ордера через 48 часов надо удваивать лот.

Снова подправим написанный нами эксперт Hedge Hog:

 int Type=0;
 double newLot=0;
 for(int i=OrdersTotal() −1;i>=0;i--)
   if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
     {if(TimeCurrent() -OrderOpenTime()>=48*60*60)
        {newLot=OrderLots();Type=OrderType();CloseOrder();}
      Count++;}
и
 if(TimeHour(TimeCurrent())==StartTime && Today!=TimeDay(TimeCurrent()) && Count==0)
   {if(newLot>0)
      {if(Type==OP_BUY) {NewOrder(OP_BUY,newLot*2); NewOrder(OP_SELL,newLot);}
       if(Type==OP_SELL){NewOrder(OP_SELL,newLot*2);NewOrder(OP_BUY,newLot);}}
    if(newLot==0)
      {NewOrder(OP_BUY,Lot);
       NewOrder(OP_SELL,Lot);}
    Today=TimeDay(TimeCurrent());
    newLot=0;}

Снова компилируем созданный советник форекс, запускаем — Работает!

Перечитываем еще раз стратегию форекс Hedge Hog. Все, мы добились чтобы эксперт Hedge Hog  торговал строго по данной торговой стратегии.

Скачать: эксперт Hedge Hog