Price Action. Автоматизация торговли по паттерну "Поглощение"
Введение
Каждый, кто изучает рынок Forex, рано или поздно сталкивается с Price Action. Это не просто методика чтения графиков, это целая система определения возможного направления движения цены. В данной статье мы детально рассмотрим паттерн "Поглощение" и создадим эксперта, который будет отслеживать данный паттерн и на его основании принимать торговые решения.
Ранее мы уже рассматривали автоматизацию торговли по паттернам Price Action, а именно по внутреннему бару, в статье Price Action. Автоматизация торговли по внутреннему бару.
Правила паттерна "Поглощение"
Паттерн "Поглощение" представляет собой бар, тело и тени которого полностью поглощают тело и тени предыдущего бара. Различают два типа паттерна:
- BUOVB (Bullish Outside Vertical Bar) — бычий внешний вертикальный бар;
- BEOVB (Bearish Outside Vertical Bar) — медвежий внешний вертикальный бар.
Рис. 1. Вид паттерна на графике
BUOVB. На графике видно, что максимум внешнего бара выше максимума предыдущего, а минимум внешнего бара ниже минимума предыдущего.
BEOVB. Данный паттерн также несложно определить на графике. Максимум внешнего бара выше максимума предыдущего, а минимум внешнего бара ниже минимума предыдущего.
Различия заключаются в том, что каждый паттерн четко дает понять о возможном направлении движения рынка.
Рис. 2. Конструкция паттерна
Правила паттерна "Поглощение":- Работать с паттерном следует на старших временных графиках: H4, D1.
- Для более точного входа следует применять дополнительные элементы графического анализа: трендовые линии, уровни поддержки/сопротивления, уровни Фибоначчи, другие паттерны Price Action и так далее.
- Во избежание преждевременного или ложного входа в рынок необходимо использовать отложенные ордера.
- Паттерны, повторяющиеся во флэте, не стоит использовать в качестве сигнала к входу в рынок.
Определение точек входа для "BUOVB", установка стоп-приказов
Рис. 3. Установка ордера Buy Stop и стоп-приказов
Рассмотрим правила входа и установки стоп-приказов на примере выше для BUOVB (бычий внешний вертикальный бар):
- Выставляем отложенный ордер Buy Stop по цене чуть выше цены High (на несколько пунктов, для подтверждения) внешнего бара.
- Уровень Stop Loss устанавливаем ниже цены Low внешнего бара.
- Уровень Take Profit устанавливаем, не доходя до ближайшего уровня сопротивления.
Определение точек входа для "BEOVB", установка стоп-приказов
Рис. 4. Установка ордера Sell Stop и стоп-приказов
Рассмотрим правила входа и установки стоп-приказов на примере выше для BEOVB (медвежий внешний вертикальный бар):
- Выставляем отложенный ордер Sell Stop по цене чуть ниже цены Low (на несколько пунктов, для подтверждения) внешнего бара.
- Уровень Stop Loss устанавливаем выше цены High внешнего бара.
- Уровень Take Profit устанавливаем, не доходя до ближайшего уровня поддержки.
Создание советника для торговли по паттерну "Поглощение"
Мы рассмотрели паттерн "Поглощение", научились правильно и безопасно входить в рынок, а также определили уровни стоп-приказов, чтобы ограничить возможные потери или зафиксировать прибыль.
Далее мы постараемся реализовать алгоритмы советника и автоматизировать торговлю по паттерну "Поглощение".
Открываем MetaEditor из терминала MetaTrader 4 и создаем нового советника (на данном моменте останавливаться подробнее не буду, так как на сайте достаточно литературы по созданию советников). На этапе создания оставляем все параметры пустыми. Назвать их можно как угодно. В итоге должно получиться следующее:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_Bar.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
После создания советника необходимо определить паттерн "Поглощение" после закрытия свечи. Для этого мы вводим новые переменные и присваиваем им значения. Смотрите код ниже:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_Bar.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); } //+------------------------------------------------------------------+
Находим оба типа паттерна "Поглощение":
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); //--- Находим медвежий паттерн BEOVB if(low1 < low2 && //Минимум первого бара ниже минимума второго бара high1 > high2 && //Максимум первого бара выше максимума второго close1 < open2 && //Цена закрытия первого бара ниже цены открытия второго open1 > close1 && //Первый бар медвежий open2 < close2) //Второй бар бычий { //--- мы прописали все условия, указывающие, что первый бар полностью поглощает второй и является медвежьим }
Таким же образом находим бычий паттерн:
//--- Находим бычий паттерн BUOVB if(low1 < low2 && //Минимум первого бара ниже минимума второго бара high1 > high2 && //Максимум первого бара выше максимума второго close1 > open2 && //Цена закрытия первого бара выше цены открытия второго open1 < close1 && //Первый бар бычий open2 > close2) //Второй бар медвежий { //--- мы прописали все условия, указывающие, что первый бар полностью поглощает второй и является бычьим }
- Создаем переменные, настраиваемые пользователем: стоп-приказы, проскальзывание, время истечения ордеров, магический номер советника, торговый лот. Стоп-лосс можем не указывать, так как будем устанавливать его по правилам паттерна.
- Вводим локальные переменные для приведения переменных в нормальный вид.
- Кроме того, мы помним, что стоп-приказы устанавливаются на определенном интервале от значений цен бара. Для этого вводим входную переменную Interval, которая отвечает за интервал между ценами минимума/максимума бара и уровнями стоп-приказов, а также ценой установки отложенного ордера.
- Вводим переменную timeBUOVB_BEOVB, отвечающую за предотвращение повторного открытия ордера на данном паттерне.
- Вводим переменную bar1size для проверки, что внешний бар имеет достаточно большой размер. Тем самым, мы можем предположить, что рынок не находится во флэте.
В результате мы получаем следующий код:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_bar.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 = 25; //Interval extern double lot = 0.1; //Lot Size extern int TP = 400; //Take Profit extern int magic = 962231; //Magic number extern int slippage = 2; //Slippage extern int ExpDate = 48; //Expiration Hour Order extern int bar1size = 900; //Bar 1 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 _bar1size; //локальная переменная, необходимая для исключения рынка во флэте datetime timeBUOVB_BEOVB; //время бара, на котором открылись ордера по паттерну, для исключения повторного открытия //+------------------------------------------------------------------+ //| 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); //--- _bar1size=NormalizeDouble(((high1-low1)/_point),0); //--- Находим медвежий паттерн BEOVB if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //на данном паттерне еще не открывались ордера _bar1size>bar1size && //первый бар достаточно большой, чтобы не считать рынок во флэте low1 < low2 && //Минимум первого бара ниже минимума второго бара high1 > high2 && //Максимум первого бара выше максимума второго close1 < open2 && //Цена закрытия первого бара ниже цены открытия второго open1 > close1 && //Первый бар медвежий open2 < close2) //Второй бар бычий { //--- мы прописали все условия, указывающие, что первый бар полностью поглощает второй и является медвежьим timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //указываем, что на данном паттерне уже установлены ордера } //--- Находим бычий паттерн BUOVB if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //на данном паттерне еще не открывались ордера _bar1size>bar1size && //первый бар достаточно большой, чтобы не считать рынок во флэте low1 < low2 && //Минимум первого бара ниже минимума второго бара high1 > high2 && //Максимум первого бара выше максимума второго close1 > open2 && //Цена закрытия первого бара выше цены открытия второго open1 < close1 && //Первый бар бычий open2 > close2) //Второй бар медвежий { //--- мы прописали все условия, указывающие, что первый бар полностью поглощает второй и является бычьим timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //указываем, что на данном паттерне уже установлены ордера } } //+------------------------------------------------------------------+
Определение уровней стоп-приказов
Мы выполнили все условия и нашли качественные паттерны. Теперь необходимо для каждого паттерна определить уровни стоп-приказов и цены установки отложенных ордеров, а также дату истечения ордера.
В теле функции OnTick() пишем следующий код:
//--- Определение цен установки ордеров и цен установки стоп-приказов buyPrice=NormalizeDouble(high1+interval*_point,Digits); //определяем цену установки ордера с учетом интервала buySL=NormalizeDouble(low1-interval*_point,Digits); //определяем стоп-лосс с учетом интервала buyTP=NormalizeDouble(buyPrice+TP*_point,Digits); //определяем тейк-профит _ExpDate=TimeCurrent()+ExpDate*60*60; //расчет времени истечения отложенного ордера //--- Также производим расчет для ордеров на продажу sellPrice=NormalizeDouble(low1-interval*_point,Digits); sellSL=NormalizeDouble(high1+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); } //+------------------------------------------------------------------+
В результате всех действий получаем следующий код:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_bar.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 = 25; //Interval extern double lot = 0.1; //Lot Size extern int TP = 400; //Take Profit extern int magic = 962231; //Magic number extern int slippage = 2; //Slippage extern int ExpDate = 48; //Expiration Hour Order extern int bar1size = 900; //Bar 1 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 _bar1size; //локальная переменная, необходимая для исключения рынка во флэте datetime timeBUOVB_BEOVB; //время бара, на котором открылись ордера по паттерну, для исключения повторного открытия //+------------------------------------------------------------------+ //| 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); //--- Определение цен установки ордеров и цен установки стоп-приказов buyPrice=NormalizeDouble(high1+interval*_point,Digits); //определяем цену установки ордера с учетом интервала buySL=NormalizeDouble(low1-interval*_point,Digits); //определяем стоп-лосс с учетом интервала buyTP=NormalizeDouble(buyPrice+TP*_point,Digits); //определяем тейк-профит _ExpDate=TimeCurrent()+ExpDate*60*60; //расчет времени истечения отложенного ордера //--- Также производим расчет для ордеров на продажу sellPrice=NormalizeDouble(low1-interval*_point,Digits); sellSL=NormalizeDouble(high1+interval*_point,Digits); sellTP=NormalizeDouble(sellPrice-TP*_point,Digits); //--- _bar1size=NormalizeDouble(((high1-low1)/_point),0); //--- Находим медвежий паттерн BEOVB if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //на данном паттерне еще не открывались ордера _bar1size>bar1size && //первый бар достаточно большой, чтобы не считать рынок во флэте low1 < low2 && //Минимум первого бара ниже минимума второго бара high1 > high2 && //Максимум первого бара выше максимума второго close1 < open2 && //Цена закрытия первого бара ниже цены открытия второго open1 > close1 && //Первый бар медвежий open2 < close2) //Второй бар бычий { //--- мы прописали все условия, указывающие, что первый бар полностью поглощает второй и является медвежьим OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue); timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //указываем, что на данном паттерне уже установлены ордера } //--- Находим бычий паттерн BUOVB if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //на данном паттерне еще не открывались ордера _bar1size>bar1size && //первый бар достаточно большой, чтобы не считать рынок во флэте low1 < low2 && //Минимум первого бара ниже минимума второго бара high1 > high2 && //Максимум первого бара выше максимума второго close1 > open2 && //Цена закрытия первого бара выше цены открытия второго open1 < close1 && //Первый бар бычий open2 > close2) //Второй бар медвежий { //--- мы прописали все условия, указывающие, что первый бар полностью поглощает второй и является бычьим OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue); timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //указываем, что на данном паттерне уже установлены ордера } } //+------------------------------------------------------------------+
Проводим компиляцию. Проверяем наличие записей в логе ошибок.
Тестирование советника
Проверяем советника на работоспособность и отсутствие ошибок. Запускаем тестер стратегий и устанавливаем входные параметры.
Рис. 5. Входные параметры для тестирования
- Выбираем валютную пару для тестирования. Я выбрал EURAUD.
- Обязательно выбираем модель тестирования "Все тики", а также указываем, что тестирование будем проводить на исторических данных. Я выбрал за весь 2014 год.
- Указывам период D1.
- Запускаем тестирование.
- После завершения тестирования проверяем журнал. В результате мы видим, что при тестировании не возникало ошибок исполнения.
Вот пример журнала после тестирования:
Рис. 7. Журнал тестирования советника
Убедившись в отсутствии ошибок, проводим оптимизацию советника.
Оптимизация
Для оптимизации советника я выбрал следующие параметры:
Рис. 8. Параметры оптимизации
Рис. 9. Настройка оптимизации
В результате оптимизации и тестирования мы получаем вполне рабочего робота.
Результаты оптимизации и тестирования
Проведя оптимизацию по наиболее популярным валютным парам, получаем следующие результаты:
Валютная пара | Чистая прибыль | Прибыльность | Просадка (%) | Общая прибыль | Общий убыток |
---|---|---|---|---|---|
EURAUD | 523.90$ | 3.70 | 2.13 | 727,98$ | 196.86$ |
USDCHF | 454.19$ | - | 2.25 | 454.19$ | 0.00$ |
GBPUSD | 638.71$ | - | 1.50 | 638.71$ | 0.00$ |
EURUSD | 638.86$ | - | 1.85 | 638.86$ | 0.00$ |
USDJPY | 423.85$ | 5.15 | 2.36 | 525.51$ | 102.08$ |
USDCAD | 198.82$ | 2.41 | 2.74 | 379.08$ | 180.26$ |
AUDUSD | 136.14$ | 1.67 | 2.39 | 339.26$ | 203.12$ |
Таб. 1. Результаты оптимизации
Более подробные результаты тестирования на валютной паре EURAUD:
Рис. 10. Результаты тестирования
Рис. 11. График результатов тестирования
Заключение
- В рамках данной статьи мы создали рабочего советника, торгующего по паттерну "Поглощение".
- Мы убедились, что даже не имея дополнительных фильтров для входа в рынок, паттерны Price Action работают.
- Мы доказали работоспособность, не прибегая к хитростям и уловкам, таким как Мартингейл, усреднение и так далее.
- Благодаря правильной установке стоп-приказов мы минимизировали просадку.
- Мы не прибегали к помощи технических индикаторов, а создали советника исключительно на чтении "голого" графика.
Спасибо за внимание, надеюсь, статья оказалась полезной.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Спасибо Дмитрий за интересную и познавательную статью, все разжевано и объяснено как для начинающих изучать Price Action. Единственно, скачал файл советника, откомпилировался без ошибок, но при прогонах ни одного выставленного ордера, а при оптимизации все результаты по нолям.
Здравствуйте!
Проверьте настройки оптимизации, а так же параметры валютной пары, на которой тестируете советника. Возможно Вы указали слишком большие размеры бара. Так же учтите, что в примере нет преобразований 5-ти в 4-х значные котировки.
Здравствуйте!
Проверьте настройки оптимизации, а так же параметры валютной пары, на которой тестируете советника. Возможно Вы указали слишком большие размеры бара. Так же учтите, что в примере нет преобразований 5-ти в 4-х значные котировки.
Дмитрий, скажите а индикатор есть, не советни, а просто индикатор, который бы стрелкой и алертом показывал вход. Если можно скиньте в лс. Спасибо.
Дмитрий, скажите а индикатор есть, не советни, а просто индикатор, который бы стрелкой и алертом показывал вход. Если можно скиньте в лс. Спасибо.
Мне кажется стоило бы учесть возможность получения ложных сигналов в середине или, что еще неприятнее, в конце тренда. А именно такие ситуации встречаются на больших TF: идет уверенное движение вниз, одна из свечей делает небольшой откат, а следующая продолжает движение по тренду - вот вам и медвежий паттерн, однако сие может быть и окончанием тренда зачем нам нужен лишний "лось"?
Думаю стоит проверить пару свечей назад для определения значимости и наличия вершины.
С Александром полностью согласен. Я создал робота по этой идеи и сливает на всех тайфреймах. на М30 лучше всего себя проявил, он увы. Очень много ложный таких паттеров. и как от них избавиться не представляю.
С Александром полностью согласен. Я создал робота по этой идеи и сливает на всех тайфреймах. на М30 лучше всего себя проявил, он увы. Очень много ложный таких паттеров. и как от них избавиться не представляю.