Файл Lite_EXPERT2.mqh - практические примеры реализации экспертов

Nikolay Kositsin | 21 июля, 2009


Введение

В своей предыдущей статье "Файл Lite_EXPERT2.mqh - функциональный конструктор экспертописателя" я познакомил читателей с функциями файла Lite_EXPERT2.mqh. В этой статье я приведу конкретные реализации экспертов на основе этих функций. Как я полагаю, торговые функции

OpenBuyOrder1_() 
OpenSellOrder1_() 
OpenBuyOrder2_() 
OpenSellOrder2_() 
OpenBuyLimitOrder1_() 
OpenBuyStopOrder1_() 
OpenSellLimitOrder1_() 
OpenSellStopOrder1_() 
Make_BuyTrailingStop_() 
Make_SellTrailingStop_()


каких-то серьёзных отличий в плане работы с ними от аналогичных функций файла Lite_EXPERT1.mqh не имеют. Инициализация пары лишних, внешних переменных, которые в них появились, никаких недоразумений не вызывает (см. Exp_0_1.mq4 и Exp_0.mq4, Exp_1.mq4 и EXP_1_1.mq4). Так что никакой необходимости в их повторном изучении нет абсолютно. И поэтому я сразу перейду к примерам, построенным на основе торговых функций с использованием в качестве внешних переменных для отложенных ордеров абсолютных значений уровней ценового графика.

ddOpenBuyOrder1_() 
dOpenSellOrder1_() 
dOpenBuyOrder2_() 
dOpenSellOrder2_() 
dOpenBuyLimitOrder1_() 
dOpenBuyStopOrder1_() 
dOpenSellLimitOrder1_() 
dOpenSellStopOrder1_() 
dModifyOpenBuyOrder_()
dModifyOpenSellOrder_()
dModifyOpenBuyOrderS()
dModifyOpenSellOrderS()
dMake_BuyTrailingStop_() 
dMake_SellTrailingStop_()

Торговые стратегии, которые будут рассмотрены в этой статье ниже, будут основаны на индикаторе Average True Range, так с него я и начну изложение данной статьи.

Использование индикатора Average True Range в механических торговых системах

Индикатор Average True Range (Далее ATR или Средний истинный диапазон) был разработан Уэллесом Уайлдером и впервые появился в его в книге - "Новые концепции в технических торговых системах" в 1978 году. Впоследствии этот индикатор стал достаточно популярным и на сей момент входит во многие пакеты программ технического анализа. Сам индикатор ATR направлений действующих трендов не указывает, а отображает в графическом виде волатильность или активность исследуемого рынка.

По большому счёту существует два варианта использования этого индикатора в механических торговых системах:

1. Фильтрация сигналов торговой системы на предмет идентификации трендового и нетрендового состояния рынка.

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

2. Адаптивные отложенные ордера.

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

Теперь можно приступать к построению экспертов с использованием файла Lite_EXPERT2.mqh. Лучше всего начать с модернизации экспертов, построенных на основе файла Lite_EXPERT1.mqh, с целью придания им большей гибкости в торговле.

Торговая система с использованием в качестве сигналов входа и выхода из рынка изменения направления мувинга

Такую систему я уже подробно рассматривал в своей статье "Эксперты на основе популярных торговых систем и алхимия оптимизации торгового робота", посвящённой простейшим торговым системам, теперь настало время к её усложнению. Почти полный аналог этой торговой системы на функциях файла Lite_EXPERT2.mqh сделан в эксперте Exp_1_1.mq4 (оригинал Exp_1.mq4). Вся задача состоит в том, чтобы сделать замену фиксированных стоплоссов и тейкпрофитов на пересчитываемые в единицах ATR и добавить аналогичные трейлинстопы, передвигаемые один раз на каждой смене бара. Лучше всего это выполнить за два этапа. Сначала заменить стоплосс и тейкпрофит (эксперт Exp_17_A.mq4), а после проверки кода на отсутствие ошибок и соответствие выбранной стратегии добавить трейлинстопы (эксперт Exp_17.mq4). Я в тексте статьи приведу лишь последний вариант с более детальными пояснениями добавленных изменений кода.

//+X================================================================X+
//|                                                       Exp_17.mq4 |
//|                             Copyright © 2009,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//+---------------------------------------------+
//| ВХОДНЫЕ ПАРАМЕТРЫ ЭКСПЕРТА ДЛЯ BUY СДЕЛОК   |
//+---------------------------------------------+
extern bool   Test_Up = true;//фильтр направления расчётов сделок
extern int    Timeframe_Up = 240;
extern double Money_Management_Up = 0.1;
extern int    Length_Up = 4;  // глубина сглаживания 
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    ATR_Period_Up = 14; // период усреднения True Range 
extern int    LevMinimum_Up = 40; // Минимальное значение в пунктах, ниже
                          // которого значения отложенных ордеров не опускаются
extern int    STOPLOSS_Up = 100;  // стоплосс в процентах ATR
extern int    TAKEPROFIT_Up = 200; // тейкпрофит в процентах ATR
extern int    TRAILINGSTOP_Up = 100; // трейлинстоп  в процентах ATR
extern bool   ClosePos_Up = true; // разрешение принудительного закрывания позиции
//+---------------------------------------------+
//| ВХОДНЫЕ ПАРАМЕТРЫ ЭКСПЕРТА ДЛЯ SELL СДЕЛОК  |
//+---------------------------------------------+
extern bool   Test_Dn = true;//фильтр направления расчётов сделок
extern int    Timeframe_Dn = 240;
extern double Money_Management_Dn = 0.1;
extern int    Length_Dn = 4;  // глубина сглаживания 
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    ATR_Period_Dn = 14; // период усреднения True Range
extern int    LevMinimum_Dn = 40; // Минимальное значение в пунктах, ниже
                          // которого значения отложенных ордеров не опускаются
extern int    STOPLOSS_Dn = 100;  // стоплосс в процентах ATR
extern int    TAKEPROFIT_Dn = 200; // тейкпрофит в процентах ATR
extern int    TRAILINGSTOP_Dn = 100; // трейлинстоп  в процентах ATR
extern bool   ClosePos_Dn = true; // разрешение принудительного закрывания позиции
//+---------------------------------------------+
//---- объявление целых переменных для минимума расчётных баров
int MinBar_Up, MinBar_Dn;
//---- объявление целых переменных для периодов графика в секундах
int Period_Up, Period_Dn;
//---- объявление переменных с плавающей точкой для отложенных ордеров
double _STOPLOSS_Up, _TAKEPROFIT_Up, _LevMinimum_Up, _TRAILINGSTOP_Up; 
double _STOPLOSS_Dn, _TAKEPROFIT_Dn, _LevMinimum_Dn, _TRAILINGSTOP_Dn; 
//+X================================================================X+
//| Custom Expert functions                                          |
//+X================================================================X+
#include <Lite_EXPERT2.mqh>
//+X================================================================X+
//| Custom Expert initialization function                            |
//+X================================================================X+
int init()
  {
//---- Проверка значения переменной Timeframe_Up на корректность
   TimeframeCheck("Timeframe_Up", Timeframe_Up);
//---- Проверка значения переменной Timeframe_Dn на корректность 
   TimeframeCheck("Timeframe_Dn", Timeframe_Dn);
//---- Инициализация переменных             
   MinBar_Up = 4 + 39 + 30;// четыре бара для сигналов 
                   //входа + длина фильтра FATL + длина фильтра JMA
   MinBar_Up = MathMax(MinBar_Up, ATR_Period_Up + 1);                 
   MinBar_Dn = 4 + 39 + 30;// четыре бара для сигналов 
                   //входа + длина фильтра FATL + длина фильтра JMA
   MinBar_Dn = MathMax(MinBar_Dn, ATR_Period_Dn + 1); 
//----  
   Period_Up = Timeframe_Up * 60; // период графика для лонгов в секундах 
   Period_Dn = Timeframe_Dn * 60; // период графика для шортов в секундах 
   
//---- Пересчёт процентов в дроби
   _STOPLOSS_Up = STOPLOSS_Up / 100.0;
   _TAKEPROFIT_Up = TAKEPROFIT_Up / 100.0;
   _TRAILINGSTOP_Up = TRAILINGSTOP_Up / 100.0;
//---- Пересчёт процентов в дроби
   _STOPLOSS_Dn = STOPLOSS_Dn / 100.0;
   _TAKEPROFIT_Dn = TAKEPROFIT_Dn / 100.0;
   _TRAILINGSTOP_Dn = TRAILINGSTOP_Dn / 100.0;
//---- Пересчёт минимума пунктов в минимум ценового расстояния
   _LevMinimum_Up = LevMinimum_Up * Point;
   _LevMinimum_Dn = LevMinimum_Dn * Point;                                
//---- завершение инициализации
   return(0);
  }
//+X================================================================X+
//| expert deinitialization function                                 |
//+X================================================================X+  
int deinit()
  {
//----+
   //----+ Удаление глобальных переменных 
                           //после тестирований и оптимизаций
   TimeLevelGlobalVariableDel(Symbol(), 1);
   TimeLevelGlobalVariableDel(Symbol(), 2);
   //---- Завершение деинициализации эксперта
   return(0);
//----+ 
  }
//+X================================================================X+
//| Custom Expert iteration function                                 |
//+X================================================================X+
int start()
  {
//----+
   //----+ Объявление локальных переменных
   int bar;
   double Mov[3], dMov12, dMov23, ATR, Level, open;
   //----+ Объявление статических переменных
   static datetime TradeTimeLevel_Up, TradeTimeLevel_Dn;
   //----
   static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop;
   static bool TrailSignal_Up, TrailSignal_Dn;
   //----
   static double dStopLoss_Up, dTakeProfit_Up, dTrailingStop_Up;
   static double dStopLoss_Dn, dTakeProfit_Dn, dTrailingStop_Dn;
   
   //+---------------------------+
   //| КОД ДЛЯ ДЛИННЫХ ПОЗИЦИЙ   |
   //+---------------------------+
   if (Test_Up) 
      if (MinBarCheck(Symbol(), Timeframe_Up, MinBar_Up))
       {
         if (IsNewBar(0, Symbol(), Timeframe_Up))
          {
           //----+ Обнуление торговых сигналов 
           BUY_Sign = false;
           BUY_Stop = false;
           //---- Получение предела времени на запрет 
                                         // следующей торговой операции
           TradeTimeLevel_Up = iTime(NULL, Timeframe_Up, 0);
           if (TradeTimeLevel_Up == 0)
            return(-1);
           TradeTimeLevel_Up += Period_Up;
                      
           //----+ ВЫЧИСЛЕНИЕ ИНДИКАТОРНЫХ ЗНАЧЕНИЙ И ЗАГРУЗКА ИХ В БУФЕРЫ        
           for(bar = 1; bar <= 3; bar++)
                     Mov[bar - 1]=                  
                         iCustom(NULL, Timeframe_Up, "JFatl", 
                                 Length_Up, Phase_Up, 0, IPC_Up, 0, bar);
           
           //----+ ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ СДЕЛОК 
           dMov12 = Mov[0] - Mov[1];
           dMov23 = Mov[1] - Mov[2]; 
           //---- Получение сигнала для открывания позиции                               
           if (dMov23 < 0)
              if (dMov12 > 0)
                        BUY_Sign = true;
           //---- Получение сигнала для закрывания позиции             
           if (dMov12 < 0)
              if (ClosePos_Up)
                        BUY_Stop = true; 
                        
           //----+ ВЫЧИСЛЕНИЕ ОТЛОЖЕННЫХ ОРДЕРОВ ДЛЯ ЛОНГОВ
           // Делаем расчёт ордеров только при наличии торгового сигнала
           if (BUY_Sign)
            {
             //---- Получение исходного значения ATR                                    
             ATR = iATR(NULL, Timeframe_Up, ATR_Period_Up, 1);
             //---- Получение текущей цены
             open = iOpen(Symbol(), Timeframe_Up, 0);
             
             //---- Вычисление расстояния до стоплосса
             Level = ATR * _STOPLOSS_Up;
             //---- Проверка расстояния до стоплосса на минимум
             if (Level < _LevMinimum_Up)
                     Level = _LevMinimum_Up;
             //---- Определение абсолютного значения стоплосса
             dStopLoss_Up = open - Level;
             
             //---- Вычисление расстояния до тейкпрофита
             Level = ATR * _TAKEPROFIT_Up;
             //---- Проверка расстояния до тейкпрофита на минимум
             if (Level < _LevMinimum_Up)
                     Level = _LevMinimum_Up;
             //---- Определение абсолютного значения тейкпрофита      
             dTakeProfit_Up = open + Level; 
             
             //---- Коррекция значений отложенных
                           // ордеров с учётом направления торговли
             dGhartVelueCorrect(OP_BUY, dStopLoss_Up);
             dGhartVelueCorrect(OP_BUY, dTakeProfit_Up);  
            } 
            
           //----+ ВЫЧИСЛЕНИЕ ТРЕЙЛИНСТОПОВ ДЛЯ ЛОНГОВ
           dTrailingStop_Up = 0;  
           TrailSignal_Up = false;
           //----
           if (TRAILINGSTOP_Up > 0)
            // Делаем расчёт трейлинстопа только, если есть необходимая позиция
            if (OrderSelect_(Symbol(), OP_BUY, 1, MODE_TRADES))
             // Двигаем трейлинстоп, если позиция открыта не на нулевом баре
             if (iBarShift(NULL, Timeframe_Up, OrderOpenTime(), false) > 0)
              {
               TrailSignal_Up = true;
               //---- Получение исходного значения ATR 
               ATR = iATR(NULL, Timeframe_Up, ATR_Period_Up, 1);
               //---- Получение текущей цены
               open = iOpen(Symbol(), Timeframe_Up, 0);
               //---- Вычисление расстояния до стоплосса
               Level = ATR * _TRAILINGSTOP_Up;
               //---- Проверка расстояния до стоплосса на минимум
               if (Level < _LevMinimum_Up)
                        Level = _LevMinimum_Up;
               //---- Получение абсолютного значения трейлинстопа          
               dTrailingStop_Up = open - Level;
               //---- Коррекция абсолютного значения трейлинстопа 
                        // с учётом направления торговли (для функций 
                           // модификации позиций значение переменной cmd обратное!)
               dGhartVelueCorrect(OP_SELL, dTrailingStop_Up);
              }                                     
          }
         
         //----+ СОВЕРШЕНИЕ СДЕЛОК
         if (!dOpenBuyOrder1_(BUY_Sign, 1, TradeTimeLevel_Up,
               Money_Management_Up, 5, dStopLoss_Up, dTakeProfit_Up))
                                                             return(-1);
         //----
         if (!CloseBuyOrder1_(BUY_Stop, 1))
                                      return(-1);                       
         //----                                 
         if (!dMake_BuyTrailingStop_(TrailSignal_Up, 1, 
                          TradeTimeLevel_Up, dTrailingStop_Up))
                                                       return(-1);
       }
   //+---------------------------+
   //| КОД ДЛЯ КОРОТКИХ ПОЗИЦИЙ  |
   //+---------------------------+
   if (Test_Dn) 
      if (MinBarCheck(Symbol(), Timeframe_Dn, MinBar_Dn))
       {
         if (IsNewBar(1, Symbol(), Timeframe_Dn))
          {
           //----+ Обнуление торговых сигналов 
           SELL_Sign = false;
           SELL_Stop = false;
           //---- Получение предела времени на запрет 
                                         // следующей торговой операции
           TradeTimeLevel_Dn = iTime(NULL, Timeframe_Dn, 0);
           if (TradeTimeLevel_Dn == 0)
            return(-1);
           TradeTimeLevel_Dn += Period_Dn;
                                 
           //----+ ВЫЧИСЛЕНИЕ ИНДИКАТОРНЫХ ЗНАЧЕНИЙ И ЗАГРУЗКА ИХ В БУФЕРЫ        
           for(bar = 1; bar <= 3; bar++)
                     Mov[bar - 1]=                  
                         iCustom(NULL, Timeframe_Dn, "JFatl", 
                                 Length_Dn, Phase_Dn, 0, IPC_Dn, 0, bar);
           
           //----+ ОПРЕДЕЛЕНИЕ СИГНАЛОВ ДЛЯ СДЕЛОК
           dMov12 = Mov[0] - Mov[1];
           dMov23 = Mov[1] - Mov[2]; 
           //---- Получение сигнала для открывания позиции                               
           if (dMov23 > 0)
              if (dMov12 < 0)
                       SELL_Sign = true;
           //---- Получение сигнала для закрывания позиции              
           if (dMov12 > 0)
               if (ClosePos_Dn)
                       SELL_Stop = true;
                       
           //----+ ВЫЧИСЛЕНИЕ ОТЛОЖЕННЫХ ОРДЕРОВ ДЛЯ ШОРТОВ
           // Делаем расчёт ордеров только при наличии торгового сигнала
           if (SELL_Sign)
            {                                   
             //---- Получение исходного значения ATR
             ATR = iATR(NULL, Timeframe_Dn, ATR_Period_Dn, 1);
             //---- Получение текущей цены
             open = iOpen(Symbol(), Timeframe_Dn, 0);
             
             //---- Вычисление расстояния до стоплосса
             Level = ATR * _STOPLOSS_Dn;
             //---- Проверка расстояния до стоплосса на минимум
             if (Level < _LevMinimum_Dn)
                     Level = _LevMinimum_Dn;
             //---- Определение абсолютного значения стоплосса
             dStopLoss_Dn = open + Level;
           
             //---- Вычисление расстояния до тейкпрофита
             Level = ATR * _TAKEPROFIT_Dn;
             //---- Проверка расстояния до тейкпрофита на минимум
             if (Level < _LevMinimum_Dn)
                     Level = _LevMinimum_Dn;
             //---- Определение абсолютного значения тейкпрофита          
             dTakeProfit_Dn = open - Level;   
             
             //---- Коррекция значений отложенных
                         // ордеров с учётом направления торговли
             dGhartVelueCorrect(OP_SELL, dStopLoss_Dn);     
             dGhartVelueCorrect(OP_SELL, dTakeProfit_Dn);
            }
           
           //----+ ВЫЧИСЛЕНИЕ ТРЕЙЛИНСТОПОВ ДЛЯ ШОРТОВ
           dTrailingStop_Dn = 0;
           TrailSignal_Dn = false;
           //----
           if (TRAILINGSTOP_Dn > 0)
            // Делаем расчёт трейлинстопа только, если есть необходимая позиция
            if (OrderSelect_(Symbol(), OP_SELL, 2, MODE_TRADES))
             // Двигаем трейлинстоп, если позиция открыта не на нулевом баре
             if (iBarShift(NULL, Timeframe_Dn, OrderOpenTime(), false) > 0) 
              {
               TrailSignal_Dn = true;
               //---- Получение исходного значения ATR 
               ATR = iATR(NULL, Timeframe_Dn, ATR_Period_Dn, 1);
               //---- Получение текущей цены
               open = iOpen(Symbol(), Timeframe_Dn, 0);
               //---- Вычисление расстояния до стоплосса
               Level = ATR * _TRAILINGSTOP_Dn;
               //---- Проверка расстояния до стоплосса на минимум
               if (Level < _LevMinimum_Dn)
                        Level = _LevMinimum_Dn;
               //---- Получение абсолютного значения трейлинстопа          
               dTrailingStop_Dn = open + Level;
               //---- Коррекция абсолютного значения трейлинстопа 
                        // с учётом направления торговли (для функций 
                           // модификации позиций значение переменной cmd обратное!)
               dGhartVelueCorrect(OP_BUY, dTrailingStop_Dn);
              }                                         
          }
         
         //----+ СОВЕРШЕНИЕ СДЕЛОК
         if (!dOpenSellOrder1_(SELL_Sign, 2, TradeTimeLevel_Dn,
               Money_Management_Dn, 5, dStopLoss_Dn, dTakeProfit_Dn))
                                                             return(-1);
         //----
         if (!CloseSellOrder1_(SELL_Stop, 2))
                                      return(-1);
         //----                                 
         if (!dMake_SellTrailingStop_(TrailSignal_Dn, 2, 
                          TradeTimeLevel_Dn, dTrailingStop_Dn))
                                                       return(-1);
       }
      
    return(0);
//----+
  }
//+X----------------------+ <<< The End >>> +-----------------------X+

Итак, в блоке внешних переменных эксперта появилась пара новых переменных - ATR_Period_Up и ATR_Period_Dn, посредством коих можно менять значения индикаторов ATR, которые используются для расчёта отложенных ордеров. Теперь в значения внешних переменных для стоплосса, тейкпрофита и трейлинстопа закладывается несколько иной логический смысл. Раньше это были относительные расстояния в пунктах от ордера и до текущей цены. Теперь это проценты от значения индикатора ATR на первом баре. То есть для вычисления ордера берутся проценты от индикатора ATR и добавляются к значению цены открывания нулевого бара. А стало быть, для пересчёта процентов в числа с плавающей точкой лучше всего использовать блок init() эксперта, где эти вычисления будут сделаны всего один раз, и посчитанные значения будут сохранены в переменных, объявленных на глобальном уровне.

В блоке init() изменились формулы для инициализации переменных LevMinimum_Up и LevMinimum_Dn по причине наличия нового индикатора ATR. В блоке start() эксперта появляются новые переменные, объявленные как статические, по причине того, что в них необходимо сохранять значения между тиками терминала. Код для вычисления отложенных ордеров и трейлинстопов скомпонован в виде небольших модулей внутри блоков для получения сигналов для сделок. Теперь для совершения сделок использованы другие функции, в которых для инициализации переменной Margin_Mode использована пятёрка, как более логичная, при плавающем стоплоссе.

Для демонстрации возможностей использования функций IndicatorCounted_() и ReSetAsIndexBuffer() в этом эксперте была сделана замена пользовательского индикатора JFatl.mq4 на функцию JFATL(), которая размещена внутри кода эксперта.

bool JFATL(int Number, string symbol, int timeframe,
               int Length, int Phase, int IPC, double& Buffer[])

Функция принимает входные параметры индикатора и массив Buffer[]. В случае успешного выполнения расчёта функция возвращает значение true, в противном случае false. Массив по ссылке превращается в аналог индикаторного буфера, который заполнен значениями индикатора JFATL. В функции сделана замена функции JJMASeries() на JJMASeries1(), которая не делает расчёт на нулевом баре. Также сделана замена функции PriceSeries() на iPriceSeries(). Блок инициализации индикатора помещён в блок "Инициализация нуля". Следует учесть, что в данном эксперте кроме этой функции функция JJMASeries1() нигде не используется, и поэтому значение переменной Number не пересчитывается и передаётся в функцию JJMASeries1() напрямую. То же самое касается и функции IndicatorCounted_().

О таких заменах индикаторов на функции я уже писал в своих статьях на эту тему 1, 2, 3. Эксперт с этой заменой представлен файлом Exp_17_.mq4. Следует отметить тот факт, что алгоритм JMA сглаживания, который использован в индикаторе JFatl.mq4 достаточно ресурсоёмкий, и подобная замена индикатора индикаторной функцией обеспечивает весьма существенное приращение скорости оптимизации этого эксперта по сравнению с предыдущим экземпляром. И наконец, для особо ленивых был сделан тот же самый эксперт(Exp_17R.mq4), в котором все необходимые функции были размещены внутри экспертного кода, и который для компиляции и своей работы не требует никаких дополнительных инклюдников и индикаторов. Все три аналога этого эксперта работают абсолютно идентично! Разве что в последнем эксперте значения переменных IPC_Up и IPC_Dn могут меняться в несколько меньших размерах (0-10), по причине отсутствия обращений к индикатору Heiken Ashi#.mq4.

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

Пробойная система для торговли на новостях

Этот вариант торговой системы был уже представлен для просмотра в моей статье экспертом Exp_10.mq4. Вариант эксперта Exp_10_1.mq4, выполненный на функциях Lite_EXPERT2.mqh является его полным аналогом. Он оказывается немного сложнее первоначального варианта, но зато значительно надёжнее в работе, будучи абсолютно безразличным к перезагрузкам эксперта, терминала или операционной системы. В этом эксперте для определения момента времени, после которого следует закрыть открытую позицию, используется функция TradeTimeLevelCheck():

bool TradeTimeLevelCheck
             (string symbol, int MagicNumber, datetime TradeTimeLevel)

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

Теперь предстоит выполнение той же самой задачи изменения алгоритма расчёта отложенных ордеров. Но в данной ситуации следует сделать динамически пересчитываемыми не только стоплосс и тейкпрофит, но и отложенные стоп-ордера. Что, в общем-то, абсолютно ничего не меняет, и всё делается абсолютно аналогично. Вдобавок, в исходном эксперте трейлинстоп работает на каждом тике, а задача ставится делать его перестановку на каждой смене бара. Конечно итоговый код эксперта (Exp_18.mq4) оказывается уже не таким простым, как первоначальный, но сама логика развития мысли в программном коде получается достаточно лаконичной и понятной. Файл Exp_18R.mq4 - это полный аналог последнего эксперта, выполненный в виде законченного, самодостаточного файла.

Заключение

Я полагаю, что ничего нового, с точки зрения самого подхода программирования, пользовательские функции файла Lite_EXPERT2.mqh по сравнению с функциями файла Lite_EXPERT1.mqh не представляют. Только расширение возможностей программирования. А сама суть применения этих функций остаётся прежней. Так что для того, кто внимательно разобрался с применением функций файла Lite_EXPERT1.mqh, никакого труда не составит достаточно легко и быстро освоить функциональные возможности файла Lite_EXPERT2.mqh.