Заработок на Рынке FOREX и РТС Сайтах .
<a href="http://www.mt5.com/ru/">Форекс портал</a>
Пятница, 29.03.2024, 00:16
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Раздел о рынке FOREX » Язык программирования MQL 5 » Программирования ЕА на MQL5
Программирования ЕА на MQL5
ШрусДата: Среда, 02.08.2017, 16:47 | Сообщение # 1
Генералиссимус
Группа: Администраторы
Сообщений: 8006
Статус: Offline
Краткий курс программирования ЕА на MQL5 без ООП и стандартной библиотеки

Этот курс предназначен для начинающих знакомство с языком программирования MQL5.
Надеюсь, с азами программирования вы знакомы. Знаете что такое переменная, типы переменных, видимость переменных. Знаете что такое функция, пользовательская функция и прочие минимальные знания программирования вам не чужды.
Для примера напишем советник по избитой теме торговли, основанную на пересечении двух индикаторов Moving Average.

Итак, начинаем:
Также надеюсь, знаете, как создать новый файл будущего советника. Меню «Файл» затем «Создать» отметить, что создаём советник и далее. Либо через контекстное меню «Новый файл»... и так далее. MetaEditor в помощь нам, создаёт такой код.

Код
//+------------------------------------------------------------------+
//|                    MyFirstEA.mq5 |
//|                    Viktorov |
//|                    v4forex@yandex.ru |
//+------------------------------------------------------------------+
#property copyright "Viktorov"
#property link      "v4forex@yandex.ru"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                    |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                    |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+


Теперь начинаем вставлять свой код. Для начала нам надо задать параметры торговли и используемых индикаторов.
Обращение к индикаторам в MQL5 происходит не так как в MQL4, поэтому надо объявить переменные, в которых будем хранить хендлы индикаторов. А поскольку индикаторов у нас два, то и хендлов должно быть два.
Затем в функции int OnInit() получим хендлы необходимых индикаторов.

В итоге наш код будет выглядеть уже вот так.

Код
//+------------------------------------------------------------------+
//|                    MyFirstEA.mq5 |
//|                    Viktorov |
//|                    v4forex@yandex.ru |
//+------------------------------------------------------------------+
#property copyright "Viktorov"
#property link      "v4forex@yandex.ru"
#property version   "1.00"

//---- input parameters
input double               lot            =  0.1;  // Размер лота
input int                  tacke          =  400;  // TackeProfit
input int                  loss           =  200;  // StopLoss
input int                  periodFastMa   =  8;    // Период усреднения быстрой МА
input ENUM_MA_METHOD       metodFastMa    =  1;    // Метод усреднения быстрой МА
input ENUM_APPLIED_PRICE   priceFastMA    =  1;    // Используемая цена быстрой МА
input int                  periodSlowMa   =  13;   // Период усреднения медленной МА
input ENUM_MA_METHOD       metodSlowMa    =  1;    // Метод усреднения медленной МА
input ENUM_APPLIED_PRICE   priceSlowMA    =  1;    // Используемая цена медленной МА

int handleFastMA  // хендл быстрой МА
  , handleSlowMA; // хендл медленной МА

//+------------------------------------------------------------------+
//| Expert initialization function                    |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   handleFastMA = iMA(_Symbol, PERIOD_CURRENT, periodFastMa, 0, metodFastMa, priceFastMA);
   handleSlowMA = iMA(_Symbol, PERIOD_CURRENT, periodSlowMa, 0, metodSlowMa, priceSlowMA);
   if(handleFastMA == INVALID_HANDLE || handleSlowMA == INVALID_HANDLE)
   return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                    |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+


Теперь надо как-то определить, что произошло пересечение линий индикаторов. Для этого напишем пользовательскую функцию определяющую факт пересечения, назовём её Crossing. Возвращать функция будет 0, 1 или -1 следовательно тип функции будет int.

