English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Построение мультивалютного индикатора с применением множества промежуточных индикаторных буферов

Построение мультивалютного индикатора с применением множества промежуточных индикаторных буферов

MetaTrader 5Индикаторы | 17 мая 2010, 13:07
11 518 19
Alexey Klenov
Alexey Klenov

Введение

Все началось с того, что я первый раз услышал о кластерных индикаторах из статьи "Теоретические основы построения кластерных индикаторов для рынка FOREX". Тогда меня это очень заинтересовало, и я решил написать нечто подобное в плане мультивалютного анализа рынка. Сначала реализовал свою версию индикатора под кодовым названием MultiCurrencyIndex, в котором по рассчитанным значениям индексов валют происходил расчет классических индикаторов (RSI, MACD, CCI).

А сейчас расскажу, как я перевел данный индикатор на новую платформу MetaTrader 5 в комплекте с MQL5, за исключением того, что вместо расчета CCI буду рассчитывать индикатор стохастический осциллятор (Stochastic Oscillator), как более перспективный (на мой взгляд).

Для начала несколько определений.

Индекс доллара - значение типа double рассчитанное по формуле, любезно предоставленной мне Neutron

,

где USD/YYY - все прямые котировки, типа USD/CHF, XXX/USD - все обратные, типа EUR/USD.

Остальные индексы  валют рассчитываются из значений Close валютных пар, содержащие в себе USD.

Основные линии - две линии индикатора, отражающие расчетные данные, относящиеся непосредственно к текущему графику. К примеру, на графике EURUSD это будут линии валют EUR и USD.

Вспомогательные линии - остальные рассчитанные линии индикатора, не относящиеся к текущему графику. К примеру, для того же графика EURUSD это будут линии валют GBP, CHF, JPY ,CAD, AUD и NZD.

Close - значение цены закрытия бара текущего таймфрейма (тип double) для необходимой валютной пары.

Итак, начнем.

Постановка задачи

Для начала нужна постановка задачи.

  1. Произвести синхронизацию графиков, задействованных валютных пар текущего таймфрейма.
  2. Получить доступ к данным Close семи валютных пар EURUSD, GBPUSD, USDCHF, USDJPY, USDCAD, AUDUSD, NZDUSD и разместить их в буферах индикатора, предназначенных для вспомогательных расчетов.
  3. На основании данных, полученных в пункте (2), рассчитать на текущем баре Индекс доллара.
  4. Зная Индекс доллара для текущего бара рассчитать остальные индексы валют.
  5. Произвести данные расчеты (пункты 3 и 4) необходимое количество раз для выбранной длины истории.
  6. В зависимости от выбранного назначения индикатора  для каждого из выбранных индексов валют рассчитать значения:
    • индекса Относительной Силы (Relative Strength Index, RSI);
    • Схождений/Расхождений Скользящих Средних (Moving Average Convergence/Divergence, MACD);
    • Стохастический Осциллятор (Stochastic Oscillator);
    • в дальнейшем список может дополняться.

Для всего этого нам потребуется:

31 индикаторный буфер:

  • 0-7 включительно - буферы для отрисовки итоговых линий;
  • 8-14 включительно - буферы основных валютных пар, содержащих в себе USD;
  • 15-22 включительно - буферы индексов валют;
  • 23-30 включительно - буферы промежуточных данных стохастика по типу close/close без сглаживания.

Для выбора назначения индикатора, заведем удобный перечислимый тип enum:

enum Indicator_Type
  {
   Use_RSI_on_indexes             = 1, // RSI от индекса
   Use_MACD_on_indexes            = 2, // MACD от индекса
   Use_Stochastic_Main_on_indexes = 3  // Stochastic от индекса
  };

Далее, с помощью команды input, в окно настроек индикаторы выведем пользователю для выбора из этого списка 

input Indicator_Type ind_type=Use_RSI_on_indexes;  // тип индикатора от индекса

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

Такие же правила действуют и для команды перечислений enum. То есть, если мнемоническому имени сопоставлен комментарий, как это показано в нашем примере, то вместо мнемонического имени используется содержимое комментария. Это дает дополнительную гибкость для написания программ с понятными описаниями входных параметров.

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

Рисунок 1. Выбор типа индикатора

Рисунок 1. Выбор типа индикатора

Предоставляем пользователю выбор необходимых валют для отрисовки индикатора и их цвет:

input bool USD=true;
input bool EUR=true;
input bool GBP=true;
input bool JPY=true;
input bool CHF=true;
input bool CAD=true;
input bool AUD=true;
input bool NZD=true;
input color Color_USD = Green;            // Цвет линии USD
input color Color_EUR = DarkBlue;         // Цвет линии EUR
input color Color_GBP = Red;              // Цвет линии GBP
input color Color_CHF = Chocolate;        // Цвет линии CHF
input color Color_JPY = Maroon;           // Цвет линии JPY
input color Color_AUD = DarkOrange;       // Цвет линии AUD
input color Color_CAD = Purple;           // Цвет линии CAD
input color Color_NZD = Teal;             // Цвет линии NZD

Рисунок 2. Выбор цвета линий индикатора

Рисунок 2. Выбор цвета линий индикатора

Еще некоторые настраиваемые параметры:

input string rem000        =  ""; // В зависимости от типа индикатора
input string rem0000       =  ""; // потребуются значения :
input int rsi_period       =   9; // период RSI
input int MACD_fast        =   5; // период MACD_fast
input int MACD_slow        =  34; // период MACD_slow
input int stoch_period_k   =   8; // период Stochastic %K
input int stoch_period_sma =   5; // период сглаживания для Stochastic %K
input int shiftbars        = 500; // количество баров для расчета индикатора

Рисунок 3. Настройки индикатора

Рисунок 3. Настройки индикатора

Ограничение в 500 баров для расчета индикатора является искусственным, но является достаточным для отображения идеи расчетов индексов. Но нужно помнить, что каждый индикаторный буфер требует памяти и при выставлении слишком большого размера этой переменной (в миллионы баров), памяти компьютера может не хватить.

Индикаторные буферы:

double   EURUSD[], // котировки
         GBPUSD[],
         USDCHF[],
         USDJPY[],
         AUDUSD[],
         USDCAD[],
         NZDUSD[]; 
                 
double     USDx[], // индексы
           EURx[],
           GBPx[],
           JPYx[],
           CHFx[],
           CADx[],
           AUDx[],
           NZDx[];      
                   
double  USDplot[], // итоговые линии по валютам
        EURplot[],
        GBPplot[],
        JPYplot[],
        CHFplot[],
        CADplot[],
        AUDplot[],
        NZDplot[];

double USDstoch[], // буферы промежуточных данных стохастика по типу close/close без сглаживания
       EURstoch[],
       GBPstoch[],
       JPYstoch[],
       CHFstoch[],
       CADstoch[],
       AUDstoch[],
       NZDstoch[]; 

Также нам потребуются некоторые глобальные (на уровне индикатора) переменные:

int             i,ii;
int        y_pos = 0// переменная Y координата для информационных объектов
datetime  arrTime[7];   // массив с последним известным временем нулевого бара (нужно для синхронизации)
int       bars_tf[7];   // для проверки количества доступных баров на разных валютных парах
int     countVal = 0;   // количество задействованных валют
int        index = 0;
datetime tmp_time[1];   // промежуточный массив для времени бара

И вот мы подошли к достаточно объемной функции OnInit, в которой будем распределять индикаторные буферы по их назначению.

Так как начальные расчеты идут через Индекс доллара, то для USD устанавливаем возможность только отключить отрисовку данной валюты в индикаторных буферах.

Выглядит это вот как:

if(USD)
  {
   countVal++;
   SetIndexBuffer(0,USDplot,INDICATOR_DATA);               // массив для отрисовки
   PlotIndexSetString(0,PLOT_LABEL,"USDplot");             // имя линии на индикаторе (при наведении мышки)
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,shiftbars);       // откуда начинаем отрисовку
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);        // стиль рисования (линия)
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,Color_USD);       // цвет линии отрисовки
   if(StringFind(Symbol(),"USD",0)!=-1)
     {PlotIndexSetInteger(0,PLOT_LINE_WIDTH,wid_main);}    // если USD присутствует в имени символа
                                                           // то рисуем линию соответствующей толщины 
   else
     {PlotIndexSetInteger(0,PLOT_LINE_STYLE,style_slave);}
   ArraySetAsSeries(USDplot,true);                         // индексация массива как таймсерия
   ArrayInitialize(USDplot,EMPTY_VALUE);                   // нулевые значения 
   f_draw("USD",Color_USD);                                // отрисовка в окне индикатора информации 
  }
