Эксперты на основе популярных торговых систем и алхимия оптимизации торгового робота (Продолжение)

Автор: lexy Вторник, Сентябрь 9th, 2014 Нет комментариев

Рубрика: Разное

В своей предыдущей статье я подробно занялся построением экспертов, обрабатывающих информацию, которая поступает с двух разных таймфреймов. Но всё дело в том, что этой информации далеко не всегда бывает достаточно для того, чтобы войти в рынок очень точно. Например, если меньший таймфрейм равен часовику, то вход в рынок сразу на смене часового бара — это зачастую далеко не самое лучшее решение, потому как тенденция, действующая на более мелком таймфрейме, чем часовой, и обычно присутствующая в ценовом шуме, может работать против открываемой позизии. Во многих случаях такую кратковременную тенденцию можно достаточно легко определить. И в случае, если она идёт против открываемой позиции, то отложить вход в рынок до того момента, когда эта, действующая на самом мелком таймфрейме, тенденция не изменит своё направление на противоположное. Или в худшем случае войти в рынок перед следующей сменой часового бара. С решения этой задачи я и начну свою статью.

«Три экрана Элдера»

Сам Александр Элдер известен как автор достаточно популярных книг по психоанализу фондового рынка. Ему принадлежит идея использования для анализа финансовых рынков графиков трёх временных форматов, которые назвали тремя экранами Элдера. Два «экрана» мы строить уже научились в моей предыдущей статье. Теперь нам предстоит достроить третий «экран». В качестве примеров для дальнейшего усложнения кода можно было бы взять уже готовых экспертов из предыдущей статьи, но я для разнообразия излагаемого материала построю по аналогичной схеме код другого эксперта (Exp_14.mq4).

В качестве первоначального аналога для построения кода я взял эксперта Exp_12.mq4, в котором сделал замену сигнального мувинга JFatl.nq4 на осциллятор JCCIX.mq4 и трендового индикатора MAMA_NK.mq4, состоящего из двух мувингов на индикатор StepMA_Stoch_NK.mq4, состоящего из пары стохастических осцилляторов. Сама первоначальная схема алгоритма в конечном счёте осталась прежней, поменялись только обращения к пользовательским индикаторам, внешние переменные эксперта и инициализация констант в блоке функции init() и немного усложнился код блоков для определения сигналов входа в рынок. Я ещё раз представлю сам алгоритм работы этого эксперта с использованием двух таймфреймов в самом общем виде, аналогично тому, что я делал в предыдущей статье, но теперь я это сделаю в немного более развёрнутом виде.

Для длинных позиций мы имеем:

И для коротких позиций:

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

Для лонгов:

И для шортов:

Сама реализация этого алгоритма в программном коде и на основе эксперта Exp_15.mq4 может быть представлена следующим образом:

//+==================================================================+
//|                                                       Exp_15.mq4 |
//|                             Copyright © 2008,   Nikolay Kositsin |
//|                              Khabarovsk,   farria@mail.redcom.ru |
//+==================================================================+
#property copyright "Copyright © 2008, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//----+ +---------------------------------------------------------------------------+
//---- ВХОДНЫЕ ПАРАМЕТРЫ ЭКСПЕРТА ДЛЯ BUY СДЕЛОК
extern bool   Test_Up = true;//фильтр направления расчётов сделок
extern double Money_Management_Up = 0.1;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +  
extern int    TimeframeX_Up = 1440;                
extern int    PeriodWATR_Up = 10;
extern double Kwatr_Up = 1.0000;
extern int    HighLow_Up = 0;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    Timeframe_Up = 240;
extern int    JJLength_Up = 8;  // глубина JJMA сглаживания входной цены
extern int    JXLength_Up = 8;  // глубина JurX сглаживания полученного индикатора
extern int    Phase_Up = 100;// параметр, изменяющийся в пределах
                        // -100 ... +100, влияет на качество переходного процесса;