Код
int Crossing()
{
   double   fastMA[2], slowMA[2];
   CopyBuffer(handleFastMA, 0, 1, 2, fastMA);
   CopyBuffer(handleSlowMA, 0, 1, 2, slowMA);
   
   if(fastMA[0] < slowMA[0] && fastMA[1] > slowMA[1])
    return(0);
   if(fastMA[0] > slowMA[0] && fastMA[1] < slowMA[1])
    return(1);

  return(-1);
}/*******************************************************************/


В данной функции в заранее объявленные массивы копируются значения индикаторов на первом и втором барах. Затем сравнивается положение линий. Если на втором баре fastMA была ниже slowMA а на первом стало наоборот, следовательно, быстрая МА пересекла медленную МА снизу вверх. И наоборот, если на втором баре fastMA была выше slowMA а стало наоборот, то быстрая МА пересекла медленную МА сверху вниз.
Поместим её в самый конец нашего кода.
Теперь самое время попытаться получить результат вызова этой функции. Вставим в функцию void OnTick() вызов нашей функции и примем значение в переменную int isCrossed. А для контроля вместо открытия позиции просто напечатаем текст "Откроем позицию Buy" или "Откроем позицию Sell".

Теперь код функции OnTick() выглядит так

Код
//+------------------------------------------------------------------+
//| Expert tick function                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int isCrossed = Crossing();
    if(isCrossed == 0)
     Print("Откроем позицию Buy");
    if(isCrossed == 1)
     Print("Откроем позицию Sell");
  }
//+------------------------------------------------------------------+


Но вот незадача… Получается что пересечение действительно на каждом тике пока не закроется текущий бар… Следовательно откроется несколько позиций подряд. Чтобы это предотвратить надо организовать открытие позиций только один раз на баре в момент его первого тика. Для этого напишем ещё одну пользовательскую функцию.

Выглядит она так.

Код
bool newBar()
{
static datetime timeLastBar;
  MqlRates mqlRates[];
   int s = 0;
    do
     {
      s++;
     }
    while(CopyRates(_Symbol, PERIOD_CURRENT, 0, 1, mqlRates) < 0 && s < 7);
   bool ret = timeLastBar != mqlRates[0].time;
   if(ret)
    timeLastBar = mqlRates[0].time;
   return(ret);
}/*******************************************************************/


В этой функции объявлена статическая static переменная типа datetime timeLastBar которая хранит время открытия бара на котором было последнее обращение к этой функции. Для определения времени открытия текущего бара будем использовать функцию CopyRates() и помещать результат в массив структур типа MqlRates. Затем полученное время последнего бара сравнивается с временем хранящимся в переменной timeLastBar и если оно изменилось в переменную запишется время последнего бара и функция вернёт true. Если-же время не изменилось, возвращается false.
Поместим его опять-же в самый конец нашего кода и исправим вызов функции Crossing()

Таким образом, вызов функции выглядит так.

Код
//+------------------------------------------------------------------+
//| Expert tick function                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int isCrossed = Crossing();
   if(newBar())
    {
     if(isCrossed == 0)
     Print("Откроем позицию Buy");
     if(isCrossed == 1)
     Print("Откроем позицию Sell");
    }
  }


Теперь можно запустить код в тестере стратегий и понаблюдать когда в журнале будет печататься наши сообщения.
 
ШрусДата: Среда, 02.08.2017, 17:01 | Сообщение # 2
Генералиссимус
Группа: Администраторы
Сообщений: 8006
Статус: Offline
Краткий курс программирования ЕА на MQL5 без ООП и стандартной библиотеки

И вот теперь самое трудное и новое. Будем писать функции открытия и модификации позиций.
Начнём с того, что определим имя функции, типы и имена входящих параметров, объявим и обнулим переменные структур которые используются в функции проверки OrderCheck( ) и функции запроса OrderSend()

Код
bool openPosition(ENUM_ORDER_TYPE type // Тип ордера
                 , double volume       // Запрашиваемый объем сделки в лотах
                 , int sl              // Stop Loss ордера в пунктах
                 , int tp              // Take Profit ордера в пунктах
                 , int magic = 0       // MagickNumber ордера
                 , string comm = NULL  // комментарий ордера/позиции
                 )
{
MqlTradeCheckResult checkResult;
   ZeroMemory(checkResult);
MqlTradeRequest     request;
  ZeroMemory(request);
MqlTradeResult      tradeResult;
    ZeroMemory(tradeResult);
  
  return(false);
}/*******************************************************************/


Затем объявим переменную для хранения актуальных цен и заполним структуру mqlTick.

Код
MqlTick             mqlTick;
      int s = 0;
       do
        {
         s++;
        }
       while(!SymbolInfoTick(_Symbol, mqlTick) && s < 7);
        double price = type == ORDER_TYPE_BUY ? mqlTick.ask : mqlTick.bid;
      double stop = type == ORDER_TYPE_BUY ? price-(sl*_Point) : price+(sl*_Point)
           , take = type == ORDER_TYPE_BUY ? price+(tp*_Point) : price-(tp*_Point);


Получим это свойство в переменную типа перечисления.

Код
ENUM_SYMBOL_TRADE_EXECUTION exec = (ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE);


Теперь самое время заполнять структуру запроса. От режима заключения сделок зависит не только поле type_filling но и как заполнять поля sl и tp
Если тип исполнения Market то стопы и тейки можно устанавливать только после открытия позиции посредством модификации позиции. Соответственно при заполнении учтём этот факт.

Заполнение структуры:

Код
request.action         =  TRADE_ACTION_DEAL;
     request.symbol         =  _Symbol;
      request.volume         =  volume;
       request.price          =  price;
        request.sl             =  exec == SYMBOL_TRADE_EXECUTION_MARKET ? 0.0 : sl == 0 ? 0.0 : NormalizeDouble(stop, _Digits);
         request.tp             =  exec == SYMBOL_TRADE_EXECUTION_MARKET ? 0.0 : tp == 0 ? 0.0 : NormalizeDouble(take, _Digits);
        request.deviation      =  555;
       request.type           =  type;
      request.type_filling   =  exec == SYMBOL_TRADE_EXECUTION_MARKET ? ORDER_FILLING_FOK : ORDER_FILLING_RETURN;
     request.magic          =  magic;
    request.comment        =  comm;


ВСЁ… Теперь проверим достаточность средств и правильность заполнения структуры запроса и отправим запрос на исполнение.
И последнее, если тип исполнения Market то после открытия позиции надо будет её выбрать для дальнейшей работы с ней и установить Stop Loss и Take Profit.
Так выглядит код открытия позиции.

