Стратегия Форекс «20/200 pips» на MQL5 для Metatrader5.
Ни что не стоит на месте, все движется и развивается, так и Metatrader4 получил
свое ожидаемое продолжение – Metatrader5 с обновленным языком программирования – MQL5.
Каждый трейдер сам для себя решит, на каком уровне он хочет знать MQL5, но азы этого
языка придется знать всем трейдерам использующим Metatrader5 как основу для
автоматической торговли на рынке Форекс. Для первого знакомства с MQL5, предлагаю
воспользоваться кодом советника для механической торговой системы «20/200 pips»,
переписанного на MQL5 для работы в Metatrader5.
Язык программирования MQL5.
Читаем справку по MQL5:
«Язык MetaQuotes Language 5 (MQL5) является объектно-ориентированным
языком программирования высокого уровня и предназначен для написания автоматических торговых стратегий,
пользовательских технических индикаторов для анализа разнообразных финансовых рынков. Он позволяет
не только писать разнообразные экспертные системы, предназначенные для работы в режиме реального
времени, но и создавать собственные графические инструменты, помогающие принимать торговые решения.»
Да, все правильно – это объектно-ориентированный язык программирования. В этом и заключаются основные
сложности перехода с MQL4 на MQL5. Например, мне лично «неуютно» программировать на объектно-ориентированных
языках, потому что я достаточно долгое время программировал на Си и Ассемблере. И мое мышление заточено
под эти языки – мне проще использовать функции, нежели методы классов, мне привычней оперировать с
переменными, нежели использовать структуры и т.д. Однако ООП (объектно-ориентированное программирование)
имеет свои неоспоримые плюсы. Именно поэтому оно так популярно. В ООП код программы всегда более структурирован
и понятен. Его легко переносить из проекта в проект, для этого, как правило, пишутся библиотеки готовых
классов и затем прикрепляются к новому проекту. И много других плюсов, о которых можно узнать, программируя
на языках ООП, к которым и относится и MQL5.
Советник на MQL5 без использования ООП.
Как я уже говорил, мне «неуютно» использовать ООП, поэтому советника я переписал без использования методов
объектно-ориентированного программирования. Да, вы правильно поняли, на языке MQL5, оказывается, можно писать
без использования ООП. Ведь стандартные функции и переменные никто не отменял. И ничего в этом нет плохого,
просто мы не будем использовать все возможности MQL5, а лишь ограничимся необходимыми нам – теми, что мы
понимаем и которыми пользовались в языке MQL4. Но, полностью избежать ООП не удастся, т.к. обращение к торговым
функциям, и другие возможности реализованы с помощью методов объектно-ориентированного программирования,
что, в общем-то, логично.
Код советника на MQL5.
Итак, представляю вам код советника механической торговой системы «20/200 pips» на MQL5:
#property copyright "Copyright 2010, Смирнов Павел"
#property link "http://www.autoforex.ru"
#property version "1.00"
input int TakeProfit=200;
input int StopLoss=2000;
input int TradeTime=18;
input int t1=7;
input int t2=2;
input int delta=70;
input double lot=0.1;
bool cantrade=true;
double Ask;
double Bid;
int OpenLong(double volume=0.1,int slippage=10,string comment="EUR/USD 20 pips expert (Long)",int magic=0)
{
MqlTradeRequest my_trade;
MqlTradeResult my_trade_result;
my_trade.action=TRADE_ACTION_DEAL;
my_trade.symbol=Symbol();
my_trade.volume=NormalizeDouble(volume,1);
my_trade.price=NormalizeDouble(Ask,_Digits);
my_trade.sl=NormalizeDouble(Ask-StopLoss*_Point,_Digits);
my_trade.tp=NormalizeDouble(Ask+TakeProfit*_Point,_Digits);
my_trade.deviation=slippage;
my_trade.type=ORDER_TYPE_BUY;
my_trade.type_filling=ORDER_FILLING_AON;
my_trade.comment=comment;
my_trade.magic=magic;
ResetLastError();
if(OrderSend(my_trade,my_trade_result))
{
Print("Код результата операции - ",my_trade_result.retcode);
}
else
{
Print("Код результата операции - ",my_trade_result.retcode);
Print("Ошибка открытия ордера = ",GetLastError());
}
return(0);
}
int OpenShort(double volume=0.1,int slippage=10,string comment="EUR/USD 20 pips expert (Short)",int magic=0)
{
MqlTradeRequest my_trade;
MqlTradeResult my_trade_result;
my_trade.action=TRADE_ACTION_DEAL;
my_trade.symbol=Symbol();
my_trade.volume=NormalizeDouble(volume,1);
my_trade.price=NormalizeDouble(Bid,_Digits);
my_trade.sl=NormalizeDouble(Bid+StopLoss*_Point,_Digits);
my_trade.tp=NormalizeDouble(Bid-TakeProfit*_Point,_Digits);
my_trade.deviation=slippage;
my_trade.type=ORDER_TYPE_SELL;
my_trade.type_filling=ORDER_FILLING_AON;
my_trade.comment=comment;
my_trade.magic=magic;
ResetLastError();
if(OrderSend(my_trade,my_trade_result))
{
Print("Код результата операции - ",my_trade_result.retcode);
}
else
{
Print("Код результата операции - ",my_trade_result.retcode);
Print("Ошибка открытия ордера = ",GetLastError());
}
return(0);
}
int OnInit()
{
return(0);
}
void OnDeinit(const int reason){}
void OnTick()
{
double Open[];
MqlDateTime mqldt;
TimeCurrent(mqldt);
int len;
MqlTick last_tick;
SymbolInfoTick(_Symbol,last_tick);
Ask=last_tick.ask;
Bid=last_tick.bid;
ArraySetAsSeries(Open,true);
if (t1>=t2)len=t1+1;
else len=t2+1;
CopyOpen(_Symbol,PERIOD_H1,0,len,Open);
if(((mqldt.hour)>TradeTime)) cantrade=true;
if(!PositionSelect(_Symbol))
{
if((mqldt.hour==TradeTime) && (cantrade))
{
if(Open[t1]>(Open[t2]+delta*_Point))
{
OpenShort(lot,10,"EUR/USD 20 pips expert (Short)",1234);
cantrade=false;
return;
}
if((Open[t1]+delta*_Point)<Open[t2])
{
OpenLong(lot,10,"EUR/USD 20 pips expert (Long)",1234);
cantrade=false;
return;
}
}
}
return;
}
|
Код советника хорошо закомментирован, поэтому остановлюсь только на некоторых моментах.
функции входа в рынок OpenShort(…) и OpenLong(…) используют две структуры: MqlTradeRequest и MqlTradeResult.
Вообще, структура – это место для хранения данных. Объявив новую структуру типа MqlTradeRequest, мы можем
хранить в ней данные согласно ее устройству. А устроена эта структура следующим образом:
struct MqlTradeRequest
{
ENUM_TRADE_REQUEST_ACTIONS action;
ulong magic;
ulong order;
string symbol;
double volume;
double price;
double stoplimit;
double sl;
double tp;
ulong deviation;
ENUM_ORDER_TYPE type;
ENUM_ORDER_TYPE_FILLING type_filling;
ENUM_ORDER_TYPE_TIME type_time;
datetime expiration;
string comment;
};
|
В коде советника структура объявляется следующей строкой:
MqlTradeRequest my_trade;
Теперь в my_trade могут храниться все те данные, которые описаны в структуре MqlTradeRequest. Эти данные мы и заполняем перед вызовом торговой функции.
Теперь, чтобы передать все эти данные серверу нам необходимо вызвать функцию:
OrderSend(my_trade,my_trade_result);
Чтобы увидеть один из плюсов ООП сравним ее с аналогичной функцией из MQL4:
OrderSend(Symbol(),OP_BUY,volume,Ask,slippage,StopLoss,TakeProfit,comment,magic,0,arrow_color);
Видите, сколько параметров приходится указывать в функции в MQL4. В MQL5 все эти параметры лежат в одной
структуре, которую мы объявили и заполнили. Поэтому, чтобы передать на сервер все эти параметры достаточно
в торговой функции лишь указать имя структуры, в которой все они хранятся. В нашем случае имя этой
структуры - my_trade. И именно в ней хранятся все необходимые для отправки запроса на сервер данные.
Также в функции OrderSend(my_trade,my_trade_result); вторым параметром указывается другая структура типа – MqlTradeResult. Вот ее описание:
struct MqlTradeResult
{
uint retcode;
ulong deal;
ulong order;
double volume;
double price;
double bid;
double ask;
string comment;
};
|
В этой структуре будет сохранен ответ сервера после выполнения запроса на открытие позиции.
Т.е. после выполнения функции OrderSend(…) проверив поля этой структуры можно определить код
выполнения нашего запроса, можно посмотреть тикет ордера, если он был выставлен и др. информацию.
На данный момент нас интересует только код результата операции, и посмотреть мы его можем следующим
образом: my_trade_result.retcode именно там, в структуре my_trade_result, лежит код выполнения запроса.
Аналогично, для доступа к текущему времени или текущим ценам Ask и Bid в коде советника используются
соответствующие структуры – mqldt и last_tick и функции запроса данных - TimeCurrent(mqldt) и
SymbolInfoTick(_Symbol,last_tick). Для поддержания актуальности данных в этих структурах,
функции запроса данных вызываются в коде при каждом поступлении нового тика.
Еще одна особенность MQL5 – у нас нет доступа к таймсерии Open[], как это было в MQL4, т.е. мы не можем напрямую
посмотреть цену открытия i-го бара текущего символа, обратившись к данным через Open[i]. Поэтому данный массив
мы заполняем сами, правда, не весь, а только тот участок цен, который нам необходим:
if (t1>=t2)len=t1+1;
else len=t2+1;
CopyOpen(_Symbol,PERIOD_H1,0,len,Open);
|
Вот, в общем-то, и все нюансы перехода на MQL5 для случая с советником торговой системы «20/200 pips». Как видите
ничего сложного, хотя и много непонятного. Однако, в Metatrader5, как и в предыдущей версии программы,
встроен превосходный справочник, поэтому любые сложности в написании программ преодолеваются без особых проблем.
Заключение.
Язык MQL5 позволяет писать более читабельные, компактные программы, но от использования ООП в небольших
проектах, при переходе с MQL4 можно отказаться. Это упростит переход, а также уменьшит риск появления новых
ошибок связанных с малой изученностью нового языка программирования. Поэтому не стесняйтесь писать
программы на MQL5 по старинке, также как вы это делали на MQL4 без использования ООП. Не стесняйтесь
использовать громоздкие конструкции и выражения, как бы ни высмеивали их «профессиональные» программисты.
Никогда не стесняйтесь своего кода, потому что главное это не чистота кода, и не правильность использования
ООП, и не скорость выполнения программы и ни что другое. Самое главное в написании советника это то, какую
прибыль он вам принесет, торгуя в автоматическом режиме на рынке Форекс.