Скачать MetaTrader 5

Принцип замены времени в интрадей-торговле

5 июля 2007, 16:05
kamal
7
1 365

Введение

В вопросах анализа предыдущего движения цен важную роль всегда играет статистическая однородность наблюдений. В условиях, когда эта однородность имеет место, возможно глубокое изучение свойств процесса с целью выявления закономерностей, способствующих построению торговой системы. Однако общеизвестно и будет показано далее, что даже в первом приближении процесс валютного курса не является однородным, а именно имеется существенная неоднородность, связанная с активностью разных сессий: Американской, Европейской, Азиатской и переходами между ними.

Возьму на себя смелость заявить, что мало кто из разработчиков систем – новичков, а также некоторых «опытных», задумывается о том, что даже самые простые индикаторы типа скользящего среднего, будучи связанными со временем, представляют из себя фактически разный агрегат в разное время суток. Безусловно, есть и системы, формулирующиеся в терминах цены, но не времени. Типичный пример – системы по renko и kagi методикам, но таких меньшинство. Большинство же, повторюсь, «завязаны» на время чаще всего опосредованно через индикаторы.

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


Теория

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

Не обсуждая вопрос, является ли процесс изменения цены диффузионным или мартингалом, заметим, что ничто не мешает аналогичным методом перейти от процесса изменения цены к чему-то устроенному попроще, а именно статистически однородному по времени процессу. С этой целью естественным путем было бы использование баров не с временным делением, а просто с фиксированным количеством тиков, то есть внутри бара «сидят» не 60 минут, а 1000 тиков, скажем.

Такое время в теории называется операционным и является натуральным для процесса изменения цены. По такому времени процесс имеет статистически постоянное среднее отклонение, что позволяет четче определять формирующиеся настроения рынка и эффективнее отделять их от случайных флуктуаций. Заметим, что использование общеупотребительных индикаторов было бы не только возможным, но гораздо более однородным. Однако, к сожалению, такая возможность пока в терминале MetaTrader 4 отсутствует, что заставляет нас обратиться к другому способу, а именно перестройке системы с учетом времени. Ниже мы приведем пример измененных индикаторов, а пока точнее изучим, о какой неоднородности идет речь.


Статистические данные

То, что активность на рынке падает в определенное время дня, превосходно видно на графиках экзотических валютных пар, например:

Кроме того, те же эффекты наблюдаются и на широко распространенных парах. Это вызывает интерес к более детальному изучению поведения объемов и волатильности. Ясное дело, что критически важным для понимания колебаний внутридневной волатильности является поведение объемов, то есть тиков на бар. Однако объем сам по себе является величиной случайной, что заставляет нас обращаться к историческому среднему. Такое обращение вполне может оказаться не вполне легальным, если статистическое «сырье» будет вести себя «плохо».

С целью проверки этих гипотез напишем простенький индикатор – ExpectedVolume (ожидаемый объем), который найдет историческое среднее количества тиков в час за histSteps шагов назад, каждый шаг длиной span дней. Типичное значение этих параметров – 100 и 1 соответственно. Все тестирование проводится на таймфрейме H1, на других внутридневных таймфеймах параметры следует соответственно менять. Приведем код индикатора:

//+------------------------------------------------------------------+
//|                                             Expected Volumes.mq4 |
//|                                     Copyright © 2007, Amir Aliev |
//|                                       http://finmat.blogspot.com/ |
//+------------------------------------------------------------------+
#property  copyright "Copyright © 2007, Amir Aliev"
#property  link      "http://finmat.blogspot.com/"
//---- 
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Blue
//---- input parameters
extern int hist_steps = 100;      // Number of observations
extern int span = 1;              // Days to step back each time 
//---- buffers
double ExtMapBuffer1[];
int sum;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   string short_name;
//---- indicators
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(0,ExtMapBuffer1);
//----
   short_name = "Expected volumes(" + hist_steps + ")";
   IndicatorShortName(short_name);
   SetIndexLabel(0, short_name);
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars = IndicatorCounted();
   int rest = Bars - counted_bars;
   int j, k, u;
