Советник ZigZagStatistic_Expert

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

 

        Из множества индикаторов, отлично работающих на истории и мало чем полезных в реальной торговле, наиболее "красивым" является ZigZag (ЗигЗаг, далее ЗЗ). Мало еще какой индикатор может похвастаться точным указанием точки входа с точностью до одного пункта. Правда, как уже отмечалось, вся эта "красота" показывает точные входы только на истории. При реальной торговле последний пик (экстремум) ЗЗ все время находится в движении и точка останова может оказаться намного дальше того значения, на котором этот пик появился впервые. И лишь при появлении нового пика, предыдущий пик фиксируется и остается таким на истории.

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

        Первый способ - консервативный и даже немного банальный. Заключается он в применении дополнительного индикатора, в качестве которого в наших исследованиях очень часто выступает MACD. Суть применения MACD в том, чтобы после появления нового пика ЗЗ ждать разворота MACD. Например, новый пик ЗЗ - нижний. Тогда нам следует дождаться момента, когда главная линия MACD (гистограмма) станет выше сигнальной линии. Это подтверждение покупки. И наоборот, если новый пик ЗЗ - верхний, то ждем, когда главная линия MACD станет ниже сигнальной. Это подтверждение продажи.

        Второй способ - статистический. Так как в нашем распоряжении находится прекрасный инструмент для выделения отдельных фаз рынка, то можно произвести расчет простейших статистических характеристик: максимального и минимального движений, а также среднего значения всех рассматриваемых движений. Одно такое движение между соседними пиками ЗЗ назовем "ногой" ЗЗ. Итак, перебирая некоторое количество ног ЗЗ (например, 10 последних), можем точно определиться как минимум с тремя величинами: максимальная длина ноги, минимальная длина ноги и средняя длина ноги. Дальше сравниваем длину последней ноги со средней полученной величиной и, если длина текущей ноги уже стала больше средней величины, совершаем сделку в обратном направлении от последнего пика. При этом, имея минимальное значение длины ноги, используем его в качестве цели сделки, как наиболее вероятное расстояние, которое может пройти цена. В то же время, максимальную длину ноги используем в качестве стопа сделки как наименее вероятную величину движения цены против сделки.

        Объединяя два перечисленных метода, получаем систему, где открытие сделки происходит при совпадении двух критериев - прохождения ценой динамически меняющегося среднего расстояния и формирования сигнала стандартного индикатора МТ4 (см. рис. 1).

Рис. 1. - Сложение двух критериев открытия сделки - индикатор и статистика.

            На рисунке видно, что короткая сделка была открыта с довольно большим опозданием, когда цена прошла уже больше половины обратного движения. "Виновником" этого в данном случае стал слишком медлительный MACD. Тем не менее, это не помешало взять прибыль, хоть рынок и "помотал нервишки" хорошим откатом. Длинная же сделка была открыта практически без опозданий. И в данном случае MACD как раз помог, так как иначе (если брать во внимание только среднюю величину ног ЗЗ) сделка была бы открыта намного выше. Примерно на уровне закрытия короткой сделки. Вот таким образом эти два критерия помогают друг другу в торговле, страхуя от преждевременных входов.

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

            Для этого нам потребуются дополнительные сделки, которые будут открываться в убыточной зоне первоначальной (первичной) позиции. Ограничим максимальное количество возможных сделок по одному сигналу любимым числом сказочников - 3. Тогда все расстояние от уровня открытия первичной сделки до ее стопа мы можем разделить на три части. На уровне первой трети будет расположен первый дополнительный ордер (вторичный ордер), а на уровне второй трети - второй дополнительный ордер (третичный ордер). На уровне трех третей у нас находится общий стоп. В результате, даже при самом неблагоприятном развитии событий, когда цена все-таки доберется до стопа, вместо одного стопа мы получим два (полный стоп от первичной позиции + две трети от вторичной + одна треть от третичной). С другой стороны, мы получаем возможность закрыть всю совокупную сделку раньше, чем планировалось изначально, так как при открытии дополнительных сделок  без достижения стопа мы получаем дополнительную прибыль от новых позиций. Поэтому при срабатывании каждого дополнительного ордера общий профит будет перерасчитываться и переноситься на такой уровень, где общая прибыль будет равна первоначально запланированной.

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

Рис. 2. - Один из случаев "спасения ситуации".

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

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

 
//+-------------------------------------------------------------------------------------+
//| Расчет сигнала                                                                      |
//+-------------------------------------------------------------------------------------+  
void GetSignal() 
{
 Signal = 0;                                             // сброс сигнала перед расчетами

 if (ZZSignal())                 // Если найдены все пики ЗЗ, то можно производить расчет
   {
    Comment("Максимальная длина = ", ZZMaxPips/Point, " пунктов\nМинимальная длина = ", 
           ZZMinPips/Point, " пунктов\nСредняя длина = ", MathRound(ZZSumm/Count/Point));
    if (ZZFDiff > ZZSumm/Count)   // если величина ноги больше средней величины, то можно
      {                                                               // совершать сделку
       double MACDM = iMACD(Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1);
       double MACDS = iMACD(Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, 1);
       if (ZZFirst == 1 && MACDM < MACDS)   // последний экстремум верхний и главная ниже
         Signal = 2;                                          // сигнальной - сигнал SELL
       if (ZZFirst == -1 && MACDM > MACDS)   // последний экстремум нижний и главная выше
         Signal = 1;                                           // сигнальной - сигнал BUY
      }
   }    
}

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

               Если же исполнение ZZSignal увенчалось успехом, то нам становятся доступны значения таких переменных:

  • ZZMinPips - минимальная длина ноги ЗЗ
  • ZZMaxpips - максимальная длина ноги ЗЗ
  • ZZSumm - общая сумма длин найденных ног ЗЗ
  • Count - количество подсчитанных ног ЗЗ
  • ZZFDiff - длина первой (наиболее поздней сформированной) ноги ЗЗ
  • ZZFirst - тип первого найденного экстремума ЗЗ (1 - верхний, -1 - нижний)

               Должно быть понятно, что делением ZZSumm на Count вычисляется среднее значение длины ноги ЗЗ. Поэтому, если значение ZZFDiff (длина первой найденной ноги ЗЗ) больше средней длины ноги, то мы можем переходить к ожиданию сигналов открытия сделок. Для этого еще необходимо получить соответствующий сигнал от MACD. Поэтому переменная Signal изменяет свое нейтральное положение, только если главная линия MACD оказывается ниже сигнальной при последнем верхнем экстремуме ЗЗ (ZZFirst = 1) или при последнем нижнем экстремуме ЗЗ (ZZFirst = -1) и нахождении главной линии MACD выше сигнальной.

            Посмотрим, как же формируются значения переменных ZZxxxxx:

 
//+-------------------------------------------------------------------------------------+
//| Нахождение последних FindPeak экстремумов ЗЗ                                        |
//+-------------------------------------------------------------------------------------+
bool ZZSignal()
{
// - 1 - ============================== Инициализация переменных ========================
 Count = 0;                                                           // счетчик пиков ЗЗ
 double ZZLast = 0;                          // Значение последнего найденного экстремума
 int i = 0;                                                              // счетчик баров
 ZZMaxPips = 0;                                             // максимальная длина ноги ЗЗ
 ZZMinPips = 100000;                                         // минимальная длина ноги ЗЗ
 ZZSumm = 0;         // общая сумма длин всех найденных ного для вычисления средней длины
 ZZFirst = 0;             // Тип первого найденного экстремума (1 - верхний, -1 - нижний)
 ZZFDiff = 0;                                           // Длина первой найденной ноги ЗЗ
// - 1 - ================================ Окончание блока ===============================

 while (Count < FindPeak)
   {
// - 2 - ======================== Поиск одного экстремума ЗЗ ============================ 
    double ZZCur = 0;
    while(ZZCur == 0 && i < Bars)
      {
       ZZCur = iCustom(Symbol(), 0, "ZigZag", Depth, Deviation, BackStep, 0, i);
       i++;
      }
// - 2 - ============================ Окончание блока ===================================

// - 3 - ======================== Анализ найденного экстремума ========================== 
    if (ZZCur == 0)
      return(False);           // Если ни один из экстремумов не определен, то это ошибка

    if (ZZLast != 0)     // если это не первый найденный экстремум, то можно рассчитывать
      {                                                          // другие характеристики
       if (ZZSumm == 0)
         ZZFDiff = MathAbs(ZZLast - ZZCur);   // вычисляем длину первой найденной ноги ЗЗ
       ZZSumm += MathAbs(ZZLast - ZZCur);             // Прибавляем последнее движение ЗЗ
       ZZMaxPips = MathMax(ZZMaxPips, MathAbs(ZZLast - ZZCur));     // Находим наибольшее
       ZZMinPips = MathMin(ZZMinPips, MathAbs(ZZLast - ZZCur));     // Находим наибольшее
       Count++;  
      }
     else           // если это первый найденный экстремум, то запоминаем его направление
      if (ND(ZZCur) == ND(High[i-1]))
        ZZFirst = 1;
       else
        if (ND(ZZCur) == ND(Low[i-1]))
          ZZFirst = -1; 
   
    ZZLast = ZZCur;                           // запоминаем текущий экстремум как прошлый 
  }  
// - 3 - ============================ Окончание блока ===================================
   
 return(True);  
}

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

            Второй и третий блоки находятся во власти цикла "while", то есть до тех пор, пока количество найденных экстремумов ЗЗ не станет равно FindPeak. 

            Поиском одного экстремума занят второй блок. В нем производится вызов пользовательского индикатора ZigZag, который, тем не менее, идет в стандартной поставке МТ4, с нужными пользователю параметрами Depth, Deviation и BackStep. Сигналом нахождения экстремума является ненулевое значение, возвращаемое функцией iCustom. Чтобы цикл не вышел за пределы доступной истории, счетчик баров i все время сравнивается с общим количеством баров Bars. Поэтому начало третьего блока сопровождается именно проверкой выхода за доступную историю. В этом случае ZZSignal вернет False.

            Далее в третьем блоке производится анализ найденного экстремума ЗЗ. Если это был первый найденный экстремум, то в ZZLast еще нет предыдущих значений. Поэтому заполняется значение ZZFirst, определяющего тип первого найденного экстремума. И только после этого ZZLast получает свое первое значение. На следующей итерации ZZLast уже будет содержать значение последнего найденного экстремума, что позволит посчитать первую сумму длин ног ЗЗ, которая также будет занесена в ZZFDiff. Здесь же будут определены максимальная и минимальная длины ног ЗЗ на данный момент.

             После того, как сформирован сигнал открытия сделки, все это можно обработать в связующей функции советника 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 -  == Окончание блока ============================================================

// - 3 - ==== Проверка необходимости открытия доливочных ордеров ========================
   PendingOrders();
// - 3 -  == Окончание блока ============================================================
   
// - 4 - == Контроль открытия нового бара и генерация сигнала ===========================
   if (LastBar == Time[0]) return (0);

   GetSignal();
// - 4 -  == Окончание блока ============================================================
   
// - 5 - == Открытие длинной позиции ====================================================
   if (Signal == 1) 
     if (LastWorkPosition() != OP_BUY)                    // последняя сделка была не BUY
       {
        RefreshRates();
        TP = ND(Bid + ZZMinPips);
        SL = ND(Bid - ZZMaxPips);
        if (OpenOrderCorrect(OP_BUY, ND(Ask), SL, TP, 0) != 0)
          return (0);
       }
// - 5 -  == Окончание блока ============================================================
     
// - 6 - == Открытие короткой позиции ===================================================
   if (Signal == 2) 
     if (LastWorkPosition() != OP_SELL)                  // последняя сделка была не SELL
       {
        RefreshRates();
        TP = ND(Ask - ZZMinPips);
        SL = ND(Ask + ZZMaxPips);
        if (OpenOrderCorrect(OP_SELL, ND(Bid), SL, TP, 0) != 0)
          return (0);
       }
// - 6 -  == Окончание блока ============================================================
     
   LastBar = Time[0];
   
   return (0);
}

             Как обычно, для ускорения работы советника в тестере, реализован принцип одного выполнения функции GetSignal на бар. При значении Signal, равного 1, будет открыта длинная первичная позиция, а при значении 2 - короткая первичная. Идентифицировать первичную позицию советник сможет по полю MagicNumber, которое сделаем составным. В самом младшем десятичном разряде MagicNumber будет указан тип позиции: 0 - первичная, 1- вторичная, 2 - третичная. Все остальные разряды будут содержать именно то число, которое указал пользователь во внешней переменной эксперта MagicNumber. Таким образом, оно будет умножено на 10.

               Еще одним обязательным условием работы эксперта будет чередование сделок BUY и SELL, что позволит не открывать сделку по одному и тому же сигналу два раза. В коде это достигается проверкой типа последней закрытой сделки (функция LastWorkPosition):

 
//+-------------------------------------------------------------------------------------+
//| Поиск последней закрытой сделки                                                     |
//+-------------------------------------------------------------------------------------+
int LastWorkPosition() 
{
// - 1 - ===== При тестировании достаточно взять последнюю по порядку сделку ============
 if (IsTesting())
   if (OrderSelect(OrdersHistoryTotal()-1, SELECT_BY_POS, MODE_HISTORY))
     return(MathMod(OrderType(), 2)); 
// - 1 - ======================= Окончание блока ========================================

// - 2 - ===== Онлайн придется перебирать все сделки и искать из них последнююю =========
 int LastTime = 0;                                           // Наибольшее время закрытия
 OType = -1;                                                     // Тип последней позиции
 for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) 
   if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) 
     if (OrderSymbol() == Symbol() && MathFloor(OrderMagicNumber()/10) == MagicNumber) 
       if (OrderCloseTime() > LastTime) 
         {
          LastTime = OrderCloseTime();
          OType = OrderType();
         }
// - 2 - ======================= Окончание блока ========================================
 
 return(MathMod(OType, 2));                  // Возвращаем тип сделки (0 - BUY, 1 - SELL)
}

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

              Последняя значимая функция советника заведует дополнительными ордерами, которые должны откладываться при появлении первичной позиции и удаляться при ее исчезновении (закрытии по профиту):

 
//+-------------------------------------------------------------------------------------+
//| Мониторинг доливочных ордеров                                                       |
//+-------------------------------------------------------------------------------------+
void PendingOrders()
{
// - 1 - == Если открыта первичная позиция, то проверяем есть ли вторичная и третичная ==
 if (OrderSelect(Primary, SELECT_BY_TICKET) && OrderCloseTime() == 0)
   {
    LastBar = Time[0];
    // - 1.1 - =================== Открытие вторичного ордера ===========================
    if (OTSecondary < OTPrimary)//время открытия вторичного ордера меньше, значит его нет
      {
       if (OrderType() == OP_BUY)     // тип первичной позиции BUY, тогда ставим BUYLIMIT
         {
          int Type = OP_BUYLIMIT;
          double Price = ND(OrderOpenPrice() - (OrderOpenPrice() - OrderStopLoss())/3);
          double TP = ND((Price + OrderOpenPrice())/2 +
                         (OrderTakeProfit() - OrderOpenPrice())/2);
         }
        else                        // тип первичной позиции SELL, тогда ставим SELLLIMIT
         {
          Type = OP_SELLLIMIT;
          Price = ND(OrderOpenPrice() + (OrderStopLoss() - OrderOpenPrice())/3);
          TP = ND((Price + OrderOpenPrice())/2 -
                         (OrderOpenPrice() - OrderTakeProfit())/2);
         } 
       OpenOrderCorrect(Type, Price, OrderStopLoss(), TP, 1);
       return;
      }
    // - 1.1 - =================== Окончание блока ======================================

    // - 1.2 - =================== Открытие третичного ордера ===========================
    if (OTTertiary < OTPrimary)// время открытия третичного ордера меньше, значит его нет
      {
       if (OrderType() == OP_BUY)     // тип первичной позиции BUY, тогда ставим BUYLIMIT
         {
          Type = OP_BUYLIMIT;
          Price = ND(OrderStopLoss() + (OrderOpenPrice() - OrderStopLoss())/3);
          TP = ND((Price + OrderOpenPrice())/2 + 
                  (OrderTakeProfit() - OrderOpenPrice())/3);
         }
        else                        // тип первичной позиции SELL, тогда ставим SELLLIMIT
         {
          Type = OP_SELLLIMIT;
          Price = ND(OrderStopLoss() - (OrderStopLoss() - OrderOpenPrice())/3);
          TP = ND((Price + OrderOpenPrice())/2 - 
                  (OrderOpenPrice() - OrderTakeProfit())/3);
         } 
       OpenOrderCorrect(Type, Price, OrderStopLoss(), TP, 2);
       return;
      }
    // - 1.2 - =================== Окончание блока ======================================
// - 1 - ======================= Окончание блока ========================================
      
// - 2 - ======================= Модификация открытых позиций ===========================
    // - 2.1 - =================== Сработал третичный ордер =============================
    if (OrderSelect(Tertiary, SELECT_BY_TICKET) && OrderCloseTime() == 0 &&  // открылась 
        OrderType() < 2)                                             // третичная позиция
      {
       TP = ND(OrderTakeProfit());                             // по ее уровню TakeProfit
       if (OrderSelect(Secondary, SELECT_BY_TICKET) && OrderCloseTime() == 0)
         if (MathAbs(TP - OrderTakeProfit()) >= Tick)
           if (WaitForTradeContext())         // устанавливается профит вторичной позиции
             OrderModify(Secondary, 0, OrderStopLoss(), TP, 0);
       if (OrderSelect(Primary, SELECT_BY_TICKET) && OrderCloseTime() == 0)
         if (MathAbs(TP - OrderTakeProfit()) >= Tick)
           if (WaitForTradeContext())                       // и профит первичной позиции
             OrderModify(Primary, 0, OrderStopLoss(), TP, 0);
       return;
      }
    // - 2.1 - =================== Окончание блока ======================================

    // - 2.2 - =================== Сработал вторичный ордер =============================
    if (OrderSelect(Secondary, SELECT_BY_TICKET) && OrderCloseTime() == 0 && 
        OrderType() < 2)  
      {
       TP = ND(OrderTakeProfit());
       if (OrderSelect(Primary, SELECT_BY_TICKET) && OrderCloseTime() == 0)
         if (MathAbs(TP - OrderTakeProfit()) >= Tick)
           if (WaitForTradeContext())
             OrderModify(Primary, 0, OrderStopLoss(), TP, 0);
      }
    // - 2.1 - =================== Окончание блока ======================================
   }
// - 2 - ======================= Окончание блока ========================================

// - 3 - === Удаление доливочных ордеров, если исчезла первичная позиция ================
  else 
   {
    if (OrderSelect(Secondary, SELECT_BY_TICKET) && OrderCloseTime() == 0)
      if (WaitForTradeContext())
        OrderDelete(Secondary);                             // удаление вторичного ордера
    if (OrderSelect(Tertiary, SELECT_BY_TICKET) && OrderCloseTime() == 0)
      if (WaitForTradeContext())
        OrderDelete(Tertiary);                              // удаление третичного ордера
   }
// - 3 - ======================= Окончание блока ========================================
     
}

                 Первый и второй блоки выполняются только в случае присутствия первичной позиции. Тикет первичной позиции все время содержится в переменной Primary, а время ее открытия - в OTPrimary. Соответственно, тикеты вторичной и третичной позиций содержатся в переменных Secondary и Tertiary, а время их открытия - в OTSecondary и OTTertiary соответственно. Сравнение времен открытия позиций позволяет определить, был открыт дополнительный ордер после первичной позиции или это было еще на прошлом сигнале.

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

                Во втором блоке происходит проверка срабатывания вторичного и третичного ордера путем определения типа ордера. Типы ордеров BUY и SELL имеют коды 0 и 1 соответственно, поэтому в сравнение производится с числом 2 (0 и 1 меньше его). Если один из ордеров сработал, то происходит модификация профитов уже существующих позиций по уровню профита вновь открытого ордера.

                И, наконец, третий блок выполняется в случае, если первичной позиции нет. Здесь проверяется наличие дополнительных ордеров. Если таковые найдены, то сразу же удаляются.

                Приступим к проверке полученного эксперта. Исторический период выберем 01.01.2008 - 31.10.2009 и таймфрейм Н1. Все входные параметры эксперта, как обычно, по умолчанию (см. рис. 3 - 6).

 

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

               Размер чистой прибыли неплохой - 2530.50 долларов, но максимальная просадка также очень велика - 2053.42 долларов, что не является хорошим показателем. Тем не менее, вид кривой баланса довольно уверенный. Очень обнадеживают продолжительные участки непрерывной прибыли.

 

Рис. 4. - Результаты тестирования эксперта на валютной паре USDCHF.

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

 

Рис. 5. - Результаты тестирования эксперта на валютной паре GBPUSD.

                Показатели фунта более скромные, чем у его предшественников. Чистая прибыль 1788.92 против просадки 4143.09. Как результаты, так и вид кривой баланса на положительный лад не настраивают.

 

Рис. 6. - Результаты тестирования эксперта на валютной паре USDJPY.

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

                Но в качестве бонуса приведем еще один результат тестирования. На сей раз это будут результаты по паре AUDUSD, которую мы еще не включали в круг рассматриваемых валютных пар (см. рис. 7). 

 

Рис. 7. - Результаты тестирования эксперта на валютной паре AUDUSD.

                Здесь стоит отметить значительную чистую прибыль 3518.56 долларов и скромную просадку - 1385.08, что дает фактор восстановления больше двух - 2.54. Таким образом, из всех приведенных сегодня тестов, данный можно назвать победителем. Ложкой дегтя является окончание теста, которое не поддерживает уверенную динамику всего тестирования.

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