Код
bool openPosition(ENUM_ORDER_TYPE type // Тип ордера
                 , double volume       // Запрашиваемый объем сделки в лотах
                 , int sl              // Stop Loss ордера в пунктах
                 , int tp              // Take Profit ордера в пунктах
                 , int magic = 0       // MagickNumber ордера
                 , string comm = NULL  // комментарий ордера/позиции
                 )
{
MqlTradeCheckResult checkResult;
   ZeroMemory(checkResult);
MqlTradeRequest     request;
  ZeroMemory(request);
MqlTradeResult      tradeResult;
    ZeroMemory(tradeResult);
MqlTick             mqlTick;
      int s = 0;
       do
        {
         s++;
        }
       while(!SymbolInfoTick(_Symbol, mqlTick) && s < 7);
        double price = type == ORDER_TYPE_BUY ? mqlTick.ask : mqlTick.bid;
      double stop = type == ORDER_TYPE_BUY ? price-(sl*_Point) : price+(sl*_Point)
           , take = type == ORDER_TYPE_BUY ? price+(tp*_Point) : price-(tp*_Point);
     ENUM_SYMBOL_TRADE_EXECUTION exec = (ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE);
    request.action         =  TRADE_ACTION_DEAL;
     request.symbol         =  _Symbol;
      request.volume         =  volume;
       request.price          =  price;
        request.sl             =  exec == SYMBOL_TRADE_EXECUTION_MARKET ? 0.0 : sl == 0 ? 0.0 : NormalizeDouble(stop, _Digits);
         request.tp             =  exec == SYMBOL_TRADE_EXECUTION_MARKET ? 0.0 : tp == 0 ? 0.0 : NormalizeDouble(take, _Digits);
        request.deviation      =  555;
       request.type           =  type;
      request.type_filling   =  exec == SYMBOL_TRADE_EXECUTION_MARKET ? ORDER_FILLING_FOK : ORDER_FILLING_RETURN;
     request.magic          =  magic;
    request.comment        =  comm;
     if(!OrderCheck(request, checkResult))
      Print(__FUNCTION__, " ", checkResult.retcode, " ", request.volume, " ", checkResult.margin_free-checkResult.margin);
    else
      {
       if(!OrderSend(request, tradeResult))
        Print(__FUNCTION__, " ", tradeResult.retcode);
       if(exec == SYMBOL_TRADE_EXECUTION_MARKET)
        {
         int n = 0;
          do
           {
            n++;
           }
          while(!PositionSelectByTicket(tradeResult.order) && n < 5);
          sl_tp_Modification(stop, take, tradeResult.order);
        }
       return(true);
      }
  return(false);
}/*******************************************************************/


Поскольку модификация позиций выполняется той-же функцией OrderSend() подробно разбирать её не имеет смысла. Отличие только в заполняемых полях структуры.

Так выглядит код модификации позиции.

Код
bool sl_tp_Modification(double stopLoss
                       , double takeProfit
                       , ulong  ticket
                       )
{
bool ret = false;
MqlTradeRequest     request;
MqlTradeCheckResult checkResult;
MqlTradeResult      tradeResult;
  ZeroMemory(request);
   ZeroMemory(checkResult);
    ZeroMemory(tradeResult);
   if(PositionSelectByTicket(ticket))
    {
     request.action         =  TRADE_ACTION_SLTP;
      request.symbol         =  PositionGetString(POSITION_SYMBOL);
       request.sl             =  stopLoss;
      request.tp             =  takeProfit;
     request.position       =  ticket;
    if(!OrderCheck(request, checkResult))
     {
     Print("****** StopLoss ", stopLoss);
     Print("****** Take_Profit ", takeProfit);
     Print("****** ticket ", ticket);
     return(ret);
     }
    }
  ret = OrderSend(request, tradeResult);
  if(!ret)  Print(__FUNCTION__, " ", tradeResult.retcode);
   return(ret);
}/*******************************************************************/


Вот теперь можно внести изменения и вместо печати в журнал открывать позиции.

Код
//+------------------------------------------------------------------+
//| Expert tick function                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int isCrossed = Crossing();
   if(newBar())
    {
     if(isCrossed == 0)
      openPosition(ORDER_TYPE_BUY, lot, loss, tacke);
     if(isCrossed == 1)
      openPosition(ORDER_TYPE_SELL, lot, loss, tacke);
    }
  }


Замечание: Наш советник предназначен для обучения и не будет, не нацелен на извлечение прибыли.

Важно:
Для правильного заполнения поля type_filling нам необходимо знать режимы заключения сделок по конкретному инструменту.


Скачать Полный код советника
Прикрепления: MyFirstEA.mq5 (13.9 Kb)
 
Форум » Раздел о рынке FOREX » Язык программирования MQL 5 » Программирования ЕА на MQL5
  • Страница 1 из 1
  • 1
Поиск:

Copyright MyCorp © 2024 Сайт управляется системой uCoz
Яндекс.Метрика