//----     
   while(rest >= 0)
     {
      if(Bars - rest < span * 23 * hist_steps) 
        {
         ExtMapBuffer1[rest] = 0;     
         rest--; 
         continue;                                   
        }
      sum = 0;
      j = 0;
      k = 0;
      u = 0;
      while(j < hist_steps && k < Bars) 
        {
         if(TimeHour(Time[rest+k]) == TimeHour(Time[rest]))
           {
            u++;
            if(u == span)
              {
               u = 0;
               j++;
               sum += Volume[rest + k]; 
              }
            k += 23;
           }
         k++;
        }
      ExtMapBuffer1[rest] = sum / hist_steps;     
      rest--;                                    
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+

Однако для проверки статистической однородности необходимо сделать наблюдения независимыми, например, разбить по дням недели. Для этого положим span = 5. Имеем следующую картинку:

Соседние горбы почти совпадают. Это означает что волатильность, которую мы измеряем тиками в час, статистически однородна. Кроме того, понять структуру этой волатильности можно, внимательнее взглянув на картинки (слева - EURUSD, справа - USDJPY):

На них ясно видны три пика активности сессий – Азиатской, Европейской и Американской. Отметим отдельно, что деление именно на эти сессии не является общепринятым - иногда выделяют и другие. В принципе, можно увидеть и некоторые особенности, например, характер активности в американскую сессию (повторяется на обоих графиках).


Изменение индикаторов

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

В конечном итоге наиболее разумным было бы все же введение «операционного» таймфрейма, а пока покажем, как поменять несколько простых индикаторов. Самый примитивный из них - скорректированные объемы строится делением реальных объемов на ожидаемые. Таким образов, отклонение в ту или иную сторону от единицы этого индикатора отражает повышенную/пониженную активность на рынке. Код этого индикатора в силу крайней простоты в тексте статьи приводить не будем. Он есть в приложденных файлах.

Следующий пример - среднее. Фактически следует просто взвешивать характеристику бара, по которой мы строим среднее (в примере берется open), количеством тиков внутри бара. Полученное число не равно строго сумме значений цены по всем тикам. Для более точной оценки надо брать не open, a средневзвешенное по бару. Индикатор сделан «в лоб» и из-за этого расчет его требует значительных и по сути излишних вычислительных затрат. Из-за этого введен дополнительный параметр – число баров из прошлого, которое индикатор будет отрисовываться, по умолчанию равно 500. Кроме того, период средней задается теперь не в барах, а в количестве тиков. Итак, код:

//+------------------------------------------------------------------+
//|                                                Corrected SMA.mq4 |
//|                                      Copyright © 2007, Amir Aliev |
//|                                    http://finmat.blogspot.com/   |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Amir Aliev"
#property link      "http://finmat.blogspot.com/"
//----
#property indicator_chart_window
#property indicator_color1 Red
//---- input parameters
extern int MA_Ticks = 10000;
extern int MA_Shift = 0;
extern int MA_Start = 500;
//---- indicator buffers
double ExtMapBuffer[];
double ExpVolBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//----
   SetIndexStyle(0, DRAW_LINE);
   SetIndexShift(0, MA_Shift);
   IndicatorBuffers(2);
//---- indicator buffers mapping
   SetIndexBuffer(0, ExtMapBuffer);
   SetIndexBuffer(1, ExpVolBuffer);
   SetIndexDrawBegin(0, 0);  
//---- initialization done
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars = IndicatorCounted();
   int rest  = Bars - counted_bars;
   int restt = Bars - counted_bars;
   double sum;                               
   int ts;                                   
   int evol;                                 
   int volsum;
   int j;
//----
   while(restt >= 0)
     {
       volsum = 0;
       for(int k = 0; k < 30; k++) 
           volsum += iVolume(NULL, 0, restt + k*24); 
       ExpVolBuffer[restt] = volsum / 30;
       restt--;
     }
//----
   while(ExpVolBuffer[rest] == 0 && rest >= 0) 
       rest--;
   rest -= MA_Ticks / 200;
   if(rest > MA_Start) 
       rest = MA_Start;  
//----
   while(rest >= 0)
     {
       sum = 0;
       ts = 0;
       j = rest;
       while(ts < MA_Ticks)
         {
           evol = ExpVolBuffer[j];
           Print("Evol = ", evol);
           if(ts + evol < MA_Ticks)
             {
               sum += evol * Open[j];
               ts += evol;
             }
           else
             {
               sum += (MA_Ticks - ts) * Open[j];
               ts = MA_Ticks;
             }
           j++;
         }
       ExtMapBuffer[rest] = sum / MA_Ticks;
       rest--;
     }   
//----
   return(0);
  }
//+------------------------------------------------------------------+

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

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

Казалось бы, нет никакого смысла усреднять объемы за прошлые периоды: достаточно просто в расчете среднего использовать имеющиеся объемы как коэффициенты. Соответствующий код средней приведем и мы, но отметим, что по техническим причинам лучше всего использовать такую среднюю на маленьких таймфреймах, вроде М1-М5:

//+------------------------------------------------------------------+
//|                                             Corrected SMA II.mq4 |
//|                                     Copyright © 2007, Amir Aliev |
//|                                       http://finmat.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Amir Aliev"
#property link      "http://finmat.blogspot.com/"
 
#property indicator_chart_window
#property indicator_color1 Red
//---- input parameters
extern int MA_Ticks = 1000;
//---- indicator buffers
double sum = 0;                               
int ticks = 0;
bool collected = false;
bool started = false;
int fbar = 0;
double ExtMapBuffer[];
int oldRange = 0;
int lbarVol = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//----
   SetIndexStyle(0, DRAW_LINE);
//---- indicator buffers mapping
   SetIndexBuffer(0, ExtMapBuffer);
//---- initialization done
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int rest = Bars - IndicatorCounted();
   if(! rest) 
       return (0);
   Print("Ticks = ", ticks);
   Print("Rest = ", rest);
   Print("fbar = ", fbar);  
   rest--;
   fbar += rest;
   while(!collected && (rest >= 0))
     {
      if(ticks + Volume[rest] < MA_Ticks)
        {
         ticks += Volume[rest];
         sum += Volume[rest] * Open[rest];
         if(!started)
           {
            fbar = rest;
            started = true;
           }
         rest--;
         continue;
        } 
      collected = true;
     }
   if(! collected) 
       return (0);
 
   ticks += (Volume[rest] - lbarVol);
   sum += (Volume[rest] - lbarVol) * Open[rest];
   lbarVol = Volume[rest];
   while(ticks > MA_Ticks)
     {
       Print("fbar-- because bar ticks reaches 1000");
       ticks -= Volume[fbar];
       sum -= Volume[fbar] * Open[fbar];
       fbar--;
     }
   ExtMapBuffer[rest] = sum / ticks;
   rest--;
   while(rest >= 0)
     {
      ticks += Volume[rest];
      sum += Volume[rest] * Open[rest];
      lbarVol = Volume[rest];
      while(ticks > MA_Ticks)
        {
         Print("fbar-- because of new bar ");
         ticks -= Volume[fbar];
         sum -= Volume[fbar] * Open[fbar];
         fbar--;
        }
      ExtMapBuffer[rest] = sum / ticks;
      rest--;
     } 
//----
   return(0);
  }
//+------------------------------------------------------------------+

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

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


Заключение

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

Сама концепция операционного времени поэтому представляется чрезвычайно полезной и естественной с позиции технического анализа. Безусловно, тот факт, что, например, какие-то ключевые новости по состоянию экономик выходят в определенное время, нарушает однородность достаточно серьезно и с трудом поддается «лечению». Однако во многих случаях применение замены времени позволяет получать более стабильные результаты и увеличивать прибыльность торговой стратегии.

Прикрепленные файлы |
Corrected_MACD.mq4 (2.36 KB)
Avals
Avals | 12 июл 2007 в 07:27
kamal:
Действительно, генерить как period converter можно, но вот только как это делать в режиме реального времени?

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

Для того, чтобы обновление было real-time нужно чтобы масштаб времени был фиксированным, но возможно нестандартным. Например М47 :) Второе предложение на счет взятия темпа времени по средней, как раз это решает. Возьмем полные сутки (период цикла активности) и разобъем эти сутки на равные интервалы по средней активности с требуемой точностью (минимальный средний тиковый объем). Допустим у нас получилось 130 интервалов. Делим сутки 24*60/130=11. Т.е. можно генерить файл М11. Открывать его через "автономно", но он будет работать real-time. Время внутри дня будет условным, а без этого и не обойдешься. А затем собирать эти условные М11 как на истории, так и real-time точно так, как в скрипте Period_converter. Собирать для точности (особенно в активное время) прийдется из минуток. Получится например, что на спокойном рынке М11 будет состоять из 70-80 минут, а на быстром рынке в американскую сессию из 3-4. Остается только находить этот множитель для каждого периода и составлять новые бары. Будет правда вопрос, что например в сутки вмещается не целое кол-во 11-ти минуток, но это решается округлением, или пересчетом множителя. ИМХО.

Кроме того, что ненужно переписывать все индикаторы, преимущество в том, что можно задавать новый "операционный" тайм-фрейм (даже не тайм, а volume-frame) и наблюдать его визуально.

P.S. В плане представления цены в зависимости от активности по времени, интересно так же представление в несколько иной плоскости - активности по ценам. Это формализм MarketProfile и VolumeProfile. http://forex.kbpauk.ru/showflat.php/Cat/0/Number/88231/page/1/fpart/1/vc/1

kamal
kamal | 12 июл 2007 в 12:37
Avals:
kamal:
Действительно, генерить как period converter можно, но вот только как это делать в режиме реального времени?

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

Для того, чтобы обновление было real-time нужно чтобы масштаб времени был фиксированным, но возможно нестандартным. Например М47 :) Второе предложение на счет взятия темпа времени по средней, как раз это решает. Возьмем полные сутки (период цикла активности) и разобъем эти сутки на равные интервалы по средней активности с требуемой точностью (минимальный средний тиковый объем). Допустим у нас получилось 130 интервалов. Делим сутки 24*60/130=11. Т.е. можно генерить файл М11. Открывать его через "автономно", но он будет работать real-time. Время внутри дня будет условным, а без этого и не обойдешься. А затем собирать эти условные М11 как на истории, так и real-time точно так, как в скрипте Period_converter. Собирать для точности (особенно в активное время) прийдется из минуток. Получится например, что на спокойном рынке М11 будет состоять из 70-80 минут, а на быстром рынке в американскую сессию из 3-4. Остается только находить этот множитель для каждого периода и составлять новые бары. Будет правда вопрос, что например в сутки вмещается не целое кол-во 11-ти минуток, но это решается округлением, или пересчетом множителя. ИМХО.

Кроме того, что ненужно переписывать все индикаторы, преимущество в том, что можно задавать новый "операционный" тайм-фрейм (даже не тайм, а volume-frame) и наблюдать его визуально.

P.S. В плане представления цены в зависимости от активности по времени, интересно так же представление в несколько иной плоскости - активности по ценам. Это формализм MarketProfile и VolumeProfile. http://forex.kbpauk.ru/showflat.php/Cat/0/Number/88231/page/1/fpart/1/vc/1


