Price Action. Автоматизация торговли по внутреннему бару

15 июля 2015, 12:30
Dmitry Iglakov
38
18 698

Введение

Каждый, кто изучает рынок Forex, рано или поздно сталкивается с Price Action. Это не просто методика чтения графиков, это целая система определения возможного направления движения цены. В данной статье мы детально рассмотрим паттерн "внутренний бар" и создадим эксперта, который будет отслеживать данный паттерн и на его основании принимать торговые решения.


Коротко о Price Action

Что же такое Price Action? Это безындикаторный метод определения движения цены. Определение происходит за счет образовавшихся сложных и простых паттернов, а также построения вспомогательных графических элементов на графике (горизонтальные, вертикальные и трендовые линии, уровни Фибоначчи, уровни поддержки/сопротивления и так далее).

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


Внутренний бар

Внутренний бар (Inside Bar) — это бар, тело и тень которого находятся полностью в диапазоне предыдущего (определяющего) бара. Максимум внутреннего бара находится ниже максимума, а минимум — выше минимума определяющего бара. Определяющий бар также часто называют измерительным. В качестве паттерна и потенциального сигнала для входа рассматривают внутренний бар вместе с определяющим.

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

Рис. 1. Вид внутреннего бара на графике

Рис. 1. Вид внутреннего бара на графике

Рис. 2. Схематическое изображение внутреннего бара

Рис. 2. Схематичное изображение внутреннего бара

Правила внутреннего бара:

  • Работать с паттерном "внутренний бар" следует на старших временных графиках: H4, D1.
  • Паттерн может быть как разворотным, так и продолжением тренда.
  • Для более точного входа следует применять дополнительные элементы графического анализа: трендовые линии, уровни поддержки/сопротивления, уровни Фибоначчи, другие паттерны Price Action и так далее.
  • Во избежание преждевременного или ложного входа в рынок необходимо использовать отложенные ордера.
  • Внутренние бары, повторяющиеся во флэте, не стоит использовать в качестве сигнала к входу в рынок.

Рис. 3. Определение качественного внутреннего бара на графике GBPUSD, D1

Рис. 3. Определение качественного внутреннего бара на графике GBPUSD, D1

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


Определение точек входа, установка стоп-приказов

Мы нашли на графике (рис. 3) качественный внутренний бар. Как же следует входить в рынок и где выставлять стоп-приказы? Рассмотрим рисунок 4.

Рис. 4. Установка ордера Buy Stop и стоп-приказов

Рис. 4. Установка ордера Buy Stop и стоп-приказов

Рассмотрим правила входа и установки стоп-приказов на примере выше:

  1. Выставляем отложенный ордер Buy Stop по цене чуть выше цены High (на несколько пунктов, для подтверждения) определяющего бара.
  2. Уровень Stop Loss устанавливаем ниже уровня поддержки и ниже цены Low определяющего бара. Это дает нам дополнительную защиту в случае срабатывания отложенного ордера и разворота, когда цена может вновь отскочить от уровня поддержки и возобновить движение в нужном направлении.
  3. Уровень Take Profit устанавливаем, не доходя до ближайшего уровня сопротивления.
Мы также помним, что внутренний бар может быть предвестником как разворота, так и продолжения тренда. Следовательно, имеет смысл устанавливать Sell Stop ордер.

Рис. 5. Установка ордера Sell Stop и стоп-приказов

Рис. 5. Установка ордера Sell Stop и стоп-приказов

Рассмотрим правила входа и установки стоп-приказов на примере выше:

  1. Выставляем отложенный ордер Sell Stop по цене чуть ниже цены Low (на несколько пунктов, для подтверждения) определяющего бара.
  2. Уровень Stop Loss устанавливаем выше цены High определяющего бара.
  3. Уровень Take Profit устанавливаем, не доходя до ближайшего уровня поддержки.


Создание советника для торговли по внутреннему бару

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

Далее мы постараемся реализовать алгоритмы советника и автоматизировать торговлю по внутреннему бару.

Открываем MetaEditor из терминала MetaTrader 4 и создаем нового советника (на данном моменте останавливаться подробнее не буду, так как на сайте достаточно литературы по созданию советников). На этапе создания оставляем все параметры пустыми. Назвать их можно как угодно. В итоге должно получиться следующее:

//+------------------------------------------------------------------+
//|                                                    InsideBar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+


Перенос конструкции графической модели в алгоритмы MQL4

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

//+------------------------------------------------------------------+
//|                                                    InsideBar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

double   open1,//цена открытия первой свечи
open2,    //цена открытия второй свечи
close1,   //цена закрытия первой свечи
close2,   //цена закрытия второй свечи
low1,     //цена минимальная первой свечи
low2,     //цена минимальная второй свечи
high1,    //цена максимальная первой свечи
high2;    //цена максимальная второй свечи
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- определение цен необходимых баров
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
  }
//+------------------------------------------------------------------+

В качестве примера мы рассмотрим одну конструкцию внутреннего бара, когда определяющий бар медвежий (бар 2), а внутренний бар бычий (бар 1). Для этого напишем несколько условий в теле функции OnTick():

void OnTick()
  {
//--- определение цен необходимых баров
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//--- если вторая свеча медвежья, а первая бычья
   if(open2>close2 && //второй бар бычий
      close1>open1 && //первый бар медвежий
      high2>high1 &&  //максимум 2 бара выше максимума первого
      open2>close1 && //открытие второго выше закрытия первого
      low2<low1)      //минимум второго ниже минимума первого
     {
      //--- мы прописали все условия, указывающие, что первый бар полностью поглощен вторым
     }
  }
  • Создаем переменные, настраиваемые пользователем: стоп-приказы, проскальзывание, время истечения ордеров, магический номер советника, торговый лот. Стоп-лосс можем не указывать, так как будем устанавливать его по правилам внутреннего бара.
  • Вводим локальные переменные для приведения переменных в нормальный вид.
  • Кроме того, мы помним, что стоп-приказы устанавливаются на определенном интервале от значений цен бара. Для этого вводим входную переменную Interval, которая отвечает за интервал между ценами минимума/максимума бара и уровнями стоп-приказов, а также ценой установки отложенного ордера.
  • Вводим переменную timeBarInside, отвечающую за предотвращение повторного открытия ордера на данном паттерне.
  • Вводим переменную bar2size для проверки, что определяющий бар имеет достаточно большой размер. Тем самым, мы можем предположить, что рынок не находится во флэте.

В результате мы получаем следующий код:

//+------------------------------------------------------------------+
//|                                                    InsideBar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

extern int     interval          = 20;                               //Interval
extern double  lot               = 0.1;                              //Lot Size
extern int     TP                = 300;                              //Take Profit
extern int     magic             = 555124;                           //Magic number
extern int     slippage          = 2;                                //Slippage
extern int     ExpDate           = 48;                               //Expiration Hour Order
extern int     bar2size          = 800;                              //Bar 2 Size

double   buyPrice,//для определения цены установки BuyStop
buyTP,      //Take Profit BuyStop
buySL,      //Stop Loss BuyStop
sellPrice,  //для определения цены установки SellStop
sellTP,     //Take Profit SellStop
sellSL;     //Stop Loss SellStop

double   open1,//цена открытия первой свечи
open2,    //цена открытия второй свечи
close1,   //цена закрытия первой свечи
close2,   //цена закрытия второй свечи
low1,     //цена минимальная первой свечи
low2,     //цена минимальная второй свечи
high1,    //цена максимальная первой свечи
high2;    //цена максимальная второй свечи

datetime _ExpDate=0;          //локальная переменная для определения времени истечения отложенного ордера
double     _bar2size;
datetime timeBarInside;         //время бара, на котором открылись ордера по внутреннему бару, для исключения повторного открытия
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid     = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits); //определение нижней цены 
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //определение верхней цены
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- определение цен необходимых баров
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
//--- если вторая свеча медвежья, а первая бычья
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //на данном паттерне еще не открывались ордера
      _bar2size>bar2size && //второй бар достаточно большой, чтобы не считать рынок во флэте
      open2>close2 && //второй бар бычий
      close1>open1 && //первый бар медвежий
      high2>high1 &&  //максимум 2 бара выше максимума первого
      open2>close1 && //открытие второго выше закрытия первого
      low2<low1)      //минимум второго ниже минимума первого
     {
      //--- мы прописали все условия, указывающие, что первый бар полностью поглощен вторым
      timeBarInside=iTime(Symbol(),Period(),1); //указываем, что на данном паттерне уже установлены ордера
     }
  }
//+------------------------------------------------------------------+


Определение уровней стоп-приказов

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

В теле функции OnTick() пишем следующий код:

buyPrice=NormalizeDouble(high2+interval*_point,Digits); //определяем цену установки ордера с учетом интервала
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //определяем стоп-лосс с учетом интервала
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //определяем тейк-профит
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //расчет времени истечения отложенного ордера
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+interval*_point,Digits);
      sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);


Работа над ошибками исполнения

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

//+---------------------------------------------------------------------------------------------------------------------+
//| Функция открывает или устанавливает ордер                                                                           |
//| symbol      - Наименование финансового инструмента, с которым проводится торговая операция.                         |
//| cmd         - Торговая операция. Может быть любым из значений торговых операций.                                    |
//| volume      - Количество лотов.                                                                                     |
//| price       - Цена открытия.                                                                                        |
//| slippage    - Максимально допустимое отклонение цены для рыночных ордеров (ордеров на покупку или продажу).         |
//| stoploss    - Цена закрытия позиции при достижении уровня убыточности (0 в случае отсутствия уровня убыточности).   |
//| takeprofit  - Цена закрытия позиции при достижении уровня прибыльности (0 в случае отсутствия уровня прибыльности). |
//| comment     - Текст комментария ордера. Последняя часть комментария может быть изменена торговым сервером.          |
//| magic       - Магическое число ордера. Может использоваться как определяемый пользователем идентификатор.           |
//| expiration  - Срок истечения отложенного ордера.                                                                    |
//| arrow_color - Цвет открывающей стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE,       |
//|               то открывающая стрелка не отображается на графике.                                                    |
//+---------------------------------------------------------------------------------------------------------------------+
int OrderOpenF(string     OO_symbol,
               int        OO_cmd,
               double     OO_volume,
               double     OO_price,
               int        OO_slippage,
               double     OO_stoploss,
               double     OO_takeprofit,
               string     OO_comment,
               int        OO_magic,
               datetime   OO_expiration,
               color      OO_arrow_color)
  {
   int      result      = -1;    //результат открытия ордера
   int      Error       = 0;     //ошибка при открытии ордера.
   int      attempt     = 0;     //количество сделаных попыток
   int      attemptMax  = 3;     //максимальное количество попыток
   bool     exit_loop   = false; //выход из цикла
   string   lang=TerminalInfoString(TERMINAL_LANGUAGE);  //язык торгового терминала, для определения языка сообщения
   double   stopllvl=NormalizeDouble(MarketInfo(OO_symbol,MODE_STOPLEVEL)*MarketInfo(OO_symbol,MODE_POINT),Digits);  //минимально допустимый уровень стоп-лосса/тейк-профита в пунктах
                                                                                                                     //модуль обеспечивает безопасное открытие ордеров. 
//--- проверяем стоп-приказы ордеров на покупку
   if(OO_cmd==OP_BUY || OO_cmd==OP_BUYLIMIT || OO_cmd==OP_BUYSTOP)
     {
      double tp = (OO_takeprofit - OO_price)/MarketInfo(OO_symbol, MODE_POINT);
      double sl = (OO_price - OO_stoploss)/MarketInfo(OO_symbol, MODE_POINT);
      if(tp>0 && tp<=stopllvl)
        {
         OO_takeprofit=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT);
        }
      if(sl>0 && sl<=stopllvl)
        {
         OO_stoploss=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT));
        }
     }
//--- проверяем стоп-приказы ордеров на продажу
   if(OO_cmd==OP_SELL || OO_cmd==OP_SELLLIMIT || OO_cmd==OP_SELLSTOP)
     {
      double tp = (OO_price - OO_takeprofit)/MarketInfo(OO_symbol, MODE_POINT);
      double sl = (OO_stoploss - OO_price)/MarketInfo(OO_symbol, MODE_POINT);
      if(tp>0 && tp<=stopllvl)
        {
         OO_takeprofit=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT));
        }
      if(sl>0 && sl<=stopllvl)
        {
         OO_stoploss=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT);
        }
     }
//--- цикл while
   while(!exit_loop)
     {
      result=OrderSend(OO_symbol,OO_cmd,OO_volume,OO_price,OO_slippage,OO_stoploss,OO_takeprofit,OO_comment,OO_magic,OO_expiration,OO_arrow_color); //попытка открыть ордер по установленным параметрам
      //--- условие, если произошла ошибка при открытии ордера
      if(result<0)
        {
         Error = GetLastError();                                     //присваиваем ошибке код
         switch(Error)                                               //перечисление ошибок
           {                                                         //перечисление ошибок закрытия ордеров и попытка их исправить
            case  2:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  Sleep(3000);                                       //задержка в 3 секунды
                  RefreshRates();
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;                                         //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case  3:
               RefreshRates();
               exit_loop = true;                                     //выход из while
               break;                                                //выход из switch   
            case  4:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  Sleep(3000);                                       //задержка в 3 секунды
                  RefreshRates();
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case  5:
               exit_loop = true;                                     //выход из while
               break;                                                //выход из switch   
            case  6:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  Sleep(5000);                                       //задержка в 3 секунды
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case  8:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  Sleep(7000);                                       //задержка в 3 секунды
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case 64:
               exit_loop = true;                                     //выход из while
               break;                                                //выход из switch
            case 65:
               exit_loop = true;                                     //выход из while
               break;                                                //выход из switch
            case 128:
               Sleep(3000);
               RefreshRates();
               continue;                                             //выход из switch
            case 129:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  Sleep(3000);                                       //задержка в 3 секунды
                  RefreshRates();
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case 130:
               exit_loop=true;                                       //выход из while
               break;
            case 131:
               exit_loop = true;                                     //выход из while
               break;                                                //выход из switch
            case 132:
               Sleep(10000);                                         //засыпаем на 10 сек.
               RefreshRates();                                       //обновляем данные
               //exit_loop = true;                                   //выход из while
               break;                                                //выход из switch
            case 133:
               exit_loop=true;                                       //выход из while
               break;                                                //выход из switch
            case 134:
               exit_loop=true;                                       //выход из while
               break;                                                //выход из switch
            case 135:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  RefreshRates();
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case 136:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //указываем еще одну попытку
                  RefreshRates();
                  break;                                             //выход из switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //обнуляем количество попыток 
                  exit_loop = true;                                  //выход из while
                  break;                                             //выход из switch
                 }
            case 137:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(2000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 138:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(1000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 139:
               exit_loop=true;
               break;
            case 141:
               Sleep(5000);
               exit_loop=true;
               break;
            case 145:
               exit_loop=true;
               break;
            case 146:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(2000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 147:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  OO_expiration=0;
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 148:
               exit_loop=true;
               break;
            default:
               Print("Error: ",Error);
               exit_loop=true; //выход из while 
               break;          //другие варианты 
           }
        }
      //--- условие, если ошибок нет
      else
        {
         if(lang == "Russian") {Print("Ордер успешно открыт. ", result);}
         if(lang == "English") {Print("The order is successfully opened.", result);}
         Error = 0;                                //обнуляем код ошибки
         break;                                    //выходим из while
         //errorCount =0;                          //обнуляем количество попыток
        }
     }
   return(result);
  }
//+------------------------------------------------------------------+

В результате всех действий получаем следующий код:

//+------------------------------------------------------------------+
//|                                                    InsideBar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

extern int     interval          = 20;                               //Interval
extern double  lot               = 0.1;                              //Lot Size
extern int     TP                = 300;                              //Take Profit
extern int     magic             = 555124;                           //Magic number
extern int     slippage          = 2;                                //Slippage
extern int     ExpDate           = 48;                               //Expiration Hour Order
extern int     bar2size          = 800;                              //Bar 2 Size

double   buyPrice,//для определения цены установки BuyStop
buyTP,      //Take Profit BuyStop
buySL,      //Stop Loss BuyStop
sellPrice,  //для определения цены установки SellStop
sellTP,     //Take Profit SellStop
sellSL;     //Stop Loss SellStop

double   open1,//цена открытия первой свечи
open2,    //цена открытия второй свечи
close1,   //цена закрытия первой свечи
close2,   //цена закрытия второй свечи
low1,     //цена минимальная первой свечи
low2,     //цена минимальная второй свечи
high1,    //цена максимальная первой свечи
high2;    //цена максимальная второй свечи

datetime _ExpDate=0;          //локальная переменная для для определения времени истечения отложенного ордера
double     _bar2size;
datetime timeBarInside;       //время бара, на котором открылись ордера по внутреннему бару, для исключения повторного открытия
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid     = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits); //определение нижней цены 
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //определение верхней цены
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- определение цен необходимых баров
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
//--- если вторая свеча медвежья, а первая бычья
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //на данном патерне еще не открывались ордера
      _bar2size>bar2size && //второй бар достаточно большой, чтобы не считать рынок во флете
      open2>close2 && //второй бар бычий
      close1>open1 && //первый бар медвежий
      high2>high1 &&  //максимум 2 бара выше максимума первого
      open2>close1 && //открытие второго выше закрытия первого
      low2<low1)      //минимум второго ниже минимума первого
     {
      buyPrice=NormalizeDouble(high2+interval*_point,Digits); //определяем цену установки ордера с учетом интервала
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //определяем стоп-лосс с учетом интервала
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //определяем тейк-профит
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //расчет времени истечения отложенного ордера
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+interval*_point,Digits);
      sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
      OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue);
      OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue);
      //--- мы прописали все условия, указывающие, что первый бар полностью поглощен вторым
      timeBarInside=iTime(Symbol(),Period(),1); //указываем, что на данном паттерне уже установлены ордера
     }
  }
//+------------------------------------------------------------------+

Проводим компиляцию. Проверяем наличие записей в логе ошибок.


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

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

Входные параметры для тестирования

Рис. 6. Входные параметры для тестирования

  1. Выбираем валютную пару для тестирования. Я выбрал CADJPY.
  2. Обязательно выбираем модель тестирования "Все тики", а также указываем, что тестирование будем проводить на исторических данных. Я выбрал за весь 2014 год.
  3. Указывам период D1.
  4. Запускаем тестирование.
  5. После завершения тестирования проверяем журнал. В результате мы видим, что при тестировании не возникало ошибок исполнения.

Вот пример журнала после тестирования:

Рис. 7. Журнал тестирования советника

Рис. 7. Журнал тестирования советника

Убедившись в отсутствии ошибок, проводим оптимизацию советника.


Оптимизация

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

Параметры оптимизации

Рис. 8. Параметры оптимизации

Рис. 9. Настройка оптимизации

Рис. 9. Настройка оптимизации

В результате оптимизации и тестирования мы получаем вполне рабочего робота.


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

Рис. 10. Результаты тестирования

Рис. 10. Результаты тестирования

Рис. 11. График результатов тестирования

Рис. 11. График результатов тестирования


Заключение

  1. В рамках данной статьи мы создали рабочего советника, торгующего по внутреннему бару.
  2. Мы убедились, что даже не имея дополнительных фильтров для входа в рынок, паттерны Price Action работают.
  3. Мы доказали работоспособность, не прибегая к хитростям и уловкам, таким как Мартингейл, усреднение и так далее.
  4. Благодаря правильной установке стоп-приказов мы минимизировали просадку.
  5. Мы не прибегали к помощи технических индикаторов, а создали советника исключительно на чтении "голого" графика.

Спасибо за внимание, надеюсь, статья оказалась полезной.

Прикрепленные файлы |
insidebar.mq4 (19.53 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (38)
Dina Paches
Dina Paches | 15 авг 2015 в 21:07
azfaraon

Наглядность не лишняя, согласна с вами.

На всякий случай скажу, что у Артёма в профиле, через его раздел "Продавец" можно выйти на, в т.ч., бесплатные индикаторы, которые рисуют и такие патерны по своим свойствам в составе.

Как минимум, три бесплатных с такими патернами в их составе насчитала у Артёма опубликованными.

Monopolist05
Monopolist05 | 26 мар 2016 в 22:55
Ребята а подскажите молодому и не опытному )) как вообще этот файл синхронизировать с MT4 и как им пользоваться ? 
Alexandr Saprykin
Alexandr Saprykin | 27 мар 2016 в 15:59
Monopolist05:
Ребята а подскажите молодому и не опытному )) как вообще этот файл синхронизировать с MT4 и как им пользоваться ? 

Сначала копилировать https://www.metatrader5.com/ru/metaeditor/help/development/compile затем добавить в каталог данных вашего терминала:

  1. Чтобы попасть в каталог данных, в терминале нажимаем Файл ->Открыть каталог данных
  2. Скачиваем архив с индикатором, распаковываем его и получаем файл ex4 и/или mql. Эти файлы нужно скопировать в папку MQL4/Indicators (если индикатор) или MQL4/Experts (если советник)  в каталоге данных вашего терминала. Откроется папка, в ней мы заходим в раздел MQL4 в каталог Indicators. И туда копируем файлы наших индикаторов. Закрываем папку,перезапускаем МТ4. 

  3. Перезапускаем MT4, открываем график валюты, на который хотим установить индикатор.
  4. Вверху терминала жмем Вставка->Индикаторы->Пользовательский и выбираем название установленного индикатора/советника
Monopolist05
Monopolist05 | 27 мар 2016 в 22:07
Alexandr Saprykin:

Сначала копилировать https://www.metatrader5.com/ru/metaeditor/help/development/compile затем добавить в каталог данных вашего терминала:

  1. Чтобы попасть в каталог данных, в терминале нажимаем Файл ->Открыть каталог данных
  2. Скачиваем архив с индикатором, распаковываем его и получаем файл ex4 и/или mql. Эти файлы нужно скопировать в папку MQL4/Indicators (если индикатор) или MQL4/Experts (если советник)  в каталоге данных вашего терминала. Откроется папка, в ней мы заходим в раздел MQL4 в каталог Indicators. И туда копируем файлы наших индикаторов. Закрываем папку,перезапускаем МТ4. 

  3. Перезапускаем MT4, открываем график валюты, на который хотим установить индикатор.
  4. Вверху терминала жмем Вставка->Индикаторы->Пользовательский и выбираем название установленного индикатора/советника
Спасибо большое за развернутый ответ ! дай Бог вам нереального профита )))
Roman Vashchilin
Roman Vashchilin | 23 фев 2017 в 17:22
Movlat Baghiyev:
Ну вы и вундеркинд)))
Да так то не особо сложно их заметить, главное тут практика, попялиться в монитор пару недель, с наглядным примером допусти вот этой картинкой и научитесь их определять на глаз так сказать.))



Поиск условий входа в рынок с помощью поддержки, сопротивления и ценового действия Поиск условий входа в рынок с помощью поддержки, сопротивления и ценового действия

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

Статистическая проверка системы управления капиталом Лябушера Статистическая проверка системы управления капиталом Лябушера

В статье приводится проверка статистических свойств системы управления капиталом Лябушера, являющейся менее агрессивной разновидностью Мартингейла и предполагающей повышение ставок не в 2 раза, а на определенную величину.

Управление терминалом MetaTrader с помощью DLL Управление терминалом MetaTrader с помощью DLL

В данной статье рассматривается управление элементами интерфейса MetaTrader с использованием вспомогательной DLL-библиотеки на примере изменения настроек рассылки Push-сообщений. К статье приложен исходный код библиотеки и пример скрипта.

Оценка эффективности торговых систем путем анализа их компонентов Оценка эффективности торговых систем путем анализа их компонентов

В данной статье исследуется эффективность составных торговых систем путем анализа эффективности отдельных ее компонентов. Любой анализ, будь то графический, на основе индикаторов или какой-то другой, является одной из ключевых составляющих успешной торговли на финансовых рынках. Эта статья — своего рода исследование нескольких независимых простых торговых систем, анализ их эффективности и полезности совместного применения.