Смотри, как бесплатно скачать роботов
Ищи нас в Facebook!
Ставь лайки и следи за новостями
Интересный скрипт?
Поставь на него ссылку - пусть другие тоже оценят
Понравился скрипт?
Оцени его работу в терминале MetaTrader 5
Просмотров:
13642
Рейтинг:
(53)
Опубликован:
2013.10.28 11:14
Обновлен:
2018.06.04 17:55
Нужен робот или индикатор на основе этого кода? Закажите его на бирже фрилансеров Перейти на биржу

Советник Moving Average входит в комплект стандартной поставки клиентского терминала MetaTrader 5 и представляет собой пример советника, торгующего при помощи индикатора Moving Average.

Файл советника Moving Average.mq5 располагается в папке: "каталог_данных_терминала\MQL5\Experts\Examples\Moving Average\". Данный советник представляет собой пример использования технических индикаторов, функций работы с торговой историей и торговых классов Стандартной библиотеки. Кроме того, в советнике реализована система управления капиталом в зависимости от результатов торговли.

Рассмотрим подробнее структуру этого советника и принцип его работы.

1. Свойства советника

//+------------------------------------------------------------------+
//|                                              Moving Averages.mq5 |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2009-2013, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00

Первые 5 строк содержат комментарий, следующие три строки задают свойства MQL5-программы (copyright, link, version) при помощи директивы препроцессора #property.

При запуске советника они отображаются во вкладке "Общие":

Свойства советника Moving Average

Рис.1. Общие параметры советника Moving Average


1.2. Включаемые файлы

Далее при помощи директивы #include следует указание компилятору о необходимости включения файла "Trade.mqh".

Это файл является частью Стандартной библиотеки, в нем содержится класс CTrade для упрощенного доступа к торговым функциям.

#include <Trade\Trade.mqh>

Наименование включаемого файла указано в скобках "<>", поэтому путь задается относительно каталога: "папка_данных_терминала\Include\".

1.3 Входные параметры

После этого указываются тип, наименования, значения по умолчанию и комментарии, роль которых показана на рис. 2.

input double MaximumRisk        = 0.02;    // Maximum Risk in percentage
input double DecreaseFactor     = 3;       // Descrease factor
input int    MovingPeriod       = 12;      // Moving Average period
input int    MovingShift        = 6;       // Moving Average shift

Входные параметры MaximumRisk и DecreaseFactor будут использоваться при управлении капиталом, параметры MovingPeriod и MovingShift определяют период и сдвиг технического индикатора Moving Average, который будет использоваться для проверки наступления торговых условий.

Текст, указанный в комментариях в строке входного параметра, наряду со значениями по умолчанию, отображается во вкладке "Параметры" вместо наименования входного параметра:

Moving Average Expert Advisor Input parameters

Рис 2. Входные параметры советника Moving Average

1.4. Глобальные переменные

После этого объявляется глобальная переменная ExtHandle, она будет использоваться для хранения хендла индикатора Moving Average.

//---
int   ExtHandle=0;

Далее идут 6 функций, предназначение каждой из них описано в комментарии перед телом функции:

  1. TradeSizeOptimized() - выполняет расчет оптимального размера лота (Calculate optimal lot size);
  2. CheckForOpen() - проверяет условия открытия позиции (Check for open position conditions);
  3. CheckForClose() - проверяет условия закрытия позиции (Check for close position conditions);
  4. OnInit() - функция инициализации советника (Expert initialization function);
  5. OnTick() - обработчик события OnTick (Expert tick function);
  6. OnDeinit() - функция деинициализации советника (Expert deinitialization function);

Последние 3 функции - это функции обработки событий, в их коде осуществляется вызов первых трех сервисных функций.


2. Функции обработки событий

2.1. Функция инициализации OnInit()