О, вот это действительно интересно, но только я к сожалению не понял почему M11 не будет просто одинацатиминутками? Ну то есть кокретно вот это непонятно "Получится например, что на спокойном рынке М11 будет состоять из 70-80 минут, а на быстром рынке в американскую сессию из 3-4. " А так это конечно искомое поведение. На пишите, пожалуйста, подробнее, что предлагается делать, думаю это будет всем полезно.

Avals
Avals | 13 июл 2007 в 09:04
kamal:

О, вот это действительно интересно, но только я к сожалению не понял почему M11 не будет просто одинацатиминутками? Ну то есть кокретно вот это непонятно "Получится например, что на спокойном рынке М11 будет состоять из 70-80 минут, а на быстром рынке в американскую сессию из 3-4. " А так это конечно искомое поведение. На пишите, пожалуйста, подробнее, что предлагается делать, думаю это будет всем полезно.

Подсчитываем средний объем, например для каждой минуты дня. Получится распределение которое вы представили в своей статье. Подсчитываем суммарное кол-во тиков (фактически средний дневной объем). Далее пользователь ввел кол-во разбиений (параметр скрипта). Это и будет новый операционный фрейм. Например, ввели 100. Среднее-дневное кол-во тиков, например 1956. Получается, что в одном новом баре будет 19,56 тиков. Далее для каждого из этих 100 баров находим сколько минуток ему соответствует (по среднему объему для минуток, чтобы сумма тиков была 19). Например, 1-ому 2 минуты, 2-ому 3 минуты, ..., 45-ому 7 минут, .... Теперь мы можем собирать новые быры. Например, 1-ый бар дня будет: Open=Open(1-ой минуты), Close(закрытие 2-ой), High(максимальное значение от 1-ой до 2-ой минуты); 2-ой бар дня будет: Open=Open(3 минуты), Close=Close(5 минуты), ... и т.д. и т.п.

Но нам нужно выводить эти бары в какой-то фиксированный TF (чтобы MT с ним мог работать). Для этого мы вычисляем скольки минутам должен соответствовать один новый бар: 24*60/100=14. Т.е. у нас искусственно вводится TF - М14 только для того, чтобы в сутки влезло 100 новых баров. А дальше все как в Period_converter: сначало генерирум историю, затем зацикливаемся на обновление real-time. Генерация происходит по выше указанному алгоритму.

Андрей
Андрей | 29 окт 2007 в 15:15

Простите, если еще следите за темой, загляните по - http://onix-trade.net/forum/index.php?showtopic=47239 - не совсем то же самое, но...

Может еще какие мысли возникнут :).

thekoss Karakozov
thekoss Karakozov | 25 июн 2013 в 21:26
При использовании  Expected Volumes .mq4 виснит терминал,что посоветуете?
Как упростить обнаружение и устранение ошибок в коде эксперта Как упростить обнаружение и устранение ошибок в коде эксперта

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

Система для создания МТС Система для создания МТС

Согласитесь, заманчиво звучит - Вы стали обладателем программы, которая за несколько минут может разработать Вам прибыльную МТС. Вам нужно просто ввести целевые параметры на сделку и нажать Enter. И - нате Вам, получите готовую МТС, протестированную и с положительным матожиданием выигрыша. Когда тысячи людей тратят тысячи часов времени на разработку той самой, единственной (МТС), которая "напоит, накормит и спать уложит", такие утверждения звучат, мягко говоря, неубедительно. С одной стороны, это действительно выглядит неправдоподобно... Но, на мой взгляд, эта задача вполне решаема.

Взаимодействие между MetaTrader 4 и Matlab посредством CSV-файлов Взаимодействие между MetaTrader 4 и Matlab посредством CSV-файлов

Пошаговые инструкции по организации обмена массивами данных между MetaTrader 4 и Matlab посредством CSV-файлов.

Технический Анализ: невозможное - возможно! Технический Анализ: невозможное - возможно!

Ответ на вопрос: почему невозможное может быть возможным, когда многое говорит об обратном? Рассуждения о техническом анализе.