Погружаемся в особенности индикаторов MetaTrader 5

 

В процессе построения "продвинутых" индикаторов возникает немало вопросов. Многие из них не удается решить с помощью документации. Приходится проводить эксперименты вслепую - не зная внутреннего устройства индикаторной подсистемы МТ5. 

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

Приветствуется размещение ссылок на другие материалы, которые прямо или косвенно помогут решить возникшие вопросы и проблемы. 

 

Тезис №1

Поскольку при вызове OnCalculate в качестве параметров по ссылке приходят огромные open, close, high, low, ..., то сразу следует вывод, что они не строятся для каждого вызова\индикатора отдельно, а хранятся где-то в уже готовом виде. Группа функций CopyXXX очень неповоротливая в тех случаях, когда приходится синхронизировать разные символы. Можно ли из скриптов и экспертов получить прямой доступ "на чтение" к внутренним массивам OHLCV ?

Вот конкретные задачи, которые мне не удается решить эффективно:

- нужно получить "срез" значений нескольких десятков индикаторов разных TF+Symbol на определенный момент времени

- нужно синхронно пройти по барам разных символов 

- нужно получить информацию о наличии\отсутствии бара для валидного DateTime (валидность можно описать для каждого брокера отдельно, например, - открытие недели пн 01:00, закрытие пт 23:59, нерабочий день 1 янв, ...)

Документация по MQL5: Основы языка / Функции / Функции обработки событий
Документация по MQL5: Основы языка / Функции / Функции обработки событий
  • www.mql5.com
Основы языка / Функции / Функции обработки событий - Документация по MQL5
 

Задача №2

Индикатор выполняет расчеты своих буферов по правилам, которые хранятся во внешнем файле. Чтобы было более понятно, поясню - внешняя программа проводит обучение нейросети и периодически сохраняет обновленную структуру в файл.

Индикатор должен следить за обновлениями и полностью пересчитываться в этом случае.

Небольшой нюанс)) : количество индикаторных буферов в общем случае заранее не известно (но не больше, скажем,  N=500, хотя реально <50) 

Имеет ли право на жизнь вот такая реализация ?

#property indicator_separate_window
#property indicator_buffers 500 // На всякий случай ))
#property indicator_plots   500

// функция для проверки даты изменения файла (в МТ5 ничего подобного не нашел)
#import "FilesDll.dll"
  int FileAge(string &aFileName);  
#import

input string File="New21.xml"; // Файл в котором хранятся кол-во буферов и правила расчета
input string Path="C:\\Program Files\\MetaTrader 5\\MQL5\\Files\\";

struct  CBuffer {  // Не смог по-другому объявить двумерный массив всех буферов
  double Data[];   //    только через массив структур, внутри которых лежит один динамический массив
};

CBuffer Buffers[500];  // Массив потенциальных буферов индикатора

int     Modified=NULL; // Дата изменения загруженного файла сети
int     RatesTotal=0;     // Копия OnCalculat'овских значений для работы из OnTimer'a
int     PrevCalculated=0; //

bool IsFileModified() {  // Проверка "изменился ли файл нейросетей с момента последнего обновления индикатора?"
  string filename=Path+File;
  int m=FileAge(filename); //Время изменения файла
  return((Modified==NULL) || (m!=Modified));
}

int Init() {
  string filename=Path+File;
  Modified=FileAge(filename);
  PrevCalculated=0;

  // Вычитываем файл filename и запоминаем структуру 
  // Весь расчет будет в объекте NetPool - коллекция загруженных из файла нейросетей
  // NetPool.FNets - количество нейросетей в файле = количество буферов для отрисовки

  for (int i=0; i<ArraySize(NetPool.FNets); i++) {  // проходим по всем НОВЫМ буферам и переинициализируем их
    ArrayInitialize(Buffers[i].Data,EMPTY_VALUE);
    SetIndexBuffer(i,Buffers[i].Data,INDICATOR_DATA);
    ArraySetAsSeries(Buffers[i].Data,true);
    PlotIndexSetDouble(i,PLOT_EMPTY_VALUE,EMPTY_VALUE);
    PlotIndexSetString(i,PLOT_LABEL,NetPool.FNets[i].Label);
    PlotIndexSetInteger(i,PLOT_DRAW_TYPE, DRAW_LINE);
    PlotIndexSetInteger(i,PLOT_LINE_COLOR,LightGray);
    PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID);
    PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1);
  };
};

