Автоматическое построение линий поддержки и сопротивления
Введение
В этой статье мы рассмотрим автоматическое построение линий поддержки и сопротивлений. Технический анализ валютных инструментов — важная часть торговли на финансовых рынках. Поэтому автоматическое построение этих линий облегчит работу финансовым аналитикам и трейдерам и даст возможность ускорить технический анализ. Помимо этого, на базе рассмотренного индикатора можно будет создавать автоматические советники.
Поиск всех локальных максимумов и минимумов
Линии поддержки и сопротивления строятся через локальные максимумы и минимумы ценовых графиков. Для определения этих экстремумов мы будем применять всем известный индикатор ZigZag. В его входных параметрах можно задать необходимые свойства для линий поддержки и сопротивления.
Масштаб линий можно изменять с помощью параметров индикатора ZigZag, но можно применять на разных таймфреймах и одинаковые параметры. Это даст возможность получить нужные нам экстремумы, чтобы потом строить по ним уровни поддержки и сопротивления.
На рисунках ниже продемонстрировано, как меняется характер вершин при смене таймфрейма. На первом рисунке показан 30-минутный минутный график, а затем — 4-часовой.
Отбор подходящих экстремумов для построения уровней
Будем строить только те линии поддержки и сопротивления, которые проходят вблизи от текущей цены — а значит, будут актуальными для нас в плане технического анализа на данный конкретный момент. Также, чтобы линии имели сходящийся к цене наклон, используем те экстремумы, каждый из которых выше или равен предыдущему для линий сопротивления — при нисходящем тренде, или ниже или равен предыдущему — при восходящем. По первому рисунку это могут быть точки 1-2-3-4-5-7, а по второму — 1-2-3-6-7-8.
Мы определились с критериями отбора экстремумов. Теперь рассмотрим реализацию в виде кода. Продемонстрируем его здесь лишь частично, чтобы разъяснить основные моменты.
//+------------------------------------------------------------------+ struct trade_points // Определяем структуру для эктремумов { double price; // Цена int pos; // Расположение, номер бара bool hpoint; // Если да, то это максимум bool lpoint; // Если да, то это минимум };
В функции OnInit() создаем хэндл индикатора ZigZag:
int OnInit() { ZZ_handle=iCustom(_Symbol,_Period,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep); return(INIT_SUCCEEDED); }
Далее, перебирая поочередно все экстремумы индикатора Zigzag, заносим информацию о них в матрицу:
double max=close[1]; double min=close[1]; int z=0; for(shift=0;shift<rates_total && !IsStopped();shift++) { CopyBuffer(ZZ_handle,0,shift,1,ZigzagBuffer); if(ZigzagBuffer[0]>0) { if(ZigzagBuffer[0]>=max && ZigzagBuffer[0]==high[shift]) { ArrayResize(mass,z+1); max=ZigzagBuffer[0]; mass[z].price=ZigzagBuffer[0]; mass[z].pos=shift; mass[z].hpoint=true; mass[z].lpoint=false; z++; } if(ZigzagBuffer[0]<=min && ZigzagBuffer[0]==low[shift]) { ArrayResize(mass,z+1); min=ZigzagBuffer[0]; mass[z].price=ZigzagBuffer[0]; mass[z].pos=shift; mass[z].lpoint=true; mass[z].hpoint=false; z++; } } }
Определение критериев для построения трендовых линий
Теперь сформировав массив с вершинами, мы можем строить нужные нам линии поддержки и сопротивления. Определение основных критериев для построения линий разъяснено на рисунке ниже.
Начиная с точки 1, мы можем построить линии через любую из последующих точек. Но не все такие линии можно считать линиями поддержки и сопротивления. Или же они могут быть неактуальными на данный момент и будут не нужны нам на графике. Для нас удобнее, чтобы на графике не было лишних построений, поэтому сделаем перебор и отфильтруем лишние линии.
Будем считать, что начальная точка линии — А, вторая вершина — Б, и точка, находящаяся возле последнего бара, — С.
Критериев может быть много, в различных ситуациях они разные. Рассмотрим здесь только основные. В дальнейшем каждый желающий сможет усовершенствовать этот индикатор по своему усмотрению. Итак, основные критерии:
- Соотношение расстояний АБ и БС
- Количество пересечений ценой отрезка АБ
- Количество пересечений ценой отрезка БС
- Расстояние от С до текущей цены
- Минимальная и максимальная длина линии
- Наклон линии
- Нахождение цены выше или ниже линии сопротивления
Рассмотрим перечисленные критерии более детально, чтобы лучше понять настройку входных параметров.
- Для соблюдения допустимых пропорций можно воспользоваться коэффициентами Фибоначчи и принять минимально допустимым соотношение не менее 0,25 или 0,382. В соответствии с данным критерием, отношения длин должны соответствовать условию АБ/АС>=02.25 (0.382) и БС/АС>=02.25 (0.382). Для удобства значение этого параметра можно будет задавать во входных настройках.
- По количеству пересечений ценой отрезка линии АБ также нужно тщательно фильтровать все имеющиеся линии. Есть много вариантов того, как проводить такую проверку. Можно учитывать только бары, которые закрылись, пробив данную линию, а можно учитывать пробитие по ценам High или Low. Второй критерий этой проверки — количество баров, которые пересекли этот отрезок линии. Эти параметры тоже вынесены во входные настройки.
- По количеству пробоев, их характеру и положению текущей цены относительно участка БС можно судить о важности линии. Все перечисленные критерии можно использовать как для формирования линии, так и для формирования торговых стратегий при создании автоматических советников. В данном индикаторе мы будем отображать лишь линии, которые еще не пересекали данный отрезок.
- Расстояние от текущей цены до линии в первую очередь может фильтроваться из соображений того, актуальна ли сейчас для нас эта линия. К примеру, можно строить только линии, расстояние до которых не более 50 — 100 пунктов.
- Минимальная длина линии в нашем случае определяется входными параметрами индикатора ZigZag, но при необходимости этот параметр также можно контролировать. В индикаторе будут проверяться минимальные длины отрезков АБ и БС.
- Так как линии поддержки более значимые, потому что по ним открываются позиции, то индикатор будет строить для восходящего тренда линии с нулевым или положительным наклоном, а для нисходящего — с нулевым или отрицательным.
- Мы можем использовать линии двумя путями. Первый — учитывать только непробитые линии и торговать в направлении тренда. Второй — использовать только пробой трендовых линий для открытия сделок в обратном направлении. Оба типа линий важны, поэтому оба они будут отражаться в индикаторе.
Ниже показана часть кода, где формируются линии сопротивления нисходящих трендов.
// Определение соответствия линий нашим критериям с последующим заполнением матрицы для нисходящего тренда. for(j=z-1; j>=0; j--) { if(mass[j].hpoint) for(i=j-1; i>=0; i--) { if(mass[i].hpoint) if(i<j) { a=mass[j].pos; b=mass[i].pos; double ratio=double((a-b)*100/a); // Определяем соотношение длины отрезка АБ к общей длине АС if(ratio>fibo && ratio<(100-fibo)) // Определяем, выполняется ли критерий №1, соотношениие участков АБ и БС if(b>Min_dist &&(a-b)>Min_dist) // Определяем, выполняется ли критерий №5, минимальная длина отрезков АБ и БС { ax=mass[j].price; bx=mass[i].price; coef=(ax-bx)/(a-b); price=close[1]; deviation=(ax+coef*bx)-price; cross_bc=0; cross_ab=0; if(MathAbs(deviation)<tolerance*_Point) // Определяем выполнение критерия №4 (Расстояние от т.С до цены закрытия предыдущего бара) { // Количество пересечений от точки a до точки b for(int n=a; n>b; n--) if((close[n]-(ax+coef*(b-n)))>0) cross_ab++; // Количество пересечений от точки b до конца for(int n=b-1; n>=0; n--) if(close[n]>(bx+coef*(b-n)) && close[n+1]<(bx+coef*(b-n+1))) cross_bc++; if(cross_bc<=Intersection_bc && cross_bc<=Intersection_ab)// Определяем, выполняется ли критерий №2 и №3 { // Заполнение матрицы для нисходящего тренда ArrayResize(DownTrend,y+1); DownTrend[y].a=a; DownTrend[y].b=b; DownTrend[y].ax=ax; DownTrend[y].bx=bx; DownTrend[y].dst=MathAbs(deviation); DownTrend[y].coef=coef; y++; } } } } } } // По полученному массиву нисходящих линий отображаем их на графике for(j=0; j<ArraySize(DownTrend); j++) { a=DownTrend[j].a; b=DownTrend[j].b; ax=DownTrend[j].ax; bx=DownTrend[j].bx; coef=DownTrend[j].coef; if(a>0 && b>0 && MathAbs(a-b)>0) { if(a>0 && b>0 && MathAbs(a-b)>0) { //--- создадим линии тренда TrendCreate(0,"DownTrend "+string(j),0,time[a],ax,time[b],bx,DColor,DStyle,DWidth,DBack,DSelection,DRayLeft,DRayRight,DHidden,DZOrder); ChartRedraw(); } }
Примеры построения индикатора:
Использование линий поддержки и сопротивления в торговле
Основной принцип торговли с применением уровней поддержки и сопротивления состоит в том, чтобы покупать вблизи линии поддержки на восходящем тренде (и продавать при понижающемся) или на флэте. Используются и некоторые графические модели (паттерны).
Такая торговая стратегия позволяет воспользоваться трендовым движением, даже когда финансовый инструмент находится во флэте, или же когда цена формирует какую-либо фигуру. Тренд помогает определять направление, в котором необходимо открывать сделки. К примеру, если текущий тренд нисходящий, но затем переходит во флэт, то предпочтительнее открывать сделки на продажу вблизи линии сопротивления, а не покупать на уровне поддержки. Присутствие понижающегося тренда означает, что сделки на продажу имеют больше шансов на успех, чем сделки на покупку. Если тренд восходящий, а после него формируется треугольник, тогда лучше открывать сделки на покупку возле линии поддержки этого треугольника.
Открытие сделок по тренду вблизи линий поддержки и сопротивления может принести прибыль, однако цена часто пробивает эти уровни. Поэтому нужно дождаться подтверждения значимости этого уровня по конкретному финансовому инструменту. Перед тем как покупать или продавать на линии, необходимо дождаться консолидации цены возле нее. Как вариант, можно подождать отскока цены от уровня, и открывать сделку только после этого.
При открытии сделок на покупку от линии поддержки рекомендуется дождаться консолидации цены возле нее, и только после этого открывать ордер на покупку, когда цена пробьет вверх High этой зоны консолидации. Это дает возможность убедиться в том, что уровень действительно влияет на цену, а также в том, что цена начинает двигаться в нужном нам направлении (идти вверх) от этого уровня. Это как раз то, что нам нужно для покупки. Аналогичная ситуация складывается при открытии сделок на продажу от линии сопротивления: необходимо дождаться появления консолидации возле зоны сопротивления, и лишь потом открывать сделку, когда цена опустится ниже Low этой зоны консолидации.
Открывая сделку, нужно заранее спрогнозировать условия ее закрытия. При открытии сделки на покупку от линии поддержки желательно закрывать сделку перед тем, как цена достигнет сильной линии сопротивления. Аналогичная ситуация складывается при открытии сделки на продажу. Можно также закрывать сделки на второстепенных уровнях поддержки и сопротивления. При покупке на линии поддержки нужно продать на уровне сопротивления в повышающемся трендовом канале. Но можно также попробовать получить более крупную прибыль, если дать цене пробить уровень. Например, при покупке от уровня поддержки в треугольнике (при общем повышающемся тренде) можно удерживать позицию, пока цена не пробьет треугольник и не продолжит движение вверх. После этого можно выйти из сделки на следующей линии сопротивления.
Советник на основе индикатора
Ниже представлен советник, имеющий следующие функции:
- StopLoss и TakeProfit
- Максимальное количество Buy/Sell ордеров
- Trailing Stop
- Функция безубытка
- Закрытие встречных сделок по сигналам индикатора
- 4 HTF-фильтра (MACD, RSI, WPR, MA) с возможностью выбора
Советник работает непосредственно с трендовыми линиями, созданными индикатором, поэтому для его работы в реальном времени надо добавить индикатор на график с установленным советником. Настройки, касающиеся индикатора, нужно устанавливать в самом индикаторе. В советнике тоже есть настройки индикатора, но они используются лишь при тестировании. Чтобы можно было тестировать советник, в коде создан хэндл на индикатор, который определяется при инициализации советника.
Предусмотрены 3 режима работы советника:
- from level — торговля на отражение цены от трендовой линии. Сделка открывается, если минимальная или максимальная цена бара пересекла уровень, цена закрытия не пробила текущую трендовую линию, а также цена следующего бара закрылась, не пробив линии. Происходит проверка на пробой ценой линии после касания.
- level breakdown — торговля на пробое ценой трендовой линии. Сделка открывается, если минимальная или максимальная цена бара пересекла уровень, цена закрытия не пробила текущую трендовую линию, а свеча следующего бара закрылась, пробив трендовую линию.
- all — используются оба вышеописанных режима.
Ниже представлена функция в коде, где формируются сигналы на покупку и продажу:
//+------------------------------------------------------------------+ int signal() { int res=0; int macd=0; int rsi=0; int wpr=0; int ma=0; if(Use_macd==true)macd=macdS(); if(Use_rsi==true)rsi=rsiS(); if(Use_wpr==true)wpr=wprS(); if(Use_ma==true)ma=maS(); CopyOpen(NULL,0,1,3,O); CopyHigh(NULL,0,1,3,H); CopyLow(NULL,0,1,3,L); CopyClose(NULL,0,1,3,C); Signals=0; for(int i=0;i<ObjectsTotal(0,0,OBJ_TREND);i++) { string sName=ObjectName(0,i,0,OBJ_TREND); if(StringFind(sName,"UpTrend")==0 || StringFind(sName,"DownTrend")==0) { ax=ObjectGetDouble(0,sName,OBJPROP_PRICE,0); bx=ObjectGetDouble(0,sName,OBJPROP_PRICE,1); p1=(int)ObjectGetInteger(0,sName,OBJPROP_TIME,0); p2=(int)ObjectGetInteger(0,sName,OBJPROP_TIME,1); a=iBarShift(p1); b=iBarShift(p2); kkk=(bx-ax)/(a-b); lvl=bx+kkk*b; plvl=bx+kkk*(b-1); if(mode==0 || mode==2) { if(StringFind(sName,"UpTrend")==0 && L[1]<=plvl && C[1]>plvl && C[0]>lvl)Signals=1; if(StringFind(sName,"DownTrend")==0 && H[1]>=plvl && C[1]<plvl && C[0]<lvl)Signals=2; } if(mode==1 || mode==2) { if(StringFind(sName,"UpTrend")==0 && L[1]<=plvl && C[1]>plvl && C[0]<lvl)Signals=2; if(StringFind(sName,"DownTrend")==0 && H[1]>=plvl && C[1]<plvl && C[0]>lvl)Signals=1; } } } if(Signals==1 &&(macd==1 || Use_macd==false) && (rsi==1 || Use_rsi==false) && (wpr==1 || Use_wpr==false) && (ma==1 || Use_ma==false))res=1; if(Signals==2 &&(macd==2 || Use_macd==false) && (rsi==2 || Use_rsi==false) && (wpr==2 || Use_wpr==false) && (ma==2 || Use_ma==false))res=2; return(res); } //+------------------------------------------------------------------+
При тестировании удалось определить, что прибыльность торговли на отскок от линии менее прибыльная, чем торговля по пробитию уровней.
Ниже представлены графики тестирования трех режимов со следующими входными параметрами:
input string s="-------------------------------------------"; // Main settings input int Magic=12345; input double LotSize=0.1; input int Slippage=30; //Slippage, points input int StopLoss=0; //StopLoss, points input int TakeProfit=0; //TakeProfit, points input int TrailingStart=0; //Trailing Start, points input int TrailingStop= 0; //Trailing Stop, points input int TrailingStep= 0; //Trailing Step, points input int SL_prof=0; //Start BE, points input int SL_lev=0; //BE level, points input int Buy_max=1; //Max Buy orders input int Sell_max=1; //Max Sell orders input bool Sig_close=true; //Close counter transactions input tip mode=0; input string s0="-------------------------------------------"; // Indicators settings input int _ExtDepth=12; input int _ExtDeviation=5; input int _ExtBackstep=3; input int _Min_dist=0; // Minimum distance input int _fibo=30; // Fibo ratio input int _tolerance=200; // Tolerance input int _Intersection_ab=1; // The allowed number of intersections from point a to point b input int _Intersection_bc=1; // The allowed number of intersections from point b to point c input string s1="-------------------------------------------"; // MACD settings input ENUM_TIMEFRAMES macd_tf=PERIOD_CURRENT; // period input int fast_ema_period=12; // period of fast ma input int slow_ema_period=26; // period of slow ma input int signal_period=9; // period of averaging of difference input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE; // type of price input string s2="-------------------------------------------"; // RSI settings input ENUM_TIMEFRAMES rsi_tf=PERIOD_CURRENT; // period input int rsi_period=14; // period input ENUM_APPLIED_PRICE rsi_applied_price=PRICE_CLOSE; // type of price input double rsi_max_s=100; // max price for Sell input double rsi_min_s=70; // min price for Sell input double rsi_max_b=30; // max price for Buy input double rsi_min_b=0; // min price for Buy input string s3="-------------------------------------------"; // WPR settings input ENUM_TIMEFRAMES wpr_tf=PERIOD_CURRENT; // period input int calc_period=14; // period input double wpr_max_s=0; // max price for Sell input double wpr_min_s=-20; // min price for Sell input double wpr_max_b=-80; // max price for Buy input double wpr_min_b=-100; // min price for Buy input string s4="-------------------------------------------"; // MA settings input ENUM_TIMEFRAMES ma_tf=PERIOD_CURRENT; // period input int ma_period=10; // period of MA input int ma_shift=0; // shift input ENUM_MA_METHOD ma_method=MODE_SMA; // type of smoothing input ENUM_APPLIED_PRICE ma_applied_price=PRICE_CLOSE; // type of price input bool Use_macd=true; // Use MACD as a filter input bool Use_rsi=false; // Use RSI as a filter input bool Use_wpr=false; // Use WPR as a filter input bool Use_ma=false; // Use MA as a filter input int sbar=1; // Signal bar 0-current, 1-close
При тестировании открывалась только одна сделка размером 0.1 лота в одном из направлений. При встречном сигнале закрывалась текущая сделка и открывалась противоположная ей. Применялся фильтр по индикатору MACD, при котором сделки на покупку открывались при значениях индикатора меньше нуля, а на продажу — выше нуля. Тестирование делалось на временном интервале 1 час по EURUSD за 2015-2017 гг.
Режим from level:
Режим level breakdown:
Ниже приведены результаты теста с настройками по умолчанию на нескольких валютных парах.
Здесь видно, что хорошие результаты показаны только по EURUSD и USDCHF. В первую очередь это связано с тем, что не все линии нужно учитывать при торговле. Также нужно учитывать другие факторы, перечисленные в начале статьи.
Кроме того, нужно помнить о влиянии фундаментального анализа, так как прохождение линий поддержки/сопротивления очень часто происходит после выхода важных новостей.
Поэтому в советник можно добавить фильтр новостей и протестировать работу только в моменты выхода новостей и при полном запрете работы на выходе новостей. Как альтернатива, данный советник можно применять на РЕНКО-графиках.
Оптимизация
Первые семь параметров, на мой взгляд, изначально в советнике установлены оптимально, и их оптимизацию далее я не делал. А вот параметры по индикатору Зиг-Заг установлены по умолчанию и нам немного не подходят. При оптимизации удалось установить, что наиболее подходящие для всех ранее протестированных валют — следующие значения параметров:
- _ExtDepth=24;
- _ExtDeviation=55;
- _ExtBackstep=9;
Для открытия сделок при оптимизации определялось, какой из режимов работы более подходит для конкретного финансового инструмента, а также насколько влияет на результат использование фильтра. В роли фильтра использовался только индикатор MACD. Но можно пробовать работать и с любыми другими индикаторами на различных таймфреймах.
Для закрытия прибыльной или убыточной сделки использовалась функция закрытия встречным сигналом. Чтобы зафиксировать прибыль и получить максимальный результат, использовались функции безубытка и установки тейк-профита. Оптимальные параметры для каждой валюты по этим функциям определялись в процессе тестирования.
Стоп-лосс для фиксации убытка не использовался, а убыточные сделки закрывались только по встречному сигналу.
Процесс оптимизации отображен в таблице. Тестирование проводилось с размером лота 0.1 за 2017 год. Также было увеличено количество открытых сделок на покупку и продажу до 10, все остальные параметры были настроены по умолчанию.
Символ | Режим |
MACD фильтр | TakeProfit |
Start BE |
Прибыль |
Profit Factor: | Recovery Factor: |
Max DD,% |
Total Trades: | Profit Trades,% |
---|---|---|---|---|---|---|---|---|---|---|
EURUSD |
level breakdown |
false |
0 |
25 |
117.20 |
1.88 |
1.65 |
0.69 |
79 |
73.42 |
USDCHF |
level breakdown | false | 20 |
10 |
135.24 |
1.31 |
1.12 |
1.03 |
482 |
72.41 |
GBPCHF |
from level |
true |
20 |
10 |
91.56 |
1.39 |
0.51 |
1.58 |
246 |
91.06 |
AUDUSD |
level breakdown | false | 20 |
10 |
139.20 |
1.39 |
1.66 |
0.79 |
485 |
71.96 |
AUDCAD |
level breakdown | true | 25 |
5 |
117.51 |
1.94 |
1.06 |
0.57 |
246 |
84.96 |
EURJPY |
level breakdown | false | 20 |
5 |
128.90 |
1.60 |
0.98 |
1.26 |
341 |
78.89 |
GBPUSD |
from level | false | 100 |
0 |
102.1 |
1.20 |
1.32 |
0.58 |
274 |
52.92 |
USDJPY |
from level | false | 30 |
0 |
147.75 |
1.56 |
0.79 |
1.73 |
348 |
79.89 |
EURGBP |
from level | true | 20 |
5 |
124.45 |
1.39 |
1.14 |
1.03 |
341 |
78.01 |
EURCHF |
from level | true | 20 |
5 |
141.08 |
2.07 |
1.88 |
0.68 |
367 |
63.22 |
USDCAD |
level breakdown | false |
100 |
25 |
142.57 |
1.46 |
0.45 |
1.22 |
248 |
78.87 |
NZDUSD |
from level | false | 0 |
25 |
270.50 |
1.37 |
1.04 |
2.37 |
616 |
62.11 |
GBPJPY |
level breakdown | true | 150 |
20 |
163.62 |
2.56 |
1.10 |
1.41 |
103 |
68.25 |
Заключение
В статье продемонстрирован базовый принцип автоматического построения линий поддержки и сопротивления. На его основе создан торговый советник и произведена оптимизация входных параметров на 13 финансовых инструментах. Для получения максимального результата по конкретному финансовому инструменту нужно индивидуально подбирать его оптимальные параметры. Чтобы подобрать оптимальные параметры, автоматизировать торговлю и проверить работу по линиям поддержки и сопротивления, и был сделан советник, имеющий ряд основных функций и 4 HTF-фильтра. В дальнейшем индикатор и советник можно расширить и модернизировать, в зависимости от конкретных потребностей.
По итогам работы было определено, что по некоторым валютам торговля на отскок менее прибыльная, чем торговля на пробой. Это говорит о том, что характер движения различных финансовых инструментов непохож и к каждому нужен индивидуальный подход.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Цитирую: "Линии поддержки и сопротивления строятся через локальные максимумы и минимумы ценовых графиков" и добавляем от меня, например, "за последние 120 минут". Весь остальной текст можно выкидывать, и про ZigZag, и про MACD и т.д. Упрощайте схему. 100 индикаторов - это как 100 человек, несущих вместе одно ведро с водой, нести в сто раз быстрее не получится. Даже если Вы меня послушаетесь, Вы получите всего лишь индикатор ВВ.
Несколько лет назад пришёл к тому, что нужно строить по телам[Open <> Close], а не [High <> Low]