Паттерны, доступные при торговле корзинами валют. Часть II
Введение
В предыдущей статье о паттернах, возникающих при торговле корзинами валют, все внимание было посвящено объединенным индикаторам на базе осцилляторов. Примером нам послужил объединенный индикатор Williams’Percent Range. В итоге мы получили несколько паттернов, рассмотрели их плюсы и минусы, сделали выводы о применимости каждого из них в реальной торговле.
Однако проделанной работы недостаточно. Объединенные индикаторы на основе осцилляторов не могут перекрыть всех потребностей трейдера в техническом анализе состояния валют корзин. Трейдерский набор нужно пополнить трендовыми объединенными индикаторами, которые имеют свои собственные паттерны. Только исследовав их, мы сможем сказать, что познакомились действительно со всеми основными видами паттернов и ничего не упустили. Это должно сделать набор технических средств вполне завершенным.
Для решения поставленной задачи создадим тестовый индикатор. Мы уже выполняли эту задачу, так что можем использовать код из предыдущей статьи с минимальными изменениями. Но предварительно не помешает напомнить о некоторых специфических особенностях трендовых объединенных индикаторов. Здесь и далее будем использовать уже знакомую читателю терминологию из предыдущих статей.
Особенности трендовых объединенных индикаторов
Трендовые объединенные индикаторы не могут быть построены на основе любого трендового родительского индикатора. На это есть ограничения.
Ограничение № 1. Объединенные индикаторы должны располагаться в отдельном окне. Действительно, в отображении такого индикатора в окне с графиком цены не будет смысла. Это доказывается принципом усреднения, по которому строятся объединенные индикаторы: совершенно непонятно, что они будут отображать в этом случае. Возникнет и проблема с единицами измерения: они будут отличаться от тех, которые имеются на графике. Из всего этого следует, что в качестве родительского индикатора не могут выступать ни скользящие средние, ни лента Боллинджера, ни прочие on chart-индикаторы.
Ограничение № 2. Объединенный индикатор покажет состояние только одной валюты; следовательно, для отображения состояния валютной пары потребуются два объединенных индикатора. Поскольку каждый из них располагается в отдельном окне, то и дополнительных окон нам потребуется два. Причина такого разделения — разница в масштабе. Если объединенные индикаторы на основе осцилляторов всегда изменяются в заранее известных пределах, то с трендовыми это не так. Заранее неизвестны ни максимальное, ни минимальное значения. А значит, ранее описанный подход с применением скользящей средней к разнице между показаниями двух объединенных индикаторов теряет смысл. Подобные совместные вычисления не подходят в случае объединения трендовых индикаторов.
Ограничения на список родительских индикаторов сужают возможности использования трендовых объединенных индикаторов. Например, из всего списка трендовых индикаторов в меню MetaTrader 5 предварительно нам подойдут только ADX и StdDev.
Но это не повод отказываться от решения поставленной задачи. Будем работать с наличным инструментарием, и начнем с уже знакомого нам объединенного трендового индикатора — с индекса валюты корзины.
Индекс валюты корзины со скользящей средней
Напишем тестовый индикатор testIndexMA.mq5, аналогичный описанному в этой статье. Сразу добавим к нему скользящую среднюю:
//| testDistance.mq5 |
//| 2016 MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link "http://www.mql5.com"
#property version "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots 2
input color clr= clrGreen;
input color clrMA = clrMagenta;
input int maperiod = 10; //Period MA
double ind[],ma[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
//int h,h1;
int OnInit()
{
//--- indicator buffers mapping
ArraySetAsSeries(ind,true);
SetIndexBuffer(0,ind);
IndicatorSetString(INDICATOR_SHORTNAME,"testdistance");
IndicatorSetInteger(INDICATOR_DIGITS,2);
PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2);
PlotIndexSetInteger(0,PLOT_LINE_COLOR,clr);
PlotIndexSetString(0,PLOT_LABEL,"_tstdistance_");
ArraySetAsSeries(ma,true);
SetIndexBuffer(1,ma);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE );
PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID );
PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 1 );
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrMA );
PlotIndexSetString (1, PLOT_LABEL, "_tstdistance_MA" );
//---
return(INIT_SUCCEEDED);
}
string pair[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY"};
bool bDirect[]={false,false,false,false,true,true,true};
int iCount=7;
double GetValue(int shift)
{
double res=1.0,t;
double dBuf[1];
for(int i=0; i<iCount; i++)
{
t=CopyClose(pair[i],PERIOD_CURRENT,shift,1,dBuf);
if(!bDirect[i]) dBuf[0]=1/dBuf[0];
res*=dBuf[0];
}//end for (int i = 0; i < iCount; i++)
return (NormalizeDouble(MathPow (res, 1/(double)iCount), _Digits) );
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(prev_calculated==0 || rates_total>prev_calculated+1)
{
int rt=rates_total;
for(int i=1; i<rt; i++)
{
ind[i]= GetValue(i);
}
rt -= maperiod;
for (int i = 1; i< rt; i++)
{
ma[i] = GetMA(ind, i, maperiod, _Digits);
}
}
else
{
ind[0]= GetValue(0);
ma[0] = GetMA(ind, 0, maperiod, _Digits);
}
//--- return value of prev_calculated for next call
return(rates_total);
}
void OnDeinit(const int reason)
{
string text;
switch(reason)
{
case REASON_PROGRAM:
text="Indicator terminated its operation by calling the ExpertRemove() function";break;
case REASON_INITFAILED:
text="This value means that OnInit() handler "+__FILE__+" has returned a nonzero value";break;
case REASON_CLOSE:
text="Terminal has been closed"; break;
case REASON_ACCOUNT:
text="Account was changed";break;
case REASON_CHARTCHANGE:
text="Symbol or timeframe was changed";break;
case REASON_CHARTCLOSE:
text="Chart was closed";break;
case REASON_PARAMETERS:
text="Input-parameter was changed";break;
case REASON_RECOMPILE:
text="Program "+__FILE__+" was recompiled";break;
case REASON_REMOVE:
text="Program "+__FILE__+" was removed from chart";break;
case REASON_TEMPLATE:
text="New template was applied to chart";break;
default:text="Another reason";
}
PrintFormat("%s",text);
}
//+------------------------------------------------------------------+
double GetMA(const double& arr[], int index , int period, int digit) {
double m = 0;
for (int j = 0; j < period; j++) m += arr[index + j];
m /= period;
return (NormalizeDouble(m,digit));
}
bool bDirect[]={true,true,true,true,true,true,true};
Абсолютные значения индикатора нас пока не интересуют. Будем считать точки пересечения графика индикатора с МА точками потенциального входа в рынок. В соответствии с предыдущими статьями, эти точки нужно фиксировать на закрытии свечи, что мы и сделали. Выделим найденные входы вертикальными линиями: синими — на покупку, красными — на продажу. Видно, что есть очевидный положительный результат. Однако профит небольшой и, очевидно, нестабильный, поэтому стоит подумать об увеличении прибыльности. Для начала вспомним о второй валюте пары и добавим на чарт индикатор индекса доллара в отдельном подокне:
Отметим пересечения МА и графика индекса доллара вертикальными линиями. Проанализируем получившуюся картину.
- Пересечение графика индекса одной из валют и МА сигнализирует о возможной перемене тренда с большей вероятностью, если такое же пересечение, но в противоположную сторону, наблюдается у второй валюты пары. Например, в паре EURUSD, если график индекса USD пересекает МА снизу вверх, то график индекса EUR должен пересекать МА сверху вниз. Cитуация сигнализирует об усилении одной валюты с одновременным ослаблением другой.
- Если точки пересечения есть на графиках индекса обеих валют, но они однонаправленные, то от входа в рынок стоит отказаться. Эта ситуация говорит о высокой вероятности возникновения бокового движения.
- Точки пересечения должны быть очевидными, заметными. Этот вопрос мы рассмотрели в предыдущей статье.
Из вышеизложенного можно сделать первый практический вывод: входить в рынок нужно с учетом индекса обеих валют. Лучше всего делать это на одновременном усилении одной валюты с ослаблением другой. Первый "маркер" возникновения такой ситуации — пересечение графика индекса одной из валют пары и МА. Но входить на этом в рынок нельзя: сперва надо дождаться хода второй валюты в противоположном направлении.
Остается открытым вопрос о запаздывании: на каком максимально возможном расстоянии могут отстоять друг от друга точки пересечения графика индекса и МА для двух валют пары? Очевидно, что минимальным (и идеальным) расстоянием будет ноль. По максимальному запаздыванию однозначный ответ дать сложно. Хотя очевидно, что такое расстояние должно присутствовать. Опасно входить в рынок, если ослабление одной валюты и усиление другой будут сильно разнесены во времени. В этом случае мы столкнемся с дивергенцией и, как следствие, с ослаблением тренда.
Итак, мы рассмотрели вопросы входа в рынок на данных трендового объединенного индикатора. Чтобы более точно оценить качество предполагаемой точки входа, перейдем к абсолютным значениям индикатора. Чуть выше в статье мы оставили их "на потом" — настало время обратиться и к ним.
Экспресс-анализ с помощью индикатора ZigZag
Для дальнейшей работы воспользуемся одним из индикаторов на основе ZigZag из этой статьи за авторством уважаемого коллеги Dmitry Fedoseev. Разместим индикатор iUniZigZagPriceSW.mq5 непосредственно на графике индекса USD:
Здесь график ZigZag-a изображен толстой синей линией. Наша цель — проанализировать и систематизировать длину отрезков ZigZag-a. Не исключено, что таким образом мы получим "амплитуду свингов" индекса доллара.
Немного изменим код индикатора:
//| iUniZigZagSW.mq5 |
//| Copyright 2016, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots 3
//--- plot High
#property indicator_label1 "High"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrGreen
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- plot Low
#property indicator_label2 "Low"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrGreen
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- plot ZigZag
#property indicator_label3 "ZigZag"
#property indicator_type3 DRAW_SECTION
#property indicator_color3 clrRed
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
//--- plot Direction
#property indicator_label4 "Direction"
#property indicator_type4 DRAW_LINE
#property indicator_style4 STYLE_SOLID
#property indicator_width4 1
//--- plot LastHighBar
#property indicator_label5 "LastHighBar"
#property indicator_type5 DRAW_LINE
#property indicator_style5 STYLE_SOLID
#property indicator_width5 1
//--- plot LastLowBar
#property indicator_label6 "LastLowBar"
#property indicator_type6 DRAW_LINE
#property indicator_style6 STYLE_SOLID
#property indicator_width6 1
#include <ZigZag\CSorceData.mqh>
#include <ZigZag\CZZDirection.mqh>
#include <ZigZag\CZZDraw.mqh>
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
enum EDirection
{
Dir_NBars=0,
Dir_CCI=1
};
//--- input parameters
input EDirection DirSelect=Dir_NBars;
input int CCIPeriod = 14;
input ENUM_APPLIED_PRICE CCIPrice = PRICE_TYPICAL;
input int ZZPeriod=14;
input string name="index-usd-zz.txt";
CZZDirection*dir;
CZZDraw*zz;
//--- indicator buffers
double HighBuffer[];
double LowBuffer[];
double ZigZagBuffer[];
double DirectionBuffer[];
double LastHighBarBuffer[];
double LastLowBarBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int h;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnInit()
{
switch(DirSelect)
{
case Dir_NBars:
dir=new CNBars(ZZPeriod);
break;
case Dir_CCI:
dir=new CCCIDir(CCIPeriod,CCIPrice);
break;
}
if(!dir.CheckHandle())
{
Alert("Ошибка загрузки индикатора 2");
return(INIT_FAILED);
}
zz=new CSimpleDraw();
//--- indicator buffers mapping
SetIndexBuffer(0,HighBuffer,INDICATOR_DATA);
SetIndexBuffer(1,LowBuffer,INDICATOR_DATA);
SetIndexBuffer(2,ZigZagBuffer,INDICATOR_DATA);
SetIndexBuffer(3,DirectionBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,LastHighBarBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,LastLowBarBuffer,INDICATOR_CALCULATIONS);
h=FileOpen(name,FILE_CSV|FILE_WRITE|FILE_ANSI,',');
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(CheckPointer(dir)==POINTER_DYNAMIC)
{
delete(dir);
}
if(CheckPointer(zz)==POINTER_DYNAMIC)
{
delete(zz);
}
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int ind=0;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[]
)
{
int start;
if(prev_calculated==0)
{
start=0;
}
else
{
start=prev_calculated-1;
}
for(int i=start;i<rates_total;i++)
{
HighBuffer[i]=price[i];
LowBuffer[i]=price[i];
}
int rv;
rv=dir.Calculate(rates_total,
prev_calculated,
HighBuffer,
LowBuffer,
DirectionBuffer);
if(rv==0)return(0);
zz.Calculate(rates_total,
prev_calculated,
HighBuffer,
LowBuffer,
DirectionBuffer,
LastHighBarBuffer,
LastLowBarBuffer,
ZigZagBuffer);
if(ind<= 10) ind++;
if(ind == 10)
{
double mx=0,mn=1000000;
double lg;
for(int i=0;i<rates_total;i++)
{
if(ZigZagBuffer[i]==0 || ZigZagBuffer[i]==EMPTY_VALUE) continue;
if(ZigZagBuffer[i] > mx) mx = ZigZagBuffer[i];
if(ZigZagBuffer[i] < mn) mn = ZigZagBuffer[i];
}
lg=mx-mn;
PrintFormat("Min index: %.05f Max index: %.05f Length: %.05f",mn,mx,lg);
lg/=100;
double levels[100];
int count[100];
ArrayInitialize(count,0);
for(int i=1; i<101; i++) levels[i-1]=NormalizeDouble(lg*i,_Digits);
mn=0;
for(int i=0;i<rates_total;i++)
{
if(ZigZagBuffer[i]==0 || ZigZagBuffer[i]==EMPTY_VALUE) continue;
if(mn==0) mn=ZigZagBuffer[i];
else
{
lg=MathAbs(mn-ZigZagBuffer[i]);
for(int j=0; j<100; j++)
{
if(lg<levels[j])
{
count[j]++;
break;
}
}
mn=ZigZagBuffer[i];
}
}
for(int i=0; i<100; i++)
{
PrintFormat("%d level: %.05f count: %d",i,levels[i],count[i]);
FileWrite(h,i,levels[i],count[i]);
}
FileClose(h);
}
return(rates_total);
}
//+------------------------------------------------------------------+
Номер по порядку | Величина длины отрезков |
Количество отрезков |
---|---|---|
0 |
0.01193 | 2975 |
1 |
0.02387 |
850 |
2 |
0.0358 |
197 |
3 |
0.04773 |
54 |
4 |
0.05967 |
17 |
- Нужно с осторожностью входить в рынок по тренду, когда величина отрезка ZigZag-a, примененного к объединенному индикатору индекса валюты корзины, превышает определенную величину. За величину отрезка здесь принимается длина проекции отрезка индикатора ZigZag на ось цены (то есть, на ось Y).
Разумеется, возникает вопрос о величине такого "критического" отрезка. Определить ее можно, применив к вышеприведенным данным статистические методы. При желании, трейдер может выполнить такой анализ самостоятельно, руководствуясь своими соображениями о допустимом риске. Для себя я принял, что величина "критического" отрезка не должна быть 0.03.
В этом примере мы проанализировали весь период имеющейся истории. Однако чтобы захватить последние, более актуальные движения рынка, правильнее работать с меньшими периодами (год, квартал, месяц).
Анализ, подобный этому, можно выполнить для всех валют корзин и для многих таймфреймов. Было бы интересно пронаблюдать, как при этом будут изменяться диаграммы для разных наборов "валюта — таймфрейм". Разработчик сразу заметит, что при необходимости алгоритм легко можно воспроизвести в коде. Но при этом нельзя забывать прописную истину: не следует ориентироваться только на один сигнал, нужно искать подтверждения. Продемонстрированную методику можно применять и ко многим обычным трендовым индикаторам. А вот в случае осцилляторов она совершенно бессмысленна и результата не даст.
Итак, мы сделали очередной шаг к повышению качества входов в рынок при использовании объединенных индикаторов. Поскольку была упомянута необходимость искать подтверждение сигналам одного индикатора, то этим мы далее и займемся.
Совместное использование различных объединенных индикаторов
Вспомним, что у нас уже есть сконструированный объединенный индикатор на основе WPR. В прошлой статье мы подробно изучили его, его код и доступные паттерны. На этот раз попытаемся применить его в паре с объединенным индикатором индекса. Получившаяся структура должна быть вполне работоспособна, т.к. многие торговые системы строятся именно таким образом: трендовый индикатор + осциллятор.
Итак, возьмем индикаторы testDistance.mq5, testWPR.mq5 и testWPRjpy.mq5 из прошлой статьи и разместим на графике вместе с объединенным индикатором индекса EUR testDistance.mq5. В прошлой статье мы изучали график EURJPY, поэтому индикатор testWPRjpy нужно переписать для работы на USD. Название индикатора сохраним, чтобы не переделывать индикатор testDistance.mq5. Все индикаторы из этого раздела можно найти в архиве wpr.zip.
Индикатор объединенного WPR будет отрисовывать нам разницу между объединенными WPR валют, входящих в нашу валютную пару (все это достаточно подробно описано в исходной статье). Нашей целью будет обнаружение ранее описанных паттернов на одном индикаторе при использовании другого в качестве фильтра:
На изображении отмечены возможные места входа в рынок (не все). Более надежными стоит считать те входы, где индикатор в верхнем (это объединенный WPR) и в нижнем окне (это объединенный индекс евро) демонстрируют нам однонаправленные паттерны. Здесь эти входы обозначены номерами 1 и 6. Это точки пересечения графиков индикатора со скользящей средней.
Интересен вход № 2, т.к. в этом месте объединенный WPR дарит нам просто академический паттерн с пересечением линии перепроданности. Прочие входы не демонстрируют нам достаточного уровня подтверждения. И хотя реальный вход в рынок в оставшихся местах и не привел бы к убыткам, но идти на такую степень риска при реальной торговле я бы не стал.
Насколько правильно использовать объединенный индикатор, отрисовывающий разницу между объединенными WPR, входящими в корзину валют? Не правильнее ли было бы использовать в паре с объединенным индексом евро объединенный WPR для евро? Попробуем это сделать, заменив testDistance.mq5 на testWPR.mq5:
Итак, на этом рисунке в нижнем окне мы видим индикатор объединенного WPR для евро. Оправдано ли его размещение? В данном случае очевидно, что оправдано. Этот индикатор подкорректировал наш вход в точках №№ 2 и 6 на одну свечу (направление указано стрелками). Не слишком уверенно подтвержден вход в точке № 1. Вход в точках № 5 и № 3 не рекомендован. Точку №4 индикатор скорректировал в новую точку № 7.
Казалось бы, эти результаты позволяют сделать вывод о том, что лучше использовать объединенный индикатор WPR валюты корзины, а не тот же индикатор разницы между объединенными WPR для двух валют валютной пары. Но это верно только для данного конкретного случая. Для "повседневного, рабочего" использования я бы не исключал применения обеих форм объединенного осциллятора до тех пор, пока не накопится какая-либо значимая статистика.
Вы можете возразить мне: "А что тут особенного? Совместное применение нескольких индикаторов не новость, зачем об этом специально рассказывать в статье? Да и паттерны здесь ни при чем."
Однако целью данной части статьи было ответить на три вопроса:
- В какой форме правильнее использовать осцилляторы в данном случае?
- Нет ли явных запретов на применение одной из форм?
- Насколько корректно идентифицируются и подтверждаются паттерны при применении различных форм осцилляторов?
В меру наших возможностей ответ был дан. Кроме того, становится ясен способ тестирования сделанных выводов.
Заключение
На этом я заканчиваю описание простейших паттернов, возникающих при торговле корзинами валют. Но следует ли на этом ставить точку на всей теме? Ни в коем случае. Впереди еще много интересных возможностей.
В заключение снова повторю очевидную вещь: Индикаторы, приложенные к статьям, не предназначены для реальной торговли! Они всего лишь демонстрируют ту или иную ситуацию, делают наглядным некий факт. Им очень далеко до стабильной работы.
Программы, используемые в статье:
# | Имя |
Тип |
Описание |
---|---|---|---|
1 | testIndexMA.mq5 | Индикатор | Тестовый объединенный индикатор доллара со скользящей средней. |
2 | testIndexMA2.mq5 | Индикатор | Тестовый объединенный индикатор евро со скользящей средней. |
3 | testIndexZig-Zag1.mq5 | Индикатор | Тестовый индикатор ZigZag с возможностью измерения и протоколирования длины отдельных отрезков. |
4 | testWPR.mq5 | Индикатор | Тестовый объединенный индикатор WPR для евро |
5 | testWPRjpy.mq5 | Индикатор | Тестовый объединенный индикатор WPR для доллара |
6 | testDistance.mq5 | Индикатор | Тестовый объединенный индикатор, отрисовывающий разницу между двумя другими, в данном случае между testWPR.mq5 и testWPRjpy.mq5 (между евро и долларом) |
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования