тел.: 8 800 200 86 47|+7 (812) 336 61 11Заказать звонок
Admiral Markets UK Admiral Markets UK Choose your country

MQLabs: Отбой волатильности. Часть 2.

Советник VolatilityBounce_Simple

Индикатор VolatilityBounce_Simple

Файлы стратегий для AutoGraf 4.0

Развернутые результаты тестирования эксперта

 

В первой части исследования стратегия "Отбой волатильности" рассматривалась в качестве торговой системы, определяющей точки разворота тренда. Хотя точнее будет сказать, что таковой она получилась в результате подбора оптимальных параметров. Изначальная же идея заключалась в использовании коррекционной природы рынка. Это свойство проявляется, когда после каждого резкого движения рынок как бы набирается сил для продолжения начатого. В такие моменты противоположное движение дает возможность с высокой степенью вероятности получить небольшую прибыль.

Для осуществления задуманного нам потребуются следующие признаки:

  1. Определение резкого движения рынка.

  2. Определение момента начала коррекции.

  3. Определение момента завершения коррекции.

Естественно, точное определение каждого из перечисленных событий невозможно. Но те случаи, когда это удастся, будут не так уж и редки.

По первому и второму пунктам решение уже имеется. Оно было представлено в первой части материала. Правда, это решение было рассчитано на определение точек разворота тренда. А сейчас мы говорим лишь об определении коррекции. С этой целью предложенное решение нужно упростить (см. рис. 1).

Рис. 1. Резкое движение, коррекция и окончание коррекции.

Вспомним, что резким движением в первой части исследования считался рост единичной волатильности (красная линия индикатора VolatilityBounce_Simple) выше среднего значения волатильности (голубая линия индикатора). Было использовано еще несколько признаков, появление которых одновременно являлось подтверждением резкого движения, а именно: свеча должна являться экстремумом (ранг экстремума определяется пользователем), цена закрытия свечи должна находиться в верхней половине (если свеча бычья) или в нижней половине (если свеча медвежья) бара, противоположный край свечи должен быть выше (свеча бычья) или ниже (свеча медвежья) аналогичного края предыдущей свечи. Из перечисленного набора признаков для текущего исследования оставим только рост волатильности выше среднего уровня. Для возможных экспериментов также оставим в индикаторе возможность указания ранга экстремума (параметр Range). Остальные признаки отбросим.

В результате принятых упрощений индикатор стал намного чаще подавать сигналы открытия сделок. Теперь нужно наиболее рационально воспользоваться полученными сигналами. Основное требование - успеть закрыть сделку с прибылью до окончания коррекции.

На рис. 1 первые два резких движения сами оказались коррекциями, а указанные направления движения - основным движением рынка. Несмотря на это, стратегия будет считать сигнал коррекционным, и пытаться закрыть сделку при первых же признаках окончания коррекции. Таким признаком (пункт №3 - см. выше) является возврат единичной волатильности ниже среднего уровня (красная линия становится ниже голубой).

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

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

В качестве трендовой системы возьмем наиболее простую стратегию - пересечение цены закрытия свечи со средней скользящей линией. В итоге окончательный алгоритм стратегии будет выглядеть так (см. рис. 2):

Рис. 2. Открытие трендовых и коррекционных сделок.

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

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

Рассмотрим, каким образом стратегия реализуется  в виде программы (советник VolatilityBounce_Simple). Мозгом эксперта является функция генерации сигналов открытия и закрытия сделок GetSignal:

 
//+-------------------------------------------------------------------------------------+
 //| Генерация сигналов покупки и продажи                                                |
 //+-------------------------------------------------------------------------------------+
 void GetSignal()
 {
  Signal = 0;
  
 // - 1 - ============ Определение значений средней и единичной волатильностей ===========
  double ATR1 = iATR(NULL, 0, ATRPeriod, 1);           // Последнее известное значение АТR
  double ATR2 = iATR(NULL, 0, ATRPeriod, 2);       // Предпоследнее известное значение ATR
  double ATR3 = iATR(NULL, 0, ATRPeriod, 3);    //Предпредпоследнее известное значение ATR
  double Curr1 = High[1] - Low[1];                           // Волатильность первой свечи
  double Curr2 = High[2] - Low[2];                           // Волатильность второй свечи
  double Curr3 = High[3] - Low[3];                          // Волатильность третьей свечи
  double MA = iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, 1);//Значение трендовой средней
 // - 1 - ========================== Окончание блока =====================================
 
  if (Curr1 > ATR1 && Curr2 < ATR2 && Curr3 <= ATR3)//Единичная волатильность стала больше
    {                          // средней волатильности после двух подряд меньших значений
 // - 2 - ================ Генерация сигнала покупки по волатильности ====================
     if (Open[1] > Close[1])                                             // свеча медвежья
       if (iLowest(NULL, 0, MODE_LOW, Range, 1) == 1)         // Свеча - локальный минимум 
         {
          Signal += 12;                                 // Сигнал покупки по волатильности
          BegSL = Open[0] - ATR1;                                          // Расчет стопа
          BegTP = High[1];                                               // Расчет профита
         } 
 // - 2 - ========================== Окончание блока =====================================
 
 // - 3 - =================== Генерация сигнала продажи по волатильности =================
     if (Open[1] < Close[1])                                                // свеча бычья
       if (iHighest(NULL, 0, MODE_HIGH, Range, 1) == 1)      // Свеча - локальный максимум
         {
          Signal -= 12;                                 // Сигнал продажи по волатильности
          BegSL = Open[0] + ATR1 + Spread;                                 // Расчет стопа
          BegTP = Low[1] + Spread;                                       // Расчет профита
         } 
 // - 3 - ========================== Окончание блока =====================================
    }
    
 // - 4 - =================== Генерация сигнала покупки по тренду ========================
  if (Close[1] > MA)                     // Закрытие свечи выше средней - восходящий тренд
    {
     Signal++;                         
     if (Curr1 < ATR1)// Если волатильность ниже среднего, то генерируется сигнал закрытия
       Signal += 20;                           // короткой позиции, открытой против тренда
    } 
 // - 4 - ========================== Окончание блока =====================================
 
 // - 5 - =================== Генерация сигнала продажи по тренду ========================
  if (Close[1] < MA)                     // Закрытие свечи ниже средней - нисходящий тренд
    {
     Signal--;  
     if (Curr1 < ATR1)// Если волатильность ниже среднего, то генерируется сигнал закрытия
       Signal -= 20;                            // длинной позиции, открытой против тренда
    } 
 // - 5 - ========================== Окончание блока =====================================
 }

Первый блок собирает информацию о значении индикаторов ATR и MA. Используя значения ATR, можно вычислить значения линий индикатора VolatilityBounce_Simple. Значение МА необходимо для определения направления тренда. ATRPeriod, MAPeriod, MAMethod и MAPrice - настроечные параметры эксперта, при помощи которых пользователь имеет возможность изменять поведение стратегии без необходимости внесения изменений в код программы.

Второй и третий блоки очень похожи на соответствующие блоки функции GetSignal советника VolatilityBounce (первая часть материала). В них генерируются сигналы покупки и продажи на основании определения начала коррекции после резкого движения рынка. В случае наличия сигнала открытия длинной сделки значение переменной Signal увеличивается на 12, а в случае наличия сигнала продажи - уменьшается на 12. Такой метод генерации сигнала выбран по той причине, что одновременно может быть активно два сигнала (коррекционный и трендовый), а решение о том, какому из них отдавать предпочтение, принимается на основании существующих сделок. Доступа к списку сделок у функции GetSignal нет, т.к. это не является областью ее ответственности. 

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