SetIndexBuffer(15,USDx,INDICATOR_CALCULATIONS);            // массив для индекса доллара для расчетов
                                                           // (не отображается на индикаторе в виде линии) 
ArraySetAsSeries(USDx,true);                               // индексация массива как таймсерия
ArrayInitialize(USDx,EMPTY_VALUE);                         // нулевые значения

if(ind_type==Use_Stochastic_Main_on_indexes)
  {
   SetIndexBuffer(23,USDstoch,INDICATOR_CALCULATIONS);     // если назначение индикатора как Use_Stochastic_Main_on_indexes,
                                                           // то нужен еще этот промежуточный массив
   ArraySetAsSeries(USDstoch,true);                        // индексация массива как таймсерия
   ArrayInitialize(USDstoch,EMPTY_VALUE);                  // нулевые значения
  } 

Для валюты EUR код в функции OnInit выглядит вот так:

if(EUR)
  {
   countVal++;
   SetIndexBuffer(1,EURplot,INDICATOR_DATA);               // массив для отрисовки
   PlotIndexSetString(1,PLOT_LABEL,"EURplot");             // имя линии на индикаторе (при наведении мышки)
   PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,shiftbars);       // откуда начинаем отрисовку
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE);        // стиль рисования (линия)
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,Color_EUR);       // цвет линии отрисовки
   if(StringFind(Symbol(),"EUR",0)!=-1)
     {PlotIndexSetInteger(1,PLOT_LINE_WIDTH,wid_main);}    // если EUR присутствует в имени символа
                                                           // то рисуем линию соответствующей толщины    
   else
     {PlotIndexSetInteger(1,PLOT_LINE_STYLE,style_slave);} // если EUR НЕ присутствует в имени символа,
                                                           // то рисуем линию соответствующего стиля (на кроссах))
   ArraySetAsSeries(EURplot,true);                         // индексация массива как таймсерия
   ArrayInitialize(EURplot,EMPTY_VALUE);                   // нулевые значения
   SetIndexBuffer(8,EURUSD,INDICATOR_CALCULATIONS);        // данные Close валютной пары EURUSD
   ArraySetAsSeries(EURUSD,true);                          // индексация массива как таймсерия
   ArrayInitialize(EURUSD,EMPTY_VALUE);                    // нулевые значения
   SetIndexBuffer(16,EURx,INDICATOR_CALCULATIONS);         // массив для индекса евро для расчетов
                                                           // (не отображается на индикаторе в виде линии) 
   ArraySetAsSeries(EURx,true);
   ArrayInitialize(EURx,EMPTY_VALUE);
   if(ind_type==Use_Stochastic_Main_on_indexes)
     {
      SetIndexBuffer(24,EURstoch,INDICATOR_CALCULATIONS);  // если назначение индикатора как Use_Stochastic_Main_on_indexes,
                                                           // то нужен еще этот промежуточный массив
      ArraySetAsSeries(EURstoch,true);                     // индексация массива как таймсерия
      ArrayInitialize(EURstoch,EMPTY_VALUE);               // нулевые значения
     }
   f_draw("EUR",Color_EUR);                                // отрисовка в окне индикатора информации
  }
По аналогии с EUR, код будет выглядеть подобно для валют GBP, JPY, CHF, CAD, AUD, и NZD, смещая индексы индикаторных буферов. Код по этим валютам можно посмотреть в прикрепленном файле индикатора.

На этом завершим описание инициализации индикатора.

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

  • Расчет RSI по пользовательскому буферу
  • Расчет MACD
  • Расчет SMA по пользовательскому буферу
  • Расчет Stochastic close/close без сглаживания
  • Отрисовка объектов (информационных)
  • Комментарий в правом нижнем углу индикатора (о состоянии индикатора)
  • Инициализация задействованных ТФ валютных пар

Коротко расскажу о каждой из них:

  • Расчет RSI по пользовательскому буферу

Входные параметры:

double f_RSI(double &buf_in[], int period,int shift),

где buf_in[] - массив типа double (как таймсерия), period - период  индикатора  RSI, shift - для какого индекса бара рассчитываем индикатор. Возвращается одно значение типа double.

  • Расчет MACD

Входные параметры:

double f_MACD(double &buf_in[], int period_fast,int period_slow,int shift),

где buf_in[]  - массив типа double (как таймсерия), period_fast - период быстрой МА, period_slow - период медленной МА, shift - для какого индекса бара рассчитываем индикатор. Возвращается одно значение типа double.

  • Расчет SMA

Входные параметры:

double SimpleMA(const int position,const int period,const double &price[]),

где position - для какого индекса бара рассчитываем индикатор, period - период  индикатора  SMA, price[] - массив типа double (как таймсерия). Возвращается одно значение типа double.

  • Расчет Stochastic close/close без сглаживания

Входные параметры:

double f_Stoch(double &price[], int period_k, int shift),

где price[] - массив типа double (как таймсерия), period_fast - период %K линии индикатора, shift - для какого индекса бара рассчитываем индикатор. Возвращается одно значение типа double.

  • Отрисовка объектов

Входные параметры:

int f_draw(string name, color _color)

где name - имя объекта, _color - цвет объекта. Функция носит информационный характер. Начиная с верхнего правого угла окна индикатора и далее вниз эта функция выводит названия задействованных валют. Текст валюты имеет такой же цвет как и линия индикатора, относящаяся к этой валюте.

  • Комментарий в правом нижнем углу индикатора

Входные параметры:

int f_comment(string text)

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

И наконец, заключительная функция и одна из самых важных - это:

  • Инициализация задействованных ТФ валютных пар

Входных параметров не имеет.

В MetaTrader 5 история храниться в виде данных минутного ТФ по каждому инструменту. Поэтому, прежде чем работать с программой, при запуске терминала происходит построение всех необходимых (задействованных) графиков на основании все тех же данных минутного ТФ. Также построение происходит при переключении ТФ текущего трафика или при попытке обращения к графику  данного ТФ из кода программ MQL5.

Поэтому:

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

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

int  Bars(
   string        symbol_name,   // имя символа
   ENUM_TIMEFRAMES timeframe    // период
   );

В специально объявленный для этого массив собираем количество доступных баров для всех задействованных валютных пар. Проверяем каждое значение на минимально необходимое количество истории (переменная "количество баров для расчета индикатора" в настройках индикатора). Если доступная количество баров в истории по какому либо инструменту меньше  значения этой переменной, то считаем, что построение пока не прошло успешно, и заново опрашиваем количество доступных данных. Как только по всем валютным парам доступной истории будет больше, чем запрошено пользователем - считаем, что эта часть инициализации выполнена успешно.

Вторая часть задачи синхронизации реализуется с помощью функции CopyTime.

Копируем в предназначенный для этих целей массив время открытия нулевого бара каждого задействованного инструмента. Если все элементы этого массива одинаковые и отличные от нуля, то считаем, что у нас нулевой бар синхронизирован и начинаем расчет индикатора. Более детально посмотреть, как это реализовано, можно в коде прикрепленного индикатора.

На этом описание дополнительных функций закончим и приступаем к реализации функции OnCalculate. Т.к. индикатор мультивалютный, то потребуется второй вариант вызова этой функции.

int OnCalculate (const int     rates_total, // размер входных таймсерий
                 const int prev_calculated, // обработано баров на предыдущем вызове
                 const datetime&    time[], // Time
                 const double&      open[], // Open
                 const double&      high[], // High
                 const double&       low[], // Low
                 const double&     close[], // Close
                 const long& tick_volume[], // Tick Volume
                 const long&      volume[], // Real Volume
                 const int&       spread[]  // Spread
   );

Определяем  количество баров, необходимое для расчета:

   int limit=shiftbars;

   if(prev_calculated>0)
     {limit=1;}
   else
     {limit=shiftbars;}

Производим синхронизацию графиков валютных пар:

   init_tf();

Далее с помощью функции CopyClose копируем данные Close всех необходимых валютных пар в индикаторные буферы, специально для этого зарегистрированные. (Более подробно о доступах к данным других ТФ текущего инструмента и/или другого инструмента можно прочитать в справке)

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

   if (EUR){copied=CopyClose("EURUSD",PERIOD_CURRENT,0,shiftbars,EURUSD); if (copied==-1){f_comment("Ждите...EURUSD");return(0);}}
   if (GBP){copied=CopyClose("GBPUSD",PERIOD_CURRENT,0,shiftbars,GBPUSD); if (copied==-1){f_comment("Ждите...GBPUSD");return(0);}}
   if (CHF){copied=CopyClose("USDCHF",PERIOD_CURRENT,0,shiftbars,USDCHF); if (copied==-1){f_comment("Ждите...USDCHF");return(0);}}
   if (JPY){copied=CopyClose("USDJPY",PERIOD_CURRENT,0,shiftbars,USDJPY); if (copied==-1){f_comment("Ждите...USDJPY");return(0);}}
   if (AUD){copied=CopyClose("AUDUSD",PERIOD_CURRENT,0,shiftbars,AUDUSD); if (copied==-1){f_comment("Ждите...AUDUSD");return(0);}}
   if (CAD){copied=CopyClose("USDCAD",PERIOD_CURRENT,0,shiftbars,USDCAD); if (copied==-1){f_comment("Ждите...USDCAD");return(0);}}
   if (NZD){copied=CopyClose("NZDUSD",PERIOD_CURRENT,0,shiftbars,NZDUSD); if (copied==-1){f_comment("Ждите...NZDUSD");return(0);}}  

Далее в цикле (от 0 до limit) производим:

  • Расчет индекса доллара;
  • Расчет индексов других валют на основании данных Close и индекса доллара для текущего бара;
for (i=limit-1;i>=0;i--)
   {
      //расчет индекса USD
      USDx[i]=1.0;
      if (EUR){USDx[i]+=EURUSD[i];}         
      if (GBP){USDx[i]+=GBPUSD[i];}
      if (CHF){USDx[i]+=1/USDCHF[i];}
      if (JPY){USDx[i]+=1/USDJPY[i];}
      if (CAD){USDx[i]+=1/USDCAD[i];}
      if (AUD){USDx[i]+=AUDUSD[i];}
      if (NZD){USDx[i]+=NZDUSD[i];}
      USDx[i]=1/USDx[i];
      //расчет остальных индексов валют
      if (EUR){EURx[i]=EURUSD[i]*USDx[i];}
      if (GBP){GBPx[i]=GBPUSD[i]*USDx[i];}
      if (CHF){CHFx[i]=USDx[i]/USDCHF[i];}
      if (JPY){JPYx[i]=USDx[i]/USDJPY[i];}
      if (CAD){CADx[i]=USDx[i]/USDCAD[i];}
      if (AUD){AUDx[i]=AUDUSD[i]*USDx[i];}
      if (NZD){NZDx[i]=NZDUSD[i]*USDx[i];}
   }

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

Если было изъявлено желание взглянуть на RSI по индексам, то выполняем нижеприведенный код:

if (ind_type==Use_RSI_on_indexes)
   {
      if (limit>1){ii=limit - rsi_period - 1;}
      else{ii=limit-1;}
      for(i=ii;i>=0;i--)
         {
            if (USD){USDplot[i]=f_RSI(USDx,rsi_period,i);}
            if (EUR){EURplot[i]=f_RSI(EURx,rsi_period,i);}
            if (GBP){GBPplot[i]=f_RSI(GBPx,rsi_period,i);}
            if (CHF){CHFplot[i]=f_RSI(CHFx,rsi_period,i);}
            if (JPY){JPYplot[i]=f_RSI(JPYx,rsi_period,i);}
            if (CAD){CADplot[i]=f_RSI(CADx,rsi_period,i);}
            if (AUD){AUDplot[i]=f_RSI(AUDx,rsi_period,i);}
            if (NZD){NZDplot[i]=f_RSI(NZDx,rsi_period,i);}                  
         }
   }  

Если захотелось увидеть MACD по индексам, то нам сюда (правда пока реализовано только на основе SimpleMA, на основе EMA будет реализовано позже):

if (ind_type==Use_MACD_on_indexes)
   {
      if (limit>1){ii=limit - MACD_slow - 1;}
      else{ii=limit - 1;}
      for(i=ii;i>=0;i--)
         {
           if (USD){USDplot[i]=f_MACD(USDx,MACD_fast,MACD_slow,i);}
           if (EUR){EURplot[i]=f_MACD(EURx,MACD_fast,MACD_slow,i);}
           if (GBP){GBPplot[i]=f_MACD(GBPx,MACD_fast,MACD_slow,i);}
           if (CHF){CHFplot[i]=f_MACD(CHFx,MACD_fast,MACD_slow,i);}
           if (JPY){JPYplot[i]=f_MACD(JPYx,MACD_fast,MACD_slow,i);}
           if (CAD){CADplot[i]=f_MACD(CADx,MACD_fast,MACD_slow,i);}
           if (AUD){AUDplot[i]=f_MACD(AUDx,MACD_fast,MACD_slow,i);}
           if (NZD){NZDplot[i]=f_MACD(NZDx,MACD_fast,MACD_slow,i);}                  
         }
   } 

Если Stochastiс, то необходимо сначала рассчитать линию %K, а потом сгладить ее методом SimpleMA. Итоговую сглаженную линию отобразить на графике.

if (ind_type==Use_Stochastic_Main_on_indexes)
   {
      if (limit>1){ii=limit - stoch_period_k - 1;}
      else{ii=limit - 1;}
      for(i=ii;i>=0;i--)
         {
           if (USD){USDstoch[i]=f_Stoch(USDx,rsi_period,i);}
           if (EUR){EURstoch[i]=f_stoch(EURx,stoch_period_k,i);}
           if (GBP){GBPstoch[i]=f_stoch(GBPx,stoch_period_k,i);}
           if (CHF){CHFstoch[i]=f_stoch(CHFx,stoch_period_k,i);}
           if (JPY){JPYstoch[i]=f_stoch(JPYx,stoch_period_k,i);}
           if (CAD){CADstoch[i]=f_stoch(CADx,stoch_period_k,i);}
           if (AUD){AUDstoch[i]=f_stoch(AUDx,stoch_period_k,i);}
           if (NZD){NZDstoch[i]=f_stoch(NZDx,stoch_period_k,i);}                  
         }
      if (limit>1){ii=limit - stoch_period_sma - 1;}
      else{ii=limit - 1;}
      for(i=ii;i>=0;i--)
         {
            if (USD){USDplot[i]=SimpleMA(i,stoch_period_sma,USDstoch);}
            if (EUR){EURplot[i]=SimpleMA(i,stoch_period_sma,EURstoch);}
            if (GBP){GBPplot[i]=SimpleMA(i,stoch_period_sma,GBPstoch);}
            if (CHF){CHFplot[i]=SimpleMA(i,stoch_period_sma,CHFstoch);}
            if (JPY){JPYplot[i]=SimpleMA(i,stoch_period_sma,JPYstoch);}
            if (CAD){CADplot[i]=SimpleMA(i,stoch_period_sma,CADstoch);}
            if (AUD){AUDplot[i]=SimpleMA(i,stoch_period_sma,AUDstoch);}
            if (NZD){NZDplot[i]=SimpleMA(i,stoch_period_sma,NZDstoch);}                  
          }                     
   }       

На этом заканчивается расчеты индикатора. На рисунках 4-6 приведено несколько картинок разного вида индикатора.


Рисунок 4.  RSI по индексам


Рисунок 5. MACD по индексам валют


Рисунок 6. Stochastiс по индексам валют

Заключение

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

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

Есть много "за" и "против" кластерного анализа рынка Forex. Торговые системы на основе такого подхода есть в свободном доступе, и имеются обсуждения на разных форумах, в том числе и на MQL4.Community. Поэтому принципы торговли по данному индикатору в этой статье не рассматриваются. 

Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (19)
Boris
Boris | 12 янв. 2011 в 12:27
olyakish:
Повторюсь, я не использую отрисовку индекса как такового, а только строю по ним осцилляторы, которые можно увидеть наглядно. по этому не так важно где находится "цена индекса" важно именно её изменения от бара к бару (приращение). Данный индикатор наглядно может показывать волатильность именно валюты в сравнении с другими валютами, участвующими в расчетах и построениях. Из всех мажеров по данному индикатору можно сказать, что GBP самая волатильная валюта. Особенно это показано в режиме "MACD от индекса".

 

С отображением jpy проблемы, при  типе индикатора MACD (при других типах, рисует) :

 

 

 и также скрин из вашей статьи :

 

 просто здесь график EURUSD, но MACD индекса JPY на всех графиках =0.

Boris
Boris | 13 янв. 2011 в 04:29
olyakish:


Формула взята вот из этой ветки https://www.mql5.com/ru/forum/109249

Это начало обсуждения. Рекомендую прочитать.

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

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

Описанная выше ситуация возникаем именно из-за некорректности данной формулы, ибо цена 1й Йены несравнимо мала по отношению к другим валютам.

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

Alexey Klenov
Alexey Klenov | 13 янв. 2011 в 13:29
BoraBo:

Описанная выше ситуация возникаем именно из-за некорректности данной формулы, ибо цена 1й Йены несравнимо мала по отношению к другим валютам.

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

 

Да MACD не самое удачное решение, как оказалось, для построения классических индикаторов по индексам. Нужно было ограничиться только индикаторами, у которых значения могут быть в определенном диапазоне ( к примеру 0-100) тогда бы не было подобных ситуаций.


Иван
Иван | 17 янв. 2013 в 18:08
Мог бы автор или кто-то ещё добавить в представленный индикатор тот же самый алгоритм расчёта и построение линий по MA, как это сделано в оригинальном индикаторе для МТ4?
https://www.mql5.com/ru/articles/1464
A. Forex
A. Forex | 13 дек. 2021 в 13:10

Спасибо большое Автору за индикатор!

Не могли бы добавить возмойность рассчета RSI по цене Typical or Weighted пожалуйста?

Пример торговой системы на основе индикатора Heiken-Ashi Пример торговой системы на основе индикатора Heiken-Ashi
В данной статье мы рассмотрим возможности использование индикатора Heiki-Ashi. Создадим на его базе простейшую торговую систему(ТС) и напишим на MQL5 советник. Протестируем ТС на истории с помощью MetaTrader5 Strategy Tester.
Virtual Order Manager для управления ордерами в позициях терминала MetaTrader 5 Virtual Order Manager для управления ордерами в позициях терминала MetaTrader 5
Эта библиотека классов может быть добавлена в советники, написанные для MetaTrader 5, чтобы они могли работать с ордерами в рамках подхода, реализованного в MetaTrader 4, а не в рамках позиционно-ориентированного подхода платформы MetaTrader 5. Это достигается путем отслеживания "виртуальных" ордеров в терминале MetaTrader 5, поддержки стопов, невидимых для брокера, и установкой дальних защитных реальных стопов на торговом сервере.
Алгоритм генерации тиков  в тестере стратегий терминала MetaTrader 5 Алгоритм генерации тиков в тестере стратегий терминала MetaTrader 5
MetaTrader 5 позволяет во встроенном тестере стратегий моделировать автоматическую торговлю с помощью экспертов на языке MQL5. Такое моделирование называется тестированием экспертов, и может проводиться с использованием многопоточной оптимизации и одновременно по множеству инструментов. Для проведения тщательного тестирования требуется генерировать тики на основе имеющейся минутной истории. В статье дается подробное описание алгоритма, по которому генерируются тики для исторического тестирования в клиентском терминале MetaTrader 5.
Переход с MQL4 на MQL5 Переход с MQL4 на MQL5
Данная статья, построенная в форме справочника по функциям MQL4, призвана помочь переходу с MQL4 на MQL5. Для каждой функции языка MQL4 приведено описание и представлен способ ее реализации на MQL5, что позволит вам значительно ускорить перевод своих программ с MQL4 на MQL5. Для удобства функции разбиты на группы, как в документации по MQL4.