Как я и обещал, сегодня мы займемся написанием эксперта 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:
выбираем «Советник» и нажимаем «Далее>»
Вводим имя нашего советника форекс и добавляем параметры аналогичные нашему скрипту MT4, написанному ранее:
После нажатия кнопочки «Готово» получаем пустой шаблон советника форекс:
//+——————————————————————+
//| 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
Добрый день.
А имеет ли смысл сейчас изучать MQL4 если скоро выйдет Metatrater5 и в нем будет уже другой язык: MQL5?
Отвечу вопросом на вопрос: А имеет ли смысл сейчас изучать рынок Forex если скоро закончится кризис и рынок опять изменится?
Ответ: имеет. Рынок изменится, но не все изменится. Новости как выходили так и будут выходить. Тех. анализ как работал — так и дальше будет работать. Некоторые закономерности в поведении цены перестанут работать, другие продолжат. А ведь появятся новые закономерности.
Тоже самое относится и к программированию. Язык изменяется, но не все изменяется. Какая-то часть встроенных функций исчезнет, другая часть останется. Появятся новые функции. Кто освоил MQL4 без труда сможет перейти на MQL5.
Вот тут ошибка вроде бы:
for(int i=OrdersTotal()-1;i>=0;i–)
должно быть вот так если не ошибаюсь:
for(int i=OrdersTotal()-1;i>=0;i–-)
Да, есть такое дело. Я уже в коментариях писал, что редактор почему то заменяет несколько знаков минус одним тире при публикации. Поэтому и выкладываю в конце статей исходный код.
TimeHour(TimeCurrent()) возвращает время брокера. А как именно GMT узнать.
В MetaTrader используется время брокера.
Самое простое — узнать у Вашего брокера разницу времени с GMT (пусть будет Shift). Для перевода в GMT:
TimeHour(TimeCurrent())-Shift;
Не понял этого момента: «Если хотя бы одна из позиций не закрылась в течении торговых суток — на следующие сутки новые ордера не открываются вообще»
Переменная Count равна нулю только пока оба предыдущих ордера открыты, она увеличивается только если мы закрываем хотыбы один из ордеров, но ниже идет проверка на Count == 0, т.е. что ордера еще открыты, и тут же мы открываем новые ордера.
Не совсем верно. Переменная Count содержит количество открытых ордеров. Если открытых ордеров нет, тогда она равна 0. Поэтому условие вполне логично: если нет открытых ордеров — можно открывать новые.
закипел))
А почему в 6 ом уроке написано как писать советник если мы ещё не дописали скрипт по открыванию ордера? допиши отдельно и включи ссылку на страницу или добавь пример как закончит скрипт
Илья
Скрипт ордера открывает, а больше от него ничего и не требуется. Поэтому вполне логично перейти к изучению советников.
Я создал советника, но есть одна проблема. Я уверен она в OrderSelect() и внутренних функциях(типа OrderTakeProfit()). Очень прошу создать урок посвещённый OrderSelect().Большое спасибо за уроки!:)
Не видя код советника я не могу ответить где ошибка. Насчет урока по OrderSelect() — в помощи к MetaTrader стандартные функции достаточно подробно описаны. И я не вижу смысла переписывать всю справку на своем блоге. Примеры как ими пользоваться уже есть в уроках, в том числе и в этом же самом уроке.
//Объясните, почему советник пишет мне цену закрытия,
//если он её не знает?
extern int ticket;
extern int start()
{
if(OrderSelect(ticket,SELECT_BY_TICKET)==true)
Print(OrderClosePrice());
//+———————————————————
if(1>OrdersTotal()){while(!IsTradeAllowed()) Sleep(100);
ticket=OrderSend(Symbol(),OP_SELL,0.01,Ask,3,Ask+10*Point,Ask-13*Point,0,1234,0,Red);}
return(0);
}
Alex
OrderClosePrice() — возвращает цену закрытия выбранного ордера. Для открытых ордеров это текущая цена по которой можно закрыть ордер. Для закрытых это цена по которой ордер был закрыт.
а функции в какой файл(предустановленный?) добавляем?
а если свой файл с функциями создавать, как на него прописывать ссылки?
Владимир
Читайте Урок 9 «Библиотека функций»
Благодарю, разобрался )))
Подскажите пожалуйста
как сделать советника
1) покупает с учетом риска 2 торговые позиции по валютной паре EURUSD в противоположные стороны и выставляет им тейк профиты и стоп лоссы
2) при закрытии этих двух торговых позиций возвращается к 1) и так покругу
barkli
алгоритм простой: 1) посчитаем кол-во открытых ордеров 2)если их нет открываем новые
можно и из этого советника сделать — убрав все остальное (открытие и закрытие по времени)
Чтоб отказаться от свопов форекс-брокер каждый день закрывает позицию ордером swap close и тут же открывает — swap open (всё делаю на тестере!) В результате советник работает корректно только если закрылись оба наших ордера по тейк-профиту. Через 48 часов ордера (как правило они уже с хорошим убытком) не закрываются и новые ордера соответственно тоже не открываются. Просто сидим и хоть полгода ждём чуда, пока рынок развернётся и пойдёт в нашу сторону…
Barry
Без логов тяжело предположить что не сработало. Я проверял на тестере и у меня все работало.
А наш советник выполняет вот это условие:
Если же 1 или 2 торговые позиции не закрылись с прибылью в течение 48 часов после открытия, то ее необходимо закрыть ВРУЧНУЮ ! А после этого размер торговой позиции именно в НАПРАВЛЕНИИ убыточной сделки на следующий торговый день следует УВЕЛИЧИТЬ в 2 раза (т.е. если прошло 48 часов и вы закрыли убыточную сделку вручную в 0.00 по GMT, то сразу после закрытия, открываете новые, но одна из них увеличина в 2 раза).
Valeri4
Да. В тексте описывается как это реализовано.
А все спасибо я разобрался, просто невнимательно код прочитал
Нашел как можно менять шрифт в MQL4. Оказывается просто.
а как сделать, чтобы в тестировании качество моделирования было высоким? у меня 25%
Все, извините, разобрался)
Спасибо за уроки — самому лень было разбираться =))
Как сделать, чтобы в этот-же день, но в другое время открывалось ещё 2 ордера?
Добрый день. Огромное спасибо за вашу работу! Скажите, а как открывать новые позиции не в 0 часов, а сразу после закрытия двух предыдущих?
Здравствуйте! В превую очередь, СПАСИБО за уроки!!!
У меня вопрос по поводу закрытия ордера:
—
if(!OrderClose(OrderTicket(),OrderLots(),PR,3,CLR_NONE))
Print(»Ошибка закрытия ордера: «,GetLastError());
return;}
—
не могу понять сам смысл команды…
ожидала что-то вроде
OrderClose(OrderTicket(),OrderLots(),PR,3,CLR_NONE);
ну и проверки на ошибки в случае возвращения true/false…а так не пойму, как одновременно ведется проверка и закрытие ордера?
Создал советника как показано в уроке, протестировал его на евро/доллар с января 2001г. по сентябрь 2011г. За всё это время он сделал две сделки. В чем причина?
Подскажите пожалуйста, что нужно дописать в советнике, чтобы ордера открывались не по времени а по отклонению от цены, на 20 пунктов. Если цена упала на 20, то открывается селл, если цена выросла на 20 пунктов от последнего ордера, то бай и т.д…
А если брокер не разрешает открывать сделки сразу со стопами? OrderModify использовать?
подскажите пожалуйста новичку в строчках
StopLoss StartTime выставляется во сколько начать торговлю и закончить или что то другое
Подскажите как написать чтобы открывался лот. 0.01 для микро сщёта Спасибо!
Добрый вечер
у меня такой вопрос
что надо прописать в советнике чтоб он открывал сделки в две стороны с определённым стопом и профитом и потом как они закрылись он сразу же открывал новы сделки ?
заранее спасибо)
пытался с начало сам разобраться но что-то не получилось)
Запустил советника — он закрыл мой открытые позиции. Можно как-то что бы он не трогал позиции открытые в ручную, а только те которые открыл сам советник.
palt
Эти уроки от 2010 года, а они рабочие в 2013 году? Как я знаю рынок изменился в 2010 г.
Спрашиваю по тому, что протестировав свои я не получил ни каких результатов. Все поля пустые.
Александр добрый день! Спасибо за ваши уроки, осваиваю язык для написания советников. Я немного преобразовал ваш советник для одновременного открытия разнонаправленных ордеров и закрытия их по тейк профиту. После закрытия советник должен сразу же открыть новый ордер того же типа что и закрыл по рыночной цене. И т.д. Можете глянуть, правильно написал?
//+——————————————————————+
//| my.mq4 |
//| Copyright 2013, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+——————————————————————+
#property copyright «Copyright 2013, 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 Type=0;
double newLot=0;
//+——————————————————————+
int init() {return(0);}
//+——————————————————————+
int deinit() {return(0);}
//+——————————————————————+
int start()
{if(DayOfWeek()==0 || DayOfWeek()==6) return(0); // в выходные не работаем
if(!IsTradeAllowed()) return(0); // пропустим тик если терминал занят
//…подсчитаем количество ордеров и откроем ордер если ордеров меньше 2
for(int i=OrdersTotal();i<2;Type=OrderType())
double Lot=GetLot(MaxRisk);
if(Lot==0) {Alert(«Недостаточно средств!»);return(0);
{if(Type!=OP_BUY) {NewOrder(OP_BUY,Lot);}
if(Type!=OP_SELL){NewOrder(OP_SELL,Lot);}}
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(LotMax_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);}
//+——————————————————————+
Здравствуйте! Помогите разобраться…
Запустила советник в реальном времени на демо-счете и на реальном счете. На демо-счете все ок — в 0 часов открывается две сделки, bay и sell. А на реальном счете выдается ошибка Market is closed. Как так? Торгую только в будни…
Заранее спасибо!
а как добавить минуты?