void CalcBar (int bar, datetime dt)
{
  // Загружаем "срез" значений индикаторов на дату dt
  double d[];
  IndPool.LoadData(dt,d); // это набор индикаторов, которые дают входные данные для всех нейросетей из NetPool

  // Проводим расчет буферов для одного бара c номером bar
  for (int j=0; j<ArraySize(NetPool.FNets); j++) {
    NetPool.FNets[j].Run(d);
    Buffers[j].Data[bar]=NetPool.FNets[j].FNeurons[<...>].FValue;
  };
  
};

void Calc() {

  // Выполняем расчет для всех необходимых баров

  int count=RatesTotal-PrevCalculated-1;
  if (count<0) count=1;
  datetime time[];
  ArraySetAsSeries(time,true);
  CopyTime(Symbol(),Period(),0,count,time);
  for (int i=0; i<count; i++) 
    CalcBar(i,time[i]);
  
  PrevCalculated=RatesTotal;
};

int OnInit() {
  EventSetTimer(10); 
  Init();
  return(0);
}

int OnCalculate (const int rates_total,      // размер массива price[]
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const int begin,            // откуда начинаются значимые данные
                 const double& price[]       // массив для расчета
) {
  RatesTotal=rates_total;
  PrevCalculated=prev_calculated;
  Calc();  
  return(PrevCalculated);
}

void OnTimer() {
  if (IsFileModified()) {
    Print ("Modified:");
    Init();
    Calc();
  };
};

Основная идея "в двух словах":

 вычисления значений буферов могут проводиться при возникновении двух видов событий OnCalculate и OnTimer. Поэтому инициализация (и реинициализация! корректно ли это???) вынесены в Init(), а расчет - в Calc() .

Init() может вызываться как из OnInit(), так и из OnTimer()

Calc() может вызываться как из OnCalculate(), так и из OnTimer() 

------------------------------------------------------------------------------------

Вопрос скорее к разработчикам, нежели к  пользователям MQL5:

нет ли в этой схеме каких-либо архитектурных нарушений индикаторной подсистемы МТ5? 

Не совсем понятны особенности  буферных индикаторов, потому и возникает этот вопрос.

 

да уж... как всё сложно...

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

 
Rinng  2010.04.21 12:54 

да уж... как всё сложно...

В данном случае это лишь пример для того чтобы более детально разобраться в возможностях "индикаторной технологии" 

yu-sha 2010.04.21 10:00 

Можно ли из скриптов и экспертов получить прямой доступ "на чтение" к внутренним массивам OHLCV?

 Размышления вслух о своих же вопросах...

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

И как следствие, ответом на вопрос будет - "технически" можно, но для пользователей нельзя, чтобы обеспечить целостность данных

Комментарий разработчика см. #  

 

 

Вопрос №3

Как получить информацию об отсутствии бара для заданной точки времени?

В следующем примере запрашивается значение Ма21 для точки времени, которая попадает в воскресенье 

int h=iMA(_Symbol,_Period,21,0,MODE_SMA,PRICE_CLOSE);
if (h != INVALID_HANDLE) {
  double v[];
  int r=CopyBuffer(h,0,D'2010.04.18',1,v);  // 2010.04.18 - воскресенье
}  

 В результате возвращается значение Ма21 для последнего бара пятницы, т.е. ближайшего бара слева

А если это "провал" в истории? 

 

 
yu-sha:

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

Расчет индикаторов в МТ5 не происходит в интерфейсном потоке.

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


 

с ново ведением основного тайм фрема как м1 уже визуально можно проследить как считает индикатор

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

генерация данных с тайм фрейма перераспределение данных и в конце концов сами вычисления это уже не мт4 со своими правилами и установленными тф


для таких сетей нужен очень мощный модуль облегчения пересчета и возможно даже внешная база данных в которой будут так сказать хранить пережованные данные и обращаться уже к ним

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

так ваше во время активной паники на рынке просто машина не будет успевать высчитывать.


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

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

 

CoreWinTT  ,

В реальной торговле даже при самом худшем раскладе (ТФ=м1, на входе в НС сотни индикаторов от разных ТФ и Symbol) ничего страшного не произойдет - за минуту (с момента закрытия предпоследней свечи до закрытия текущей) один бар прекрасно обсчитается. Эксперты анализируют только закрытые свечи - иначе и быть не может.

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

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

 
но вот видите ничего страшного....
 

Скажите пожалуйста, кто уже разобрался в тонкостях мкл5..

сейчас индикатор такого типа : у меня отрисовывается прямоугольничками. Происходит это довольно долго, да и множество объектов притормаживает терминал. Можно ли в МТ5 оптимизировать отрисовку такого типа? в плане как скорости, так и нагрузки. Если да,то как (в общих чертах).

Спасибо

Причина обращения: