Индикатор TrendDefinition

Советник TrendDefinintion

 

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

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

    Разделим поставленную задачу на две подзадачи, точнее на определение двух видов трендов. Один назовем "глобальным", который будет определяться по старшему таймфрейму (например D1), другой - "локальным", который определим по младшему (рабочему) таймфрейму (например Н1). Причем, каждый из трендов будет определяться по разным алгоритмам.

    Для определения глобального тренда очень удобно использовать какую-нибудь классическую методику. В данном случае очень хорошо подойдут фракталы. Пробитие ценой последнего UP-фрактала вверх будем считать началом глобального восходящего тренда, и наоборот - пробитие последнего Down-фрактала вниз считаем началом глобального нисходящего тренда (см. рис. 1). UP-фракталом называется фрактал, который сформировался на максимуме свечи и является локальным максимумом среди пяти прилегающих свечей (двух слева и двух справа). Соответственно Down-фрактал формируется на минимуме свечи и является локальным минимумом среди пяти прилегающих свечей.

Рис. 1. - Определение тренда по фракталам.

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

    Для определения локального тренда используем более чувствительный индикатор Trend_Definition, который основан на скользящих средних (см. рис. 2). В особых пояснениях техника работы с индикатором не нуждается - стрелки говорят сами за себя. Необходимо учесть лишь один нюанс - открытие сделки осуществляется, когда закрылась свеча, на которой появилась стрелка. Красными пунктирными линиями отмечено открытие коротких сделок, а синими - длинных.

Рис. 2. - Определение тренда по индикатору Trend_Definition.

    Соединяя воедино два метода, получим такое правило: "Сделки открываются в направлении, указанном индикатором Trend_Definition, если оно совпадает с направлением глобального тренда, определенного по методу пробития фракталов".

    С открытием разобрались, это хорошо. Но не менее важно иметь правило для выхода из сделок. Простое "да мне хватит" здесь применять не стоит, так как чревато недобором прибыли в долгосрочном тренде, что приведет к недостаточному перекрытию получаемых убытков. Решение выхода из сделки, как оказывается, лежит на поверхности. Если Trend_Definition показывает противоположное направление глобальному тренду, то стоит закрыть текущую сделку (но не открывать противоположную) и подождать нового трендсогласующегося сигнала.

    В итоге у нас сформулированы правила открытия и закрытия сделок. Можно воплотить их в коде на MQL4.

    Генерация сигналов открытия и закрытия сделок будет производиться  в одной функции - GetSignal. Результатом вычислений станет одно из пяти состояний, которые должны обрабатываться экспертом:

  • 0 - нет сигналов. Эксперт ничего не предпринимает.

  • 1 - сигнал открытия длинной позиции. Эксперт закрывает текущую короткую позицию, если таковая имеется, и открывает длинную.

  • 2 - сигнал открытия короткой позиции. Эксперт закрывает текущую длинную позицию, если таковая имеется, и открывает короткую.

  • 3 - сигнал закрытия длинной позиции. Эксперт закрывает имеющуюся длинную позицию.

  • 4 - сигнал закрытия короткой позиции. Эксперт закрывает имеющуюся короткую позицию.

 
//+-------------------------------------------------------------------------------------+
//| Расчет сигнала по Trend_Definition и дневным фракталам                              |
//+-------------------------------------------------------------------------------------+
void GetSignal()
{
 Signal = 0;                                                         // обнуление сигнала
 
// - 1 - == Берем значения 4-го и 5-го буферов индикатора Trend_Definition ==============
 double STBuy = iCustom(Symbol(), 0, "Trend_Definition", TimeFrame, MAPeriod, Method, 
                        Smoothing, Filter, False, Steady, 2*MAPeriod, 3, 1);
 double STSell = iCustom(Symbol(), 0, "Trend_Definition", TimeFrame, MAPeriod, Method, 
                         Smoothing, Filter, False, Steady, 2*MAPeriod, 4, 1);
// - 1 - == Окончание блока =============================================================

// - 2 - == Сигнал закрытия SELL и открытия BUY =========================================
 if (STBuy != EMPTY_VALUE)        // если значение индикатора "непустое", то стрелка есть
   {
    Signal = 4;                                           // Это уже сигнал закрытия SELL      
    if (FindLastBit(PERIOD_D1) == 1)    // если же последний дневной фрактал пробит вверх
      Signal = 1;                                           // то это сигнал открытия BUY
   }   
// - 2 - == Окончание блока =============================================================

// - 3 - == Сигнал закрытия BUY и открытия SELL =========================================
 if (STSell != EMPTY_VALUE)       // если значение индикатора "непустое", то стрелка есть
   {
    Signal = 3;                                            // Это уже сигнал закрытия BUY
    if (FindLastBit(PERIOD_D1) == 2)     // если же последний дневной фрактал пробит вниз
      Signal = 2;                                          // то это сигнал открытия SELL
   }   
// - 3 - == Окончание блока =============================================================
}

В начале функции обнуляется значение переменной Signal, которая и отвечает за подачу торговых сигналов эксперту. В первом блоке переменные STBuy и STSell посредством вызова функции iCustom заполняются значениями четвертого и пятого (в индикаторах нумерация буферов начинается с нуля, поэтому в коде вместо 4 и 5 указано 3 и 4) буферов индикатора TrendDefinition на предыдущей (первой) свече. Факт наличия стрелки индикатора - это непустое значение (EMPTY_VALUE). Таким образом, если существует значение STBuy, то это, как минимум, сигнал закрытия короткой позиции и переменная Signal принимает значение 4. Если же при этом глобальный тренд определен как восходящий, то есть результат вызова функции FindLastBit равен 1, то это уже сигнал открытия длинной позиции и переменная Signal принимает значение 1. Точно таким же образом отрабатывает блок 3, где происходит генерация сигналов закрытия длинной позиции и открытия короткой позиций.

Функция FindLastBit производит нахождение последнего пробития фрактала на дневном графике.

 
//+-------------------------------------------------------------------------------------+
//| Поиск последнего пробития                                                           |
//| Имеется несколько граничных случаев, когда функция неправильно определяет пробитие: |
//|  1) Свеча пробивает оба фрактала. В этом случае анализ производится по соотношению  |
//|     Open и Close, но такой метод далеко не всегда верен                             |
//|  2) Опять же, одна свеча пробивает фракталы в разные стороны и закрывается дожи.    |
//|     В этом случае предпочтение искусственно отдается пробитию вверх                 |
//+-------------------------------------------------------------------------------------+
int FindLastBit(int TF)
{
 int MaxBars = iBars(Symbol(), TF)-1;
 int i = 3;
 while(True)
   {
    if(!LastFractal(TF, i))                             // Находим два последних фрактала
      return(0);
    int UpBit = iHighest(Symbol(), TF, MODE_HIGH, NUp+1);   // Поиск пробития UP-фрактала
    if(UpBit == NUp)                                            // Если фрактал не пробит
      UpBit = MaxBars;                        // то ставим метку "не было пробития вверх"
    int DnBit = iLowest(Symbol(), TF, MODE_LOW, NDn+1);   // Поиск пробития Down-фрактала
    if(DnBit == NDn)                                            // Если фрактал не пробит
      DnBit = MaxBars;                         // то ставим метку "не было пробития вниз"
    if(UpBit == MaxBars && DnBit == MaxBars)// Если не найдено ни одно пробитие фракталов
      {
       i = MathMin(NUp, NDn)+1;         // то переходим у поиску следующей пары фракталов
       continue;                                               // продолжение цикла while
      }  
    // Определяем, какой из фракталов был пробит позже
    if((UpBit < DnBit) || 
       (DnBit == UpBit && iOpen(Symbol(), TF, DnBit) <= iClose(Symbol(), TF, DnBit)))
        return(1);                                              // верхний - возвращаем 1
    if((DnBit < UpBit) || 
       (DnBit == UpBit && iOpen(Symbol(), TF, DnBit) > iClose(Symbol(), TF, DnBit)))
       return(2);                                                // нижний - возвращаем 1
    // -----------------------------------------------  
   } 
}

Несмотря на кажущуюся сложность, логика функции проста. После вызова пользовательской функции LastFractal в переменных NUp и NDn фиксируются номера баров с последними Up- и Down-фракталами соотвественно. Затем достаточно произвести поиск самого большого и самого малого значения цены, начиная с текущей свечи до свечи с фракталом. Если номер найденного экстремума отличается от NUp или NDn, значит фрактал пробит. Если же новый экстремум не найден, то происходит возврат в цикл с поиском следующей пары фракталов. И так до тех пор, пока не будет найдено последнее пробитие.

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

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

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

Июль 2009