Советник SARPlusAlligator

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

 

    "A trend is your friend" ("Тренд - твой друг"). С этой поговоркой трудно поспорить. Где еще, как не в трендах, делают состояния? При каких иных обстоятельствах на рынке можно в считанные минуты стать миллионером или нищим? Ведь любой тренд сопровождается всплеском эмоций, спектр которых протягивается от безумного страха до неуемной жадности. Поэтому многие трейдеры относятся к тренду, как к божеству - его и боятся, и ждут одновременно.

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

    Итак, какой инструмент лучше всего характеризует тренд? Безусловно, набор средних скользящих. Какой набор средних скользящих является классическим? "Самым классическим" является набор двух средних, на основании которых создан индикатор MACD. Но с другой стороны, две средние на "набор" не тянут. Требуется хотя бы три средние. И здесь мы располагаем классикой - индикатор из системы Билла Вильямса Аллигатор.

    Но, как любой индикатив, индикатор Аллигатор имеет свои недостатки, которые приводят к частым ложным сигналам. В свою очередь, такие сигналы довольно дорого (в буквальном смысле) обходятся трейдеру. Одним из решений этой проблемы является дополнение системы фильтром. Им может быть что угодно - еще один индикатор, ограничение работы по времени, расчет уровней поддержки и сопротивления. В данном случае стоит остановиться на еще одном трендовом индикаторе. Речь идет о параболике - Parabolic SAR. Чем он нам поможет? Это мы увидим уже в полном описании торговой системы.

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

    Для совершения коротких сделок, ждем первого сигнала от параболика. Его точки должны переместиться в область над ценой, что дает нам сигнал закрытия длинных сделок. Далее ждем, когда линия губ Аллигатора окажется ниже линии зубов, а линия зубов - ниже линии челюстей. Вновь проверяем, находятся ли точки параболика над линией челюстей Аллигатора, а цена открытия свечи - под линией губ. Только при выполнении этих условий можно открывать короткую сделку.

    Описанный принцип проиллюстрирован на рис. 1, где зеленая линия - линия губ Аллигатора, красная - линия зубов, а синяя - линия челюстей. Черные точки - это параболик. На рис. 1 очень хорошо видно, как индикаторы фильтруют сигналы друг друга, не позволяя реагировать на поздние или просто ложные сигналы.

    

Рис. 1. - Совершение сделок по стратегии "Ловец трендов".

    Особых отличий от "стандартной схемы" в стратегии нет. Поэтому данный советник от предыдущих будет отличаться лишь сигнальной частью. Сигналов снова выходит пять:

  •     0 - нет сигнала

  •     1 - сигнал покупки

  •     2 - сигнал продажи

  •     3 - сигнал закрытия длинных сделок

  •     4 - сигнал закрытия коротких сделок

    В результате, знакомая функция GetSignal принимает вид:

 
//+-------------------------------------------------------------------------------------+
//| Расчет значений параболика и Аллигатора с формированием сигналов для позиций        |
//+-------------------------------------------------------------------------------------+
void GetSignal()
{
 Signal = 0;
// - 1 - == Получение значений индикаторов ==============================================
 double SAR = iSAR(Symbol(), 0, SARStep, SARMaximum, 0);
 double Jaw = iAlligator(Symbol(), 0, JawPeriod, JawShift, TeethPeriod, TeethShift, 
                         LipsPeriod, LipsShift, AlligatorMethod, AlligatorPrice, 
                         MODE_GATORJAW, 0);
 double Teeth = iAlligator(Symbol(), 0, JawPeriod, JawShift, TeethPeriod, TeethShift, 
                           LipsPeriod, LipsShift, AlligatorMethod, AlligatorPrice, 
                           MODE_GATORTEETH, 0);
 double Lips = iAlligator(Symbol(), 0, JawPeriod, JawShift, TeethPeriod, TeethShift, 
                          LipsPeriod, LipsShift, AlligatorMethod, AlligatorPrice, 
                          MODE_GATORLIPS, 0);
// - 1 - == Окончание блока =============================================================

// - 2 - == Генерация сигнала ===========================================================
 if (SAR < Low[1])                                                 // Параболик под ценой
   {
    Signal = 3;                                                          // Закрытие SELL
    if (SAR < Jaw && Open[0] > Lips && Jaw < Teeth && Teeth < Lips)     // Параболик ниже
                                              // Аллигатора, а цена открытия свечи - выше
      Signal = 1;                                                         // Открытие BUY
   }   
 
 if (SAR > High[1])                                                // Параболик над ценой
   {
    Signal = 4;                                                           // Закрытие BUY
    if (SAR > Jaw && Open[0] < Lips && Lips < Teeth && Teeth < Jaw)     // Параболик выше
                                              // Аллигатора, а цена открытия свечи - ниже
      Signal = 2;
   }   
// - 2 - == Окончание блока =============================================================
}

    Бросается в глаза расчет значений индикаторов на нулевом баре (см. блок 1). Обычно подобное не приветствуется, так как невозможно точно смоделировать поведение цен "внутри бара". Но все дело в том, что эти значения будут рассчитываться лишь для момента открытия нового бара. Все последующие значения, которые можно рассчитать за время формирования бара, учитываться не будут, так как функция GetSignal будет выполняться всего один раз на один бар - при его открытии.

    Во втором блоке генерация сигналов "закрытие Sell" и "открытие Buy" происходит вложено, как это и предписано стратегией. Если значение параболика ниже минимума предыдущей свечи, то это в любом случае сигнал "закрытие Sell" (переменная Signal принимает значение 3). И в то же время это условие является частью сигнала "открытие Buy", которое подтверждается, когда параболик оказывается ниже линии челюстей (переменная Jaw), а остальные линии Аллигатора выстраиваются в движении наверх (линии малого периода выше линий большего периода).

     Такая же вложенность наблюдается у сигналов "закрытие Buy" и "открытие Sell". Если значение параболика выше максимума предыдущей свечи, то это сигнал "закрытие Buy" (переменная Signal принимает значение 4). Переход сигнала "закрытие Buy" в сигнал "открытие Sell" происходит, когда параболик становится выше линии челюстей Аллигатора, а линии Аллигатора выстраиваются в движении вниз.

      Вложенная обработка сигналов находит свое продолжение и в функции start:

 
//+-------------------------------------------------------------------------------------+
//| Функция START эксперта                                                              |
//+-------------------------------------------------------------------------------------+
int start()
  {
// - 1 -  == Разрешено ли советнику работать? ===========================================
   if (!Activate || FatalError)             // Отключается работа советника, если функция
    return(0);           //  init завершилась с ошибкой  или имела место фатальная ошибка
// - 1 -  == Окончание блока ============================================================
     
// - 2 - == Сбор информации об условиях торговли ========================================
   Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point);                  // текщий спрэд
   StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point);  // текущий уровень стопов 
// - 2 -  == Окончание блока ============================================================
   
   if (LastBar == Time[0])
     return(0);
   
// - 3 - == Расчет последних трех экстремумов ЗЗ ========================================
   GetSignal();
// - 3 -  == Окончание блока ============================================================

// - 4 - == Установка ордеров ===========================================================
   if (Signal == 1 || Signal == 3)                      // Открытие BUY или закрытие SELL
     {
      int Res = CheckOrdersReal(OP_SELL);   // Закрытие SELL и проверка существования BUY
      if (Res == 0 && Signal == 1)// Открытие BUY только при условии успешного выполнения
        {                       // функции CheckOrdersReal и наличия сигнала открытия BUY
         RefreshRates();
         double SL = ND(IF(StopLoss == 0, 0, Ask - StopLoss*Tick));               
         double TP = ND(IF(TakeProfit == 0, 0, Ask + TakeProfit*Tick));
         if (OpenOrderCorrect(OP_BUY, ND(Ask), SL, TP, True) != 0)    // открытие позиции
           return(0); // если не удалось открыть, то попытка переносится на следующий тик
        }
      if (Res == 1) return(0);//если не удалось закрыть SELL, то сделаем это на следующем
                                                                                  // тике
     }

   if (Signal == 2 || Signal == 4)                      // Открытие SELL или закрытие BUY
     {
      Res = CheckOrdersReal(OP_BUY);        // Закрытие BUY и проверка существования SELL
      if (Res == 0 && Signal == 2)//Открытие SELL только при условии успешного выполнения
        {                      // функции CheckOrdersReal и наличия сигнала открытия SELL
         RefreshRates();
         SL = ND(IF(StopLoss == 0, 0, Bid + StopLoss*Tick));               
         TP = ND(IF(TakeProfit == 0, 0, Bid - TakeProfit*Tick));
         if (OpenOrderCorrect(OP_SELL, ND(Bid), SL, TP, True) != 0)   // открытие позиции
           return(0); // если не удалось открыть, то попытка переносится на следующий тик
        }
      if (Res == 1) return(0);//если не удалось закрыть SELL, то сделаем это на следующем
                                                                                  // тике  
     }   
// - 4 -  == Окончание блока ============================================================
   LastBar = Time[0];

   return(0);
  }

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

    Также стоит обратить внимание на принцип отработки новой свечи. Он, конечно, довольно банальный - сохранение времени открытия самой последней свечи в переменной LastBar. Но здесь учитываются случаи, когда советнику не удалось в течение одного тика совершить операции закрытия старой сделки и открытия новой. Для этого и проверяются результаты вызова функций OpenOrderCorrect и CheckOrdersReal. Если хотя бы одна из этих функций завершилась неудачно, то выполнение до предпоследней строки функции start так и не дойдет. В итоге в переменной LastBar останется значение времени открытия предыдущей свечи, что позволит выполнить все действия по открытию и закрытию сделок.

   Основные функции советника описаны и он готов к работе, как в тестере, так и онлайн. Но перед реальным использованием стоит протестировать стратегию и увидеть ее слабые места.

   Эксперт SARPlusAlligator протестируем на промежутке 01.01.2008 - 19.09.2009, таймфрейм H1, значения входных параметров - по умолчанию. Результаты приведены на рис. 2 - 5.

Рис. 2. - График кривой баланса, получаемый при тестировании советника на валютной паре EURUSD.

 

Рис. 3. - График кривой баланса, получаемый при тестировании советника на валютной паре USDCHF.

 

Рис. 4. - График кривой баланса, получаемый при тестировании советника на валютной паре GBPUSD.

 

Рис. 5. - График кривой баланса, получаемый при тестировании советника на валютной паре USDJPY.

    На этот раз результаты получились наполовину удачные (или наполовину неудачные - кому как больше нравится), так как на двух из четырех валютных пар получена прибыль, а на остальных двух - нет. Рассмотрим статистические характеристики прибыльных пар. Это GBPUSD и USDJPY.

    GBPUSD.   Количество сделок 332. Чистая прибыль 4278.48 долларов против максимальной просадки 859.18, что дает фактор восстановления 4.98. За все время разработок стратегий в данной рубрике это самый высокий показатель! Если исходить из начального капитала 10000, то максимальный риск за последние полтора года составил 8,5%. Но при этом получена прибыль 42,7%. Довольно неплохой бизнес. Ко всему прочему, характер кривой баланса очень близок к идеальному. Рост наблюдается  равномерный, нет периодов "застоя" или рывков. Поэтому результаты смело можно относить к отличным.

    USDJPY.   Количество сделок 363. Чистая прибыль 2057.63 долларов против максимальной просадки 767.65. Соответственно, фактор восстановления 2.68. Как уже ранее упоминалось, фактор восстановления больше двух - очень неплохой показатель. Но здесь немного портит картину вид кривой баланса. В первой половине теста особых изменений баланса не происходило, затем же произошел двухэтапный рывок вверх, после которого наблюдается небольшое затишье. Это свидетельствует о непостоянстве выявленной закономерности, но, с другой стороны, может принести плоды сиюминутно, в отличие от пары GBPUSD, где прибыль накапливается равномерно.

    Такие удачные результаты тестирования по парам GBPUSD и USDJPY наводят на мысль о возможном применении стратегии на одной из самых волатильных валютных пар Forex - GBPJPY, которая чудесным образом сочетает закономерности обеих пар. Для "чистоты эксперимента" тестирование произведем с точно такими же параметрами и на точно таком же промежутке (см. рис. 6)

Рис. 6. - График кривой баланса, получаемый при тестировании советника на валютной паре GBPJPY.

    Как видим, чуда не случилось. Результаты взяли крайности от своих "родителей". От USDJPY взято непостоянство, а от GBPUSD - хорошая прибыль. Но в итоге это вылилось в такие показатели. Количество сделок 357. Читая прибыль 6831.94, а максимальная просадка 2665.58 долларов. Фактор восстановления выходит 2.56. Это ниже, чем у обеих родительских пар. Вид кривой баланса ужасен. Сначала серьезная просадка, потом резкий выход из нее, а затем вновь топтание на месте. Поэтому работать по описанной стратегии на паре GBPJPY не рекомендуется.

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

Сентябрь 2009