extern int    IPC_Up = 0; /* Выбор цен, по которым производится расчёт
индикатора (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL,
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW,
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open,
14-Heiken Ashi Close.) */
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    TimeframeN_Up = 15;
extern int    Noise_period_Up = 8;
//extern int    SmoothN_Up = 7;
//extern int    MaMethodN_Up = 1;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    STOPLOSS_Up = 50;  // стоплосс
extern int    TAKEPROFIT_Up = 100; // тейкпрофит
extern bool   ClosePos_Up = true; // разрешение принудительного закрывания позиции
//----+ +---------------------------------------------------------------------------+
//---- ВХОДНЫЕ ПАРАМЕТРЫ ЭКСПЕРТА ДЛЯ SELL СДЕЛОК
extern bool   Test_Dn = true;//фильтр направления расчётов сделок
extern double Money_Management_Dn = 0.1;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    TimeframeX_Dn = 1440;
extern int    PeriodWATR_Dn = 10;
extern double Kwatr_Dn = 1.0000;
extern int    HighLow_Dn = 0;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    Timeframe_Dn = 240;
extern int    JJLength_Dn = 8;  // глубина JJMA сглаживания входной цены
extern int    JXLength_Dn = 8;  // глубина JurX сглаживания полученного индикатора
extern int    Phase_Dn = 100;// параметр, изменяющийся в пределах
                        // -100 ... +100, влияет на качество переходного процесса;
extern int    IPC_Dn = 0; /* Выбор цен, по которым производится расчёт
индикатора (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL,
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW,
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open,
14-Heiken Ashi Close.) */
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    TimeframeN_Dn = 15;
extern int    Noise_period_Dn = 8;
//extern int    SmoothN_Dn = 7;
//extern int    MaMethodN_Dn = 1;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    STOPLOSS_Dn = 50;  // стоплосс
extern int    TAKEPROFIT_Dn = 100; // тейкпрофит
extern bool   ClosePos_Dn = true; // разрешение принудительного закрывания позиции
//----+ +---------------------------------------------------------------------------+
//---- Целые переменные для обращений к пользовательским индикаторам
int SmoothN_Up = 7, SmoothN_Dn = 7, MaMethodN_Up = 1, MaMethodN_Dn = 1;
//---- Целые переменные для минимума расчётных баров
int MinBar_Up, MinBar_Dn, MinBarX_Up, MinBarX_Dn, MinBarN_Up, MinBarN_Dn;
//+==================================================================+
//| Custom Expert functions                                          |
//+==================================================================+
#include <Lite_EXPERT1.mqh>
//+==================================================================+
//| TimeframeCheck() functions                                       |
//+==================================================================+
void TimeframeCheck(string Name, int Timeframe)
  {
//----+
   //---- Проверка значения переменной Timeframe на корректность
   if (Timeframe != 1)
    if (Timeframe != 5)
     if (Timeframe != 15)
      if (Timeframe != 30)
       if (Timeframe != 60)
        if (Timeframe != 240)
         if (Timeframe != 1440)
           Print(StringConcatenate("Параметр ",Name,
                     " не может ", "быть равным ", Timeframe, "!!!"));    
//----+
  }
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//---- Проверка значения переменных таймфреймов на корректность
   TimeframeCheck("TimeframeX_Up", TimeframeX_Up);
   TimeframeCheck("Timeframe_Up", Timeframe_Up);
   TimeframeCheck("TimeframeN_Up", TimeframeN_Up);

//---- Проверка значения переменных таймфреймов на корректность
   TimeframeCheck("TimeframeX_Dn", TimeframeX_Dn);
   TimeframeCheck("Timeframe_Dn", Timeframe_Dn);
   TimeframeCheck("TimeframeN_Dn", TimeframeN_Dn);

//---- Инициализация переменных            
   MinBarX_Up = 2 + PeriodWATR_Up;
   MinBar_Up = 4 + 3 * JXLength_Up + 30;
   MinBarN_Up = 4 + Noise_period_Up + SmoothN_Up;

//---- Инициализация переменных
   MinBarX_Dn = 2 + PeriodWATR_Dn;
   MinBar_Dn = 4 + 3 * JXLength_Dn + 30;
   MinBarN_Dn = 4 + Noise_period_Dn + SmoothN_Dn;

//---- завершение инициализации
   return(0);
  }
//+==================================================================+
//| expert deinitialization function                                 |
//+==================================================================+  
int deinit()
  {
//----+

    //---- Завершение деинициализации эксперта
    return(0);
//----+
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Объявление локальных переменных
   int    bar;
   double JCCIX[2], Trend, Fast_StepMA, Slow_StepMA, MA1, MA2;
   //----+ Объявление статических переменных
   static datetime StopTime_Up, StopTime_Dn;
   static double   TrendX_Up, TrendX_Dn, OldTrend_Up, OldTrend_Dn;
   //---
   static int  LastBars_Up, LastBars_Dn;
   static int  LastBarsX_Up, LastBarsX_Dn, LastBarsN_Up, LastBarsN_Dn;
   //---
   static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop;
   static bool SecondStart_Up, SecondStart_Dn, NoiseBUY_Sign, NoiseSELL_Sign;

   //----+ +---------------------------------------------------------------+
   //----++ КОД ДЛЯ ДЛИННЫХ ПОЗИЦИЙ                                        |
   //----+ +---------------------------------------------------------------+
   if (Test_Up)
    {
      int IBARS_Up = iBars(NULL, Timeframe_Up);
      int IBARSX_Up = iBars(NULL, TimeframeX_Up);
      int IBARSN_Up = iBars(NULL, TimeframeN_Up);
      //---
      if (IBARS_Up >= MinBar_Up && IBARSX_Up >= MinBarX_Up && IBARSN_Up >= MinBarN_Up)
       {      
         //----+ +----------------------+
         //----+ ОПРЕДЕЛЕНИЕ ТРЕНДА     |
         //----+ +----------------------+
         if (LastBarsX_Up != IBARSX_Up)
          {
           //----+ Инициализация переменных
           LastBarsX_Up = IBARSX_Up;
           BUY_Sign = false;
           BUY_Stop = false;

           //----+ вычисление индикаторных значений
           Fast_StepMA = iCustom(NULL, TimeframeX_Up, "StepMA_Stoch_NK",
                                 PeriodWATR_Up, Kwatr_Up, HighLow_Up, 0, 1);
           //---        
           Slow_StepMA = iCustom(NULL, TimeframeX_Up, "StepMA_Stoch_NK",
                                 PeriodWATR_Up, Kwatr_Up, HighLow_Up, 1, 1);
           //----+ определение тренда                                
           TrendX_Up = Fast_StepMA - Slow_StepMA;
           //----+ определение сигнала для закрывания сделок
           if (TrendX_Up < 0)
                      BUY_Stop = true;                                      
          }

         //----+ +----------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +----------------------------------------+
         if (LastBars_Up != IBARS_Up && TrendX_Up > 0)
          {
           //----+ Инициализация переменных
           BUY_Sign = false;
           LastBars_Up = IBARS_Up;
           //----+ Инициализация шумовых переменных
           NoiseBUY_Sign = false;
           StopTime_Up = iTime(NULL, Timeframe_Up, 0)
                                          + 50 * Timeframe_Up;

           //----+ Инициализация нуля
           if (!SecondStart_Up)
            {
              //--- Поиск направления тренда на первом старте
              for(bar = 2; bar < IBARS_Up - 1; bar++)
               {
                 JCCIX[0] = iCustom(NULL, Timeframe_Up,
                    "JCCIX", JJLength_Up, JXLength_Up, Phase_Up, IPC_Up, 0, bar);
                 //---  
                 JCCIX[1] =  iCustom(NULL, Timeframe_Up,
                    "JCCIX", JJLength_Up, JXLength_Up, Phase_Up, IPC_Up, 0, bar + 1);
                 //---  
                 OldTrend_Up = JCCIX[0] - JCCIX[1];
                 //---    
                 if (OldTrend_Up != 0)
                   {
                    SecondStart_Up = true;
                    break;
                   }
               }
            } 

           //----+ вычисление индикаторных значений и загрузка их в буфер      
           for(bar = 1; bar < 3; bar++)
                     JCCIX[bar - 1] =                  
                         iCustom(NULL, Timeframe_Up,
                                "JCCIX", JJLength_Up, JXLength_Up,
                                                   Phase_Up, IPC_Up, 0, bar);

           //----+ определение сигналов для сделок  
           Trend = JCCIX[0] - JCCIX[1];

           if (TrendX_Up > 0)                    
              if (OldTrend_Up < 0)
                         if (Trend > 0)
                                 BUY_Sign = true;
           if (Trend != 0)
                   OldTrend_Up = Trend;                                  
          }

         //----+ +------------------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +------------------------------------------------+
         if (BUY_Sign)
          if (LastBarsN_Up != IBARSN_Up)
           {
             NoiseBUY_Sign = false;
             LastBarsN_Up = IBARSN_Up;
             //---
             MA1 = iCustom(NULL, TimeframeN_Up,
                      "2Moving Avereges", Noise_period_Up, SmoothN_Up,
                         MaMethodN_Up, MaMethodN_Up, PRICE_LOW, 0, 0, 1);
             //---
             MA2 = iCustom(NULL, TimeframeN_Up,
                       "2Moving Avereges", Noise_period_Up, SmoothN_Up,
                         MaMethodN_Up, MaMethodN_Up, PRICE_LOW, 0, 0, 2);
             //---                  
             if (MA1 > MA2 || TimeCurrent() > StopTime_Up)  
                                           NoiseBUY_Sign = true;

           }

         //----+ +-------------------+
         //----+ СОВЕРШЕНИЕ СДЕЛОК   |
         //----+ +-------------------+
         if (NoiseBUY_Sign)
           if (!OpenBuyOrder1(BUY_Sign, 1, Money_Management_Up,
                                          STOPLOSS_Up, TAKEPROFIT_Up))
                                                                 return(-1);
         if (ClosePos_Up)
                if (!CloseOrder1(BUY_Stop, 1))
                                        return(-1);
        }
     }

   //----+ +---------------------------------------------------------------+
   //----++ КОД ДЛЯ КОРОТКИХ ПОЗИЦИЙ                                       |
   //----+ +---------------------------------------------------------------+
   if (Test_Dn)
    {
      int IBARS_Dn = iBars(NULL, Timeframe_Dn);
      int IBARSX_Dn = iBars(NULL, TimeframeX_Dn);
      int IBARSN_Dn = iBars(NULL, TimeframeN_Dn);
      //---
      if (IBARS_Dn >= MinBar_Dn && IBARSX_Dn >= MinBarX_Dn && IBARSN_Dn >= MinBarN_Dn)
       {
         //----+ +----------------------+
         //----+ ОПРЕДЕЛЕНИЕ ТРЕНДА     |
         //----+ +----------------------+
         if (LastBarsX_Dn != IBARSX_Dn)
          {
           //----+ Инициализация переменных
           LastBarsX_Dn = IBARSX_Dn;
           SELL_Sign = false;
           SELL_Stop = false;

           //----+ вычисление индикаторных значений
           Fast_StepMA = iCustom(NULL, TimeframeX_Dn, "StepMA_Stoch_NK",
                                 PeriodWATR_Dn, Kwatr_Dn, HighLow_Dn, 0, 1);
           //---        
           Slow_StepMA = iCustom(NULL, TimeframeX_Dn, "StepMA_Stoch_NK",
                                 PeriodWATR_Dn, Kwatr_Dn, HighLow_Dn, 1, 1);
           //----+ определение тренда                                
           TrendX_Dn = Fast_StepMA - Slow_StepMA;
           //----+ определение сигнала для закрывания сделок
           if (TrendX_Dn > 0)
                      SELL_Stop = true;                                      
          }

         //----+ +----------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +----------------------------------------+
         if (LastBars_Dn != IBARS_Dn && TrendX_Dn < 0)
          {
           //----+ Инициализация переменных
           SELL_Sign = false;
           LastBars_Dn = IBARS_Dn;
           //----+ Инициализация шумовых переменных
           NoiseSELL_Sign = false;
           StopTime_Dn = iTime(NULL, Timeframe_Dn, 0)
                                          + 50 * Timeframe_Dn;

           //----+ Инициализация нуля
           if (!SecondStart_Dn)
            {
              //--- Поиск направления тренда на первом старте
              for(bar = 2; bar < IBARS_Dn - 1; bar++)
               {
                 JCCIX[0] = iCustom(NULL, Timeframe_Dn,
                    "JCCIX", JJLength_Dn, JXLength_Dn, Phase_Dn, IPC_Dn, 0, bar);
                 //---  
                 JCCIX[1] =  iCustom(NULL, Timeframe_Dn,
                    "JCCIX", JJLength_Dn, JXLength_Dn, Phase_Dn, IPC_Dn, 0, bar + 1);
                 //---  
                 OldTrend_Dn = JCCIX[0] - JCCIX[1];
                 //---    
                 if (OldTrend_Dn != 0)
                   {
                    SecondStart_Dn = true;
                    break;
                   }
               }
            } 

           //----+ вычисление индикаторных значений и загрузка их в буфер    
           for(bar = 1; bar < 3; bar++)
                     JCCIX[bar - 1]=                  
                         iCustom(NULL, Timeframe_Dn,
                                "JCCIX", JJLength_Dn, JXLength_Dn,
                                                   Phase_Dn, IPC_Dn, 0, bar);
           //----+ определение сигналов для сделок  
           Trend = JCCIX[0] - JCCIX[1];
           //---
           if (TrendX_Dn < 0)                                
              if (OldTrend_Dn > 0)
                         if (Trend < 0)
                                 SELL_Sign = true;
           if (Trend != 0)
                   OldTrend_Dn = Trend;                                        
          }

         //----+ +------------------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +------------------------------------------------+
         if (SELL_Sign)
          if (LastBarsN_Dn != IBARSN_Dn)
           {
             NoiseSELL_Sign = false;
             LastBarsN_Dn = IBARSN_Dn;
             //---
             MA1 = iCustom(NULL, TimeframeN_Dn,
                      "2Moving Avereges", Noise_period_Dn, SmoothN_Dn,
                         MaMethodN_Dn, MaMethodN_Dn, PRICE_HIGH, 0, 0, 1);
             //---
             MA2 = iCustom(NULL, TimeframeN_Dn,
                      "2Moving Avereges", Noise_period_Dn, SmoothN_Dn,
                         MaMethodN_Dn, MaMethodN_Dn, PRICE_HIGH, 0, 0, 2);
             //---                
             if (MA1 < MA2 || TimeCurrent() > StopTime_Dn)  
                                           NoiseSELL_Sign = true;
           }

         //----+ +-------------------+
         //----+ СОВЕРШЕНИЕ СДЕЛОК   |
         //----+ +-------------------+
         if (NoiseSELL_Sign)
           if (!OpenSellOrder1(SELL_Sign, 2, Money_Management_Dn,
                                            STOPLOSS_Dn, TAKEPROFIT_Dn))
                                                                  return(-1);
           if (ClosePos_Dn)
                if (!CloseOrder1(SELL_Stop, 2))
                                        return(-1);
        }
     }
//----+ 

    return(0);
  }
//+------------------------------------------------------------------+

Теперь мне следовало бы поподробнее остановиться на подробностях превращения эксперта Exp_14.mq4 в Exp_15.mq4. У нас появляется в программном коде новый модуль » ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК». Суть работы этого модуля можно выразить следующим образом (Я опять рассмотрю только алгоритм для длинных позиций):
Сигнал NoiseBUY_Sign возникает, если на самом мелком таймфрейме направление тренда совпадает с направлением сигнала входа в рынок BUY_Sig. Или, в случае несовпадения этого тренда, сигнал NoiseBUY_Sign возникает перед очередной сменой бара.

В качестве трендового мувинга я использовал индикатор, полученный двойным сглаживанием ценового ряда стандартными алгоритмами для усреднения. В качестве внешнего параметра для эксперта из этого модуля я использовал только две переменные:

extern int    TimeframeN_Up = 15;
extern int    Noise_period_Up = 8;

Большинство внешних переменных пользовательского индикатора 2Moving Avereges.mq4 я сделал фиксированными (инициализация глобальных переменных):

int SmoothN_Up = 7, SmoothN_Dn = 7, MaMethodN_Up = 1, MaMethodN_Dn = 1;

 

Остальная логика достраивания кода абсолютно аналогична тому, что я проделывал в своей предыдущей статье.

Общая идея построения экспертов с использованием трёх таймфреймов

Код эксперта, вообщем-то, готов, и на этом можно было бы и остановиться. Но, на мой взгляд, сделана самая незначительная часть работы. Едва ли первая же торговая система, написаная на основе подобной идеи, выдаст приличные результаты в реальной торговле. Так что в подобном мероприятии следует ориентироваться на то, что придётся строить код не одного и не двух подобных экспертов для того чтобы можно было выбрать более достойный вариант. Так что теперь перед нами предстоит задача абстрагироваться от конкретных алгоритмов расчёта торговых сигналов и оставить только сам алгоритм трёх экранов. Что по большому счёту не составляет никакой проблемы. Итоговый код без алгоритмов будет выглядеть вот так:

//+==================================================================+
//|                                                 ThreeScreens.mqh |
//|                             Copyright © 2008,   Nikolay Kositsin |
//|                              Khabarovsk,   farria@mail.redcom.ru |
//+==================================================================+
#property copyright "Copyright © 2008, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//----+ +---------------------------------------------------------------------------+
//---- ВХОДНЫЕ ПАРАМЕТРЫ ЭКСПЕРТА ДЛЯ BUY СДЕЛОК
extern bool   Test_Up = true;//фильтр направления расчётов сделок
extern double Money_Management_Up = 0.1;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +  
extern int    TimeframeX_Up = 1440;                
// Объявления и инициализации внешних параметров эксперта для лонгов для старшего таймфрейма
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    Timeframe_Up = 240;
// Объявления и инициализации внешних параметров эксперта для лонгов для среднего таймфрейма
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    TimeframeN_Up = 15;
// Объявления и инициализации внешних параметров эксперта для лонгов для младшего таймфрейма
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    STOPLOSS_Up = 50;  // стоплосс
extern int    TAKEPROFIT_Up = 100; // тейкпрофит
extern bool   ClosePos_Up = true; // разрешение принудительного закрывания позиции
//----+ +---------------------------------------------------------------------------+
//---- ВХОДНЫЕ ПАРАМЕТРЫ ЭКСПЕРТА ДЛЯ SELL СДЕЛОК
extern bool   Test_Dn = true;//фильтр направления расчётов сделок
extern double Money_Management_Dn = 0.1;
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    TimeframeX_Dn = 1440;
// Объявления и инициализации внешних параметров эксперта для шортов для старшего таймфрейма
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    Timeframe_Dn = 240;
// Объявления и инициализации внешних параметров эксперта для шортов для среднего таймфрейма
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    TimeframeN_Dn = 15;
// Объявления и инициализации внешних параметров эксперта для шортов для младшего таймфрейма
//---- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
extern int    STOPLOSS_Dn = 50;  // стоплосс
extern int    TAKEPROFIT_Dn = 100; // тейкпрофит
extern bool   ClosePos_Dn = true; // разрешение принудительного закрывания позиции
//----+ +---------------------------------------------------------------------------+
//---- Целые переменные для минимума расчётных баров
int MinBar_Up, MinBar_Dn, MinBarX_Up, MinBarX_Dn, MinBarN_Up, MinBarN_Dn;
//+==================================================================+
//| Custom Expert functions                                          |
//+==================================================================+
#include <Lite_EXPERT1.mqh>
//+==================================================================+
//| TimeframeCheck() functions                                       |
//+==================================================================+
void TimeframeCheck(string Name, int Timeframe)
  {
//----+
   //---- Проверка значения переменной Timeframe на корректность
   if (Timeframe != 1)
    if (Timeframe != 5)
     if (Timeframe != 15)
      if (Timeframe != 30)
       if (Timeframe != 60)
        if (Timeframe != 240)
         if (Timeframe != 1440)
           Print(StringConcatenate("Параметр ",Name,
                     " не может ", "быть равным ", Timeframe, "!!!"));    
//----+
  }
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//---- Проверка значения переменных таймфреймов на корректность
   TimeframeCheck("TimeframeX_Up", TimeframeX_Up);
   TimeframeCheck("Timeframe_Up", Timeframe_Up);
   TimeframeCheck("TimeframeN_Up", TimeframeN_Up);

//---- Проверка значения переменных таймфреймов на корректность
   TimeframeCheck("TimeframeX_Dn", TimeframeX_Dn);
   TimeframeCheck("Timeframe_Dn", Timeframe_Dn);
   TimeframeCheck("TimeframeN_Dn", TimeframeN_Dn);

//---- Инициализация переменных для лонгов            
   MinBarX_Up = // инициализация переменной для минимума расчётных баров для старшего таймфрейма
   MinBar_Up = // инициализация переменной для минимума расчётных баров для среднего таймфрейма
   MinBarN_Up = // инициализация переменной для минимума расчётных баров для младшего таймфрейма

//---- Инициализация переменных для шортов
   MinBarX_Dn =  // инициализация переменной для минимума расчётных баров для старшего таймфрейма
   MinBar_Dn =  // инициализация переменной для минимума расчётных баров для среднего таймфрейма
   MinBarN_Dn = // инициализация переменной для минимума расчётных баров для младшего таймфрейма

//---- завершение инициализации
   return(0);
  }
//+==================================================================+
//| expert deinitialization function                                 |
//+==================================================================+  
int deinit()
  {
//----+

    //---- Завершение деинициализации эксперта
    return(0);
//----+
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Объявление локальных переменных алгоритмов сделок
   //----+ Объявление статических переменных алгоритмов сделок

   //----+ Объявление статических переменных
   static datetime StopTime_Up, StopTime_Dn;
   //---
   static int  LastBars_Up, LastBars_Dn;
   static int  LastBarsX_Up, LastBarsX_Dn;
   static int  LastBarsN_Up, LastBarsN_Dn;
   //---
   static bool BUY_Sign, BUY_Stop;
   static bool SELL_Sign, SELL_Stop;
   static bool NoiseBUY_Sign, NoiseSELL_Sign;
   static double TrendX_Up, TrendX_Dn;

   //----+ +---------------------------------------------------------------+
   //----++ КОД ДЛЯ ДЛИННЫХ ПОЗИЦИЙ                                        |
   //----+ +---------------------------------------------------------------+
   if (Test_Up)
    {
      int IBARS_Up = iBars(NULL, Timeframe_Up);
      int IBARSX_Up = iBars(NULL, TimeframeX_Up);
      int IBARSN_Up = iBars(NULL, TimeframeN_Up);
      //---
      if (IBARS_Up >= MinBar_Up && IBARSX_Up >= MinBarX_Up && IBARSN_Up >= MinBarN_Up)
       {      
         //----+ +----------------------+
         //----+ ОПРЕДЕЛЕНИЕ ТРЕНДА     |
         //----+ +----------------------+
         if (LastBarsX_Up != IBARSX_Up)
          {
           //----+ Инициализация переменных
           LastBarsX_Up = IBARSX_Up;
           BUY_Sign = false;
           BUY_Stop = false;

           // Алгоритм определения направления тренда на старшем таймфрейме
                                              //(инициализация переменной TrendX_Up)

           //----+ определение сигнала для закрывания сделок
           if (TrendX_Up < 0)
                      BUY_Stop = true;                                      
          }

         //----+ +----------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +----------------------------------------+
         if (LastBars_Up != IBARS_Up && TrendX_Up > 0)
          {
           //----+ Инициализация переменных
           BUY_Sign = false;
           LastBars_Up = IBARS_Up;
           //----+ Инициализация шумовых переменных
           NoiseBUY_Sign = false;
           StopTime_Up = iTime(NULL, Timeframe_Up, 0)
                                          + 50 * Timeframe_Up;

           // Алгоритм для определения точки входа в рынок на среднем таймфрейме
                                                //(Инициализация переменной BUY_Sign)

          }

         //----+ +------------------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +------------------------------------------------+
         if (BUY_Sign)
          if (LastBarsN_Up != IBARSN_Up)
           {
             NoiseBUY_Sign = false;
             LastBarsN_Up = IBARSN_Up;
             //---

             // Алгоритм для уточнения точки входа в рынок на младшем таймфрейме
                                            //(Инициализация переменной NoiseBUY_Sign)

           }

         //----+ +-------------------+
         //----+ СОВЕРШЕНИЕ СДЕЛОК   |
         //----+ +-------------------+
         if (NoiseBUY_Sign)
           if (!OpenBuyOrder1(BUY_Sign, 1, Money_Management_Up,
                                          STOPLOSS_Up, TAKEPROFIT_Up))
                                                                 return(-1);
         if (ClosePos_Up)
                if (!CloseOrder1(BUY_Stop, 1))
                                        return(-1);
        }
     }

   //----+ +---------------------------------------------------------------+
   //----++ КОД ДЛЯ КОРОТКИХ ПОЗИЦИЙ                                       |
   //----+ +---------------------------------------------------------------+
   if (Test_Dn)
    {
      int IBARS_Dn = iBars(NULL, Timeframe_Dn);
      int IBARSX_Dn = iBars(NULL, TimeframeX_Dn);
      int IBARSN_Dn = iBars(NULL, TimeframeN_Dn);
      //---
      if (IBARS_Dn >= MinBar_Dn && IBARSX_Dn >= MinBarX_Dn && IBARSN_Dn >= MinBarN_Dn)
       {
         //----+ +----------------------+
         //----+ ОПРЕДЕЛЕНИЕ ТРЕНДА     |
         //----+ +----------------------+
         if (LastBarsX_Dn != IBARSX_Dn)
          {
           //----+ Инициализация переменных
           LastBarsX_Dn = IBARSX_Dn;
           SELL_Sign = false;
           SELL_Stop = false;

           // Алгоритм определения направления тренда на старшем таймфрейме
                                               //(инициализация переменной TrendX_Dn)

           //----+ определение сигнала для закрывания сделок
           if (TrendX_Dn > 0)
                      SELL_Stop = true;                                      
          }

         //----+ +----------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +----------------------------------------+
         if (LastBars_Dn != IBARS_Dn && TrendX_Dn < 0)
          {
           //----+ Инициализация переменных
           SELL_Sign = false;
           LastBars_Dn = IBARS_Dn;
           //----+ Инициализация шумовых переменных
           NoiseSELL_Sign = false;
           StopTime_Dn = iTime(NULL, Timeframe_Dn, 0)
                                          + 50 * Timeframe_Dn;

           // Алгоритм для определения точки входа в рынок на среднем таймфрейме
                                                //(Инициализация переменной SELL_Sign) 

          }

         //----+ +------------------------------------------------+
         //----+ ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК   |
         //----+ +------------------------------------------------+
         if (SELL_Sign)
          if (LastBarsN_Dn != IBARSN_Dn)
           {
             NoiseSELL_Sign = false;
             LastBarsN_Dn = IBARSN_Dn;
             //---

             // Алгоритм для уточнения точки входа в рынок на младшем таймфрейме
                                           //(Инициализация переменной NoiseSELL_Sign)

           }

         //----+ +-------------------+
         //----+ СОВЕРШЕНИЕ СДЕЛОК   |
         //----+ +-------------------+
         if (NoiseSELL_Sign)
           if (!OpenSellOrder1(SELL_Sign, 2, Money_Management_Dn,
                                            STOPLOSS_Dn, TAKEPROFIT_Dn))
                                                                  return(-1);
           if (ClosePos_Dn)
                if (!CloseOrder1(SELL_Stop, 2))
                                        return(-1);
        }
     }
//----+ 

    return(0);
  }