Функция OnInit() вызывается один раз при первом запуске советника. В обработчике события OnInit() обычно производится подготовка советника к работе: проверка корректности входных параметров, инициализация индикаторов, переменных и т.д. В случае критических ошибок, при которых дальнейшая работа не имеет смысла, используется выход из функции с кодом возврата INIT_FAILED.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Error creating MA indicator");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Поскольку торговля советника основана на индикаторе Moving Average, при помощи вызова функции iMA() создается индикатор Moving Average и его хендл сохраняется в глобальную переменную ExtHandle.

В случае ошибки производится выход из функции OnInit() с кодом возврата INIT_FAILED - это правильный способ завершения работы советника/индикатора в случае неудачной инициализации.


2.2. Функция OnTick()

Функция OnTick() вызывается каждый раз при поступлении новой котировки по символу графика, на котором запущен советник.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(PositionSelect(_Symbol))
      CheckForClose();
   else
      CheckForOpen();
//---
  }

При помощи функции PositionSelect() определяется факт наличия открытой позиции по текущему символу.

Если в настоящий момент есть открытая позиция, то вызывается функция CheckForClose(), в которой производится анализ текущего состояния рынка и закрытие открытой позиции, иначе вызывается функции CheckForOpen(), в которой проверяются условия входа в рынок и при их наступлении производится открытие новой позиции.


2.3. Функция деинициализации OnDeInit()

Функция деинициализации OnDeInit() вызывается при удалении советника с графика. Если в процессе работы программа размещает графические объекты, их можно убрать с графика.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+

В данном случае при деинициализации советника никаких действий не производится.


3. Сервисные функции

3.1. Функция TradeSizeOptimized()

Эта функция выполняет расчет и возвращает значение оптимального размера лота для открытия позиции с учетом заданного уровня риска и результатов торговли.

//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- рассчитываем размер лота
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2);
//--- рассчитываем длину серии непрерывных убыточных сделок
   if(DecreaseFactor>0)
     {
      //--- запрашиваем всю торговую историю
      HistorySelect(0,TimeCurrent());
      //--
      int    orders=HistoryDealsTotal();  // общее количество сделок
      int    losses=0;                    // количество убыточных сделок в серии

      for(int i=orders-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(ticket==0)
           {
            Print("HistoryDealGetTicket failed, no trade history");
            break;
           }
         //--- проверка символа сделки
         if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
         //--- проверка прибыли
         double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
         if(profit>0.0)
            break;
         if(profit<0.0)
            losses++;
        }
      //---
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- нормализация и проверка допустимых значений торгового объема
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;

   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- возвращаем значение торгового объема
   return(lot);
  }

При помощи функции SymbolInfoDouble() проверяется наличие цен для текущего символа, далее при помощи функции OrderCalcMargin() осуществляется запрос маржи, необходимой для выставления ордера (в данном случае указан ордер на покупку). Начальный размер лота определяется исходя из значения маржи, необходимой для выставления ордера, свободной маржи счета (AccountInfoDouble(ACCOUNT_FREEMARGIN)) и максимально допустимому значению риска, заданному во входном параметре MaximumRisk.

При положительном значении входного параметра DecreaseFactor производится анализ сделок в истории и корректировка размера лота с учетом информации о максимальной серии убыточных сделок: начальный размер лота умножается на величину (1-losses/DecreaseFactor).

Затем производится "округление" торгового объема до величины, кратной минимально допустимому шагу объема (stepvol) для текущего символа. Также запрашиваются минимальное (minvol) и максимально возможные значения (maxvol) торгового объема, и в случае выхода величины lot за допустимые пределы производится ее корректировка. В результате функция возвращает рассчитанное значение торгового объема.


3.2. Функция CheckForOpen()

Функция CheckForOpen() производит проверку условий открытия позиции и осуществляет ее открытие в случае наступления торговых условий (в данном случае - пересечение ценой скользящей средней).

//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- копируем значения цен
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
//--- торгуем только на первом тике нового бара
   if(rt[1].tick_volume>1)
      return;
//--- получаем текущее значение индикатора Moving Average 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }
//--- проверка сигналов
   ENUM_ORDER_TYPE signal=WRONG_VALUE;

   if(rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=ORDER_TYPE_SELL;    // условие на продажу
   else
     {
      if(rt[0].open<ma[0] && rt[0].close>ma[0])
         signal=ORDER_TYPE_BUY;  // условие на покупку
     }
//--- дополнительные проверки
   if(signal!=WRONG_VALUE)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),
                               SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
                               0,0);
           }
//---
  }

При торговле с помощью скользящей средней требуется проверка факта пересечения ценой скользящей средней. При помощи функции CopyRates() в массив структур rt[] копируются два значения текущих цен, rt[1] соответствует текущему бару, а rt[0] - завершенному бару.

Начало нового бара осуществляется путем проверки тикового объема текущего бара - если он равен 1, то имеет место факт наступления нового бара. Следует отметить, что данный способ обнаружения нового бара может не работать в некоторых случаях (когда котировки приходят пачками), поэтому факт начала построения нового бара рекомендуется производить путем сохранения и сравнения времени текущей котировки (см. IsNewBar).

Текущее значение индикатора Moving Average запрашивается при помощи функции CopyBuffer() и сохраняется в массиве ma[], содержащем только одно значение. После этого производится проверка факта пересечения ценой скользящей средней и дополнительные проверки (проверка возможности торговли при помощи советника и наличие баров в истории). В случае успеха производится открытие соответствующей позиции по инструменту при помощи вызова метода PositionOpen() объекта trade (экземпляра класса CTrade).

Цена открытия позиции задается при помощи функции SymbolInfoDouble(), возвращающей цену Bid или Ask в зависимости от значения переменной signal. Объем позиции определяется при помощи вызова функции TradeSizeOptimized(), рассмотренной выше.


3.3. Функция CheckForClose()

Функция CheckForClose() производит проверку условий закрытия позиции и осуществляет ее закрытие при наступлении условий ее закрытия.

//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   MqlRates rt[2];
//--- копируем значения цен
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
//--- торгуем только на первом тике нового бара
   if(rt[1].tick_volume>1)
      return;
//--- получаем текущее значение индикатора Moving Average 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }
//--- получаем тип позиции, выбранной ранее через PositionSelect()
   bool signal=false;
   long type=PositionGetInteger(POSITION_TYPE);

   if(type==(long)POSITION_TYPE_BUY   && rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=true;
   if(type==(long)POSITION_TYPE_SELL  && rt[0].open<ma[0] && rt[0].close>ma[0])
      signal=true;
//--- дополнительные проверки
   if(signal)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionClose(_Symbol,3);
           }
//---
  }

Алгоритм работы функции CheckForClose() аналогичен алгоритму работы CheckForOpen(). В зависимости от направления текущей открытой позиции проверяются условия ее закрытия (пересечение ценой средней сверху вниз для покупки или пересечение ценой средней снизу вверх для продажи). Закрытие открытой позиции осуществляется при помощи вызова метода PositionClose() объекта trade (экземпляра класса CTrade).


4. Тестирование на исторических данных

Наилучшие значения параметров можно найти при помощи тестера стратегий терминала MetaTrader 5.

Например, при оптимизации параметра MovingPeriod на интервале 2012.01.01-2013.08.01 наилучшие результаты получаются при MovingPeriod=45:

Результаты тестирования на исторических данных советника Moving Average

Результаты тестирования на исторических данных советника Moving Average

Выводы:

Советник Moving Average, входящий в поставку клиентского терминала MetaTrader 5, представляет собой пример использования технических индикаторов, функций работы с торговой историей и торговых классов Стандартной библиотеки. Кроме того, в советнике реализована система управления капиталом в зависимости от результатов торговли.


INERCIA_bars INERCIA_bars

Окраска баров ценового графика в зависимости от величины изменения цены.

Stoch_3HTF Stoch_3HTF

Три основных линии стохастика с трех различных таймфреймов на одном графике.

LinearRegressionLine LinearRegressionLine

Линия линейной регрессии с размещением данных в индикаторном буфере.

LW_Fractals LW_Fractals

Индикатор отрисовывает фракталы по трем свечкам.