По окончании функции GetSignal значение переменной Signal может быть одним из следующих:

  1. Signal = 0. Очень редкий случай, означающий равенство цены закрытия свечи и средней скользящей, а также отсутствие коррекционного сигнала.

  2. Signal = 1. Восходящий тренд. Открывается длинная трендовая сделка, а короткая закрывается, или ничего не предпринимается, если длинная сделка уже открыта.

  3. Signal = -1. Нисходящий тренд.  Открывается короткая трендовая сделка, а длинная закрывается, или ничего не предпринимается, если короткая сделка уже открыта.

  4. Signal = 11 (12 - 1). Коррекция в нисходящем тренде. Закрывается текущая короткая трендовая и открывается длинная коррекционная сделка.

  5. Signal = -11 (-12 + 1). Коррекция в восходящем тренде. Закрывается текущая длинная трендовая и открывается короткая коррекционная сделка.

  6. Signal = 12. Редкий случай. Трендового сигнала нет, но есть сигнал открытия коррекционной длинной сделки. Открытие длинной коррекционной сделки с закрытием любой короткой.

  7. Signal = -12. Редкий случай. Трендового сигнала нет, но есть сигнал открытия коррекционной короткой сделки. Открытие короткой коррекционной сделки с закрытием любой длинной.

  8. Signal = 13 (12 + 1). Сигнал восходящего тренда и его коррекции (звучит глупо, но в данном случае нужно понимать, что система несовершенна и может допускать такие взаимоисключающие сигналы). Трактуется как открытие длинной коррекционной сделки, если длинной до сих пор нет. В противном случае не предпринимается никаких действий.

  9. Signal = -13 (-12 - 1). Сигнал нисходящего тренда и его коррекции. Открывается короткая коррекционная сделка.

  10. Signal = 21 (1 + 20). Сигнал окончания коррекции в восходящем тренде. Закрывается короткая коррекционная и открывается длинная трендовая сделка.

  11. Signal = -21 (-1 - 20). Сигнал окончания коррекции в нисходящем тренде. Закрывается длинная коррекционная и открывается короткая трендовая сделка.

Как видно, случаев комбинации трех сигналов (открытие трендовой сделки, открытие и закрытие коррекционной сделки) одновременно нет. Это объясняется тем, что не могут одновременно существовать сигналы открытия и закрытия коррекционных сделок.

Обработка значения переменной Signal с совершением соответствующих действий производится функцией Trade:

 
//+-------------------------------------------------------------------------------------+
 //| Открытие позиций                                                                    |
 //+-------------------------------------------------------------------------------------+
 bool Trade()
 {
 // - 1 - ==================== Открытие длинной позиции ==================================
  if (Signal > 0)
    {
     int Res = CheckOrders(OP_SELL);     // Закрытие коротких сделок, если таковые имеются
     if (Res == 0)     // Сделок, открытых по текущему сигналу, нет, можно открывать новую
       {
        RefreshRates();
        int MN = 0;                           // По умолчанию открывается трендовая сделка
        double SL = Bid - SLFactor*iATR(NULL, 0, ATRPeriod, 1);     // "Пожарный" стоп для
                                                                       // трендовой сделки
        double TP = 0; // Профит трендовой сделке не нужен - закрытие по обратному сигналу
        if (Signal > 10 && Signal < 20)      // Если имеется сигнал по отбою волатильности
          {
           MN = 1;                                                // Контртрендовая сделка
           SL = BegSL;                                     // Стоп для контрендовой сделки
           TP = BegTP;                                   // Профит для контрендовой сделки
          }
        if (OpenOrderCorrect(OP_BUY, Lots, NP(Ask), NP(SL), NP(TP), MN) != 0)
          return(False);                    
       }   
     if (Res == 1) return(False);//Существует короткая позиция, которую закрыть не удалось
    }       
 // - 1 - ==================== Окончание блока ===========================================
            
 // - 2 - ==================== Открытие короткой позиции =================================
  if (Signal < 0)
    {
     Res = CheckOrders(OP_BUY);           // Закрытие длинных сделок, если таковые имеются
     if (Res == 0)     // Сделок, открытых по текущему сигналу, нет, можно открывать новую
       { 
        RefreshRates();
        MN = 0;                               // По умолчанию открывается трендовая сделка
        SL = Ask + SLFactor*iATR(NULL, 0, ATRPeriod, 1);            // "Пожарный" стоп для
                                                                       // трендовой сделки
        TP = 0;        // Профит трендовой сделке не нужен - закрытие по обратному сигналу
        if (Signal < -10 && Signal  > -20)   // Если имеется сигнал по отбою волатильности
          {
           MN = 1;                                                // Контртрендовая сделка
           SL = BegSL;                                     // Стоп для контрендовой сделки
           TP = BegTP;                                   // Профит для контрендовой сделки
          } 
        if (OpenOrderCorrect(OP_SELL, Lots, NP(Bid), NP(SL), NP(TP), MN) != 0)
          return(False);                   
       }   
     if (Res == 1) return(False);// Существует длинная позиция, которую закрыть не удалось
    }       
 // - 2 - ==================== Окончание блока ===========================================
  
  return(True);    
 }

Каждый из двух блоков функции обрабатывает свою ситуацию. Блок 1 обрабатывает положительные значения переменной Signal, что приводит к закрытию короткой сделки и открытию длинной. Блок 2 работает при отрицательном значении Signal. В этом случае закрывается длинная сделка и открывается короткая.

Трендовая и коррекционная сделки различаются экспертом по полю MagicNumber. То значение MagicNumber, которое пользователь указывает в настроечных параметрах, принимается в качестве базы и умножается на 10. Если сделка трендовая, то к полученному значению ничего не добавляется. Если же сделка коррекционная, то добавляется 1. По этой причине функции OpenOrderCorrect передается значение переменной MN, которая принимает значение 0 или 1 в зависимости от вида сделки.

Уровни стоп-приказа и профита у трендовой и коррекционной сделок также отличаются. У трендовой сделки нет профита, а стоп-приказ устанавливается на расстоянии нескольких средних волатильностей от цены открытия сделки. Множитель волатильности пользователь может изменять, регулируя значение параметра SLFactor. Как показывает практика, трендовые сделки очень редко достигают стопа, закрываясь по обратному сигналу. Поэтому можно говорить, что стоп-приказ трендовой сделки выполняет функцию защиты от непредвиденных обстоятельств.

Коррекционная сделка обладает как профитом, так и уровнем стоп-приказа. Уровень стоп-приказа устанавливается на расстоянии волатильности предыдущей свечи от цены открытия текущей свечи (BegSL). Уровень профита ставится на противоположном экстремуме сигнальной свечи (BegTP).

Перед совершением операции открытия сделки в обоих блоках проверяется наличие противоположной сделки. Это производится путем вызова функции CheckOrders. Функция возвращает результат 0, если можно открывать сделку (нет текущих сделок). Результат 1 означает, что была найдена противоположная открытию сделка и попытка закрытия оказалась неудачной. В случае возврата результата 2 новая сделка открыта не будет, т.к. была найдена подобная сделка или противоположную сделку закрывать еще нельзя (случаи существования коррекционной сделки в тренде). Таким образом, если функция CheckOrders вернула 2, то блок открытия сделки не будет выполнен, а функция Trade вернет значение true, что приведет к отсутствию вызовов функции до начала следующего бара.

Рассмотрим функцию CheckOrders:

 
//+-------------------------------------------------------------------------------------+
 //| Поиск своих ордеров. Возвращает:                                                    |
 //|    0 - Своих позиций нет. Можно открывать новую позицию                             |
 //|    1 - Не удалось закрыть указанную позицию. Требуется еще попытка                  |
 //|    2 - Существует противоположная указанной позиция, открытая по последнему сигналу |
 //+-------------------------------------------------------------------------------------+
 int CheckOrders(int Type)                    // Type - Тип позиции, которую нужно закрыть
 {             
  int total = OrdersTotal()-1;                               
  for (int i = total; i >= 0; i--)                     // Используется весь список ордеров
    if (OrderSelect(i, SELECT_BY_POS))                       // Убедимся, что ордер выбран
      if (MathFloor(OrderMagicNumber()/10) == MagicNumber &&    // Ордер открыт экспертом,
          OrderSymbol() == Symbol())         // который прикреплен к текущей валютной паре
        if (OrderType() == Type)                        // Если тип ордера равен заданному
          {
           int ID = MathMod(OrderMagicNumber(), 10);
           if (ID == 1 && MathAbs(Signal) < 20)              // Ордер открыт по сигналу от
                                        // волатильности, а волатильность остается высокой
             return(2);                                    // Такой ордер закрывать нельзя
           if (WaitForTradeContext())                       // Свободен ли торговый поток?
             {
              if (Type == OP_BUY)                  // Если следует закрыть длинную сделку,
                double Price = MarketInfo(Symbol(), MODE_BID);  // то применяется цена BID
               else                               // Если следует закрыть короткую сделку,
                Price = MarketInfo(Symbol(), MODE_ASK);         // то применяется цена ASK
              if (!OrderClose(OrderTicket(), OrderLots(), NP(Price), 3)) // Если сделку не 
                return(1);                    // удалось закрыть, то результат функции - 1
             }
          }                          
         else                       // найден противоположный параметру Type по типу ордер
          return(2);                        // открывать новую сделку нельзя - результат 2
  
  return(0);                                                     // Можно открывать сделку
 }

Для определения факта принадлежности выбранного ордера к числу ордеров, открытых экспертом, его MagicNumber делится на 10 без остатка и сравнивается со значением настроечного параметра MagicNumber. Если ордер распознан как "свой", то проверяется равенство его типа значению переменной Type, являющейся единственным аргументом функции CheckOrders. Неравенство типов означает присутствие противоположной значению Type позиции, что приводит к завершению функции CheckOrders и возврату значения 2.

При равенстве типов определяется тип сигнала, по которому открыта сделка (трендовая или коррекционная). Для этого MagicNumber ордера делится на 10 и фиксируется остаток от деления. Остатку 0 соответствует трендовая сделка, а 1 - коррекционная. Если сделка коррекционная, а значение переменной Signal по модулю меньше 20 (нет сигнала закрытия коррекционной сделки), то функция CheckOrders мгновенно прекращает свое выполнение и возвращает результат 2. Во всех остальных случаях найденная сделка закрывается. При удачном закрытии функция CheckOrders возвращает результат 0, при неудачном - 1.

 

Тестирование советника

При тестировании советника VolatilityBounce_Simple оказалось, что он описывает закономерности, присущие только одной валютной паре - EURUSD. Для остальных мажоров (USDCHF, GBPUSD и USDJPY) не удалось подобрать параметры, позволяющие получить прибыль. Хорошей новостью является то, что для EURUSD не пришлось проводить оптимизацию - хорошие результаты были показаны с параметрами, используемыми экспертом по умолчанию.

Исторический период тестирования: 01.01.2009 - 18.12.2010. Таймфрейм стандартный -  Н1. Результаты показаны на рис. 3.

 

 

                Рис. 3. Результаты тестирования эксперта VolatilityBounce_Simple на валютной паре EURUSD.

Результаты получились, как никогда, хорошие. Кривая баланса, несмотря на периоды застоя, уверенно движется вверх. Эта уверенность подкрепляется огромным (если судить по предыдущим опытам) количеством сделок - 2 495 (рекорд MQLabs). Если посчитать среднее количество сделок в неделю, то получим значение 24.46. Это почти пять сделок в сутки. При такой активной торговле стратегии удается показывать прибыль. В цифрах результаты характеризуются так: чистая прибыль 5 215 долларов, максимальная просадка 1 156 долларов, фактор восстановления 4.51. К недостаткам статистических показателей в данном случае можно отнести показатель максимального количества убыточных сделок подряд - 22. В денежном эквиваленте это составляет 388 долларов.

"Плюсами" статистических показателей стратегии являются: максимальная прибыльная сделка (310 долларов), которая значительно превосходит максимальную убыточную (165 долларов), и средняя прибыльная сделка (40 долларов), которая превосходит среднюю убыточную сделку (26 долларов).

 

 Доработка стратегии для использования в AutoGraf 4.0

Стратегия VolatilityBounce_Simple для приложения AutoGraf располагает шестью настроечными параметрами, которые соответствуют входным параметрам эксперта следующим образом: ATRPeriod - AT_1, Range - AT_2, MAPeriod - AT_3, MAMethod - AT_4, MAPrice - AT_5, SLFactor - AT_6.

Необходимости установки соответствия для параметра эксперта Lots нет, т.к. объем сделок можно настраивать во время исполнения стратегии при помощи панели настроек AutoGraf (значения под надписью Lot).

Запуск стратегии VolatilityBounce_Simple в среде AutoGraf 4.0 состоит из следующих шагов:

  • Получить файл по ссылке Файлы стратегий для AutoGraf 4.0 и распаковать полученный архив в папку MT4\experts\libraries (с перезаписью файлов AG_AT.ex4 и AG_AT.mq4).

  • Запустить AutoGraf (прикрепить индикатор AG_ind, а затем эксперт AG_exp).

  • Для работы стратегии в ключе приведенных результатов в окне настроек AutoGraf (закладка "Входные параметры") установить нужные значения параметров AT_1 - AT_6. Полное повторение результатов при этом не гарантируется.

  • Выбрать стратегию №5. Для этого необходимо передвинуть вверх значок So и среди названий стратегий найти значок S5, который также потянуть вверх.

  • Запустить функцию автоматической торговли, передвинув значок AT в верхнее положение.

 Использование полученного советника рекомендуется только в полуавтоматическом режиме под присмотром трейдера и после всестороннего изучения слабых и сильных сторон стратегии.

 

Игорь Герасько

Декабрь 2010

Специально для компании Admiral Markets

2.75
 
 
X
Loading