//+------------------------------------------------------------------+

Если использовать этот код как шаблон для написания экспертов, то сперва следует сделать инициализацию переменных в соответствующих блоках » ОПРЕДЕЛЕНИЕ ТРЕНДА » и » ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК «:

TrendX_Up = 1;
TrendX_Dn =-1;
Noise8uy_Sign = true;
NoiseSELL_Sign = true;

И после этого добавить ваш собственный код в блоки » ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК » и провести настройку работы эксперта с этим кодом. Как это делается можно посмотреть в коде эксперта Exp_15_A.mq4, в котором представлены только алгоритмы для определения сигналов для входов в рынок для среднего таймфрейма, а алгоритмы определения тренда на старшем таймфрейме и направления шумовой тенденции на младшем таймфрейме отсутствуют. Следует обратить внимание на инициализации переменных для минимального количества баров в блоке int init() для этого случая:

//---- Инициализация переменных            
   MinBarX_Up = 0;
   MinBar_Up = 4 + 3 * JXLength_Up + 30;
   MinBarN_Up = 0;

//---- Инициализация переменных
   MinBarX_Dn = 0;
   MinBar_Dn = 4 + 3 * JXLength_Dn + 30;
   MinBarN_Dn = 0;

На втором шаге из блоков «ОПРЕДЕЛЕНИЕ ТРЕНДА» убираем инициализации

TrendX_Up = 1;
TrendX_Dn =-1;

Дописываем ваш код для определения направления тренда в эти блоки и настраиваем эксперта ещё раз. Этот этап написания кода изображён в эксперте Exp_15_B.mq4. Следует не забыть сделать инициализацию переменных MinBarX_Up и MinBarX_Dn в блоке init():

//---- Инициализация переменных            
   MinBarX_Up = 2 + PeriodWATR_Up;
   MinBar_Up = 4 + 3 * JXLength_Up + 30;
   MinBarN_Up = 0;

//---- Инициализация переменных
   MinBarX_Dn = 2 + PeriodWATR_Dn;
   MinBar_Dn = 4 + 3 * JXLength_Dn + 30;
   MinBarN_Dn = 0;

В результате имеем эксперта, работающего на двух таймфреймах. На третьем шаге абсолютно аналогично достраиваем код эксперта в блоках «ОПРЕДЕЛЕНИЕ ШУМОВЫХ СИГНАЛОВ ДЛЯ ВХОДА В РЫНОК», предварительно убрав инициализации

Noise8uy_Sign = true;
NoiseSELL_Sign = true;

из этих блоков и дописав арифметические выражения для инициализации переменных для минимального количества баров в блоке int init() для этого случая:

//---- Инициализация переменных            
   MinBarX_Up = 2 + PeriodWATR_Up;
   MinBar_Up = 4 + 3 * JXLength_Up + 30;
   MinBarN_Up = 4 + Noise_period_Up + SmoothN_Up;

//---- Инициализация переменных
   MinBarX_Dn = 2 + PeriodWATR_Dn;
   MinBar_Dn = 4 + 3 * JXLength_Dn + 30;
   MinBarN_Dn = 4 + Noise_period_Dn + SmoothN_Dn;

Таким образом код эксперта оказался сделанным за три этапа. Если же пытаться строить такой код сразу за один этап, то в нём можно наделать ошибок, которые в дальнейшем будет весьма проблематично обнаружить!

 

Заключение

В данной статье я изложил свой вариант общего подхода к написанию экспертов с использованием трёх таймфреймов. Технически подобная затея достаточно легко реализуема средствами MQL4, вопрос в другом — «В плоскости каких решений подобная идея покажет свой определённый практический смысл?»

Прикрепленные файлы:
 EXPERTS.zip (20.4 Kb)
 INCLUDE.zip (34.7 Kb)
 indicators.zip (20.7 Kb)
 TESTER.zip (6.3 Kb)
Источник: mql4.com

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты