Как сохранить ссылку или указатель на массив, полученный в OnCalculate() ? Что сейчас предлагают разработчики ?

 

Очередной раз сталкиваюсь со старой проблемой - в OnCalculate() передаются массивы, с которыми работает индикатор.

Как сохранить указатели или ссылки на них, чтобы затем обращаться к необходимым данным ?

Как я понимаю, по-прежнему есть только два не больно приятных варианта.

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

2. На каждом OnCalculate() сперва копировать данные массивов в свой массив типа CArrayDouble - и сохранять указатель на него, в дальнейшем использовать именно его.


Мне оба варианта совершенно не нравятся.

В первом - невозможно использовать структуру классов. (Скажем, у вас есть класс, вычисляющий канал, который получает данные с помощью виртуальных функций - как передать в него указатели на массивы OHLC ?)

Во втором - на каждом вызове OnCalculate() происходит совершенно излишнее копирование всего массива (ну или по крайней мере, той его части, которая будет пересчитана).


Изменилось ли сейчас что-то в этом плане ?

Было бы неплохо иметь функцию int OnCalculate(const int rates_total,const int prev_calculated,const CArrayDatetime* time, const CArayDouble* open, CArrayDouble* high...) - в общем, аналог функйи OnCalculate(), работающий с объектами Стандартной Библиотеки, на которые можно сохранять указатели, а не с массивами, на который ни указателей, ни ссылок нет.  


Вобще, хотелось бы знать, как народ работает с этими массивами в сложных многуровневых вложенных функциях и классах ?

 
George Merts:

аналог функйи OnCalculate(), работающий с объектами Стандартной Библиотеки

Категорически против встроенности СБ в язык.

Делайте Calculate-буферы для Open, High и т.д. В OnCalculate только дописывайте rates_total-prev_calculated. И работайте с буферами уже, которые видны везде. 

 
fxsaber:

Категорически против встроенности СБ в язык.

А никто ничего встраивать не предлагает.

Я говорю, что было бы хорошо иметь ДОПОЛНИТЕЛЬНО такую функцию. Чтобы копирование сразу было в объекты типа CArrayDouble.

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

fxsaber:

Делайте Calculate-буферы для Open, High и т.д. В OnCalculate только дописывайте rates_total-prev_calculated. И работайте с буферами уже, которые видны везде. 

И как обойтись без лишнего копирования ?

Вопрос как раз в том, чтобы обойтись без копирования. А то, что ты предлагаешь - я так и делаю, это второй вариант, который мне не нравится.

 

George Merts: 

Очередной раз сталкиваюсь со старой проблемой - в OnCalculate() передаются массивы, с которыми работает индикатор.

Как сохранить указатели или ссылки на них, чтобы затем обращаться к необходимым данным ?

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

George Merts:

Было бы неплохо иметь функцию int OnCalculate(const int rates_total,const int prev_calculated,const CArrayDatetime* time, const CArayDouble* open, CArrayDouble* high...) - в общем, аналог функйи OnCalculate(), работающий с объектами Стандартной Библиотеки, на которые можно сохранять указатели, а не с массивами, на который ни указателей, ни ссылок нет.  

Этого никогда не будет. Стандартные классы не в части у MQ, в том смысле что весь API к МТ написан без единого класса. Более коцептуально правильным решением было бы ввести третий формат iCustom:

//+------------------------------------------------------------------+
//| Accumulation/Distribution                                        |
//+------------------------------------------------------------------+
int OnCalculate(const int prev_calculated,
                const MqlRates &rates[]
                )
  {
  }

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

Также есть вариант забить на то, что дает сама iCustom и работать с котировками через функции Copy*, но этот вариант тоже имеет свои недостатки.

 
George Merts:

А то, что ты предлагаешь - я так и делаю, это второй вариант, который мне не нравится.

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

Т.е. не в свой массив, а именно в индикаторные буферы. 

 
Vasiliy Sokolov:
 
//+------------------------------------------------------------------+
//| Accumulation/Distribution                                        |
//+------------------------------------------------------------------+
int OnCalculate(const int prev_calculated,
                const MqlRates &rates[]
                )
  {
  }

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

Где ж "решается", если мы не можем сохранить ни эту ссылку, ни указатель на этот массив ?

В данном случае - просто массивы значений заменены массивом структур, но дополнительное копирование необходимо все равно.

 
fxsaber:

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

Т.е. не в свой массив, а именно в индикаторные буферы. 

А как иметь доступ к ним "при высокой вложенности" функций ? Предлагаешь опять же - тянуть ссылки через все вложенные функции ?
 
George Merts:
А как иметь доступ к ним "при высокой вложенности" функций ? Предлагаешь опять же - тянуть ссылки через все вложенные функции ?
Нет, это же индикаторные буферы. Ссылки на них незачем тянуть. Видны, как ::-массивы.
 
fxsaber:
Нет, это же индикаторные буферы. Ссылки на них незачем тянуть. Видны, как ::-массивы.

А... Понял. Да. Видны отовсюду.

А с копированием как ? Надо же, чтобы туда данные кто-то копировал ? Терминал копирует данные в исходные массивы, а потом мы еще их и в индикаторные передаем ? Неэффективно, по-моему.

Кстати, это тоже вариант - чтобы просто массивы, передаваемые в OnCalculate() - были бы глобальными. Тогда их никуда "тащить" не надо, они везде были бы видны.  Действительно. Тоже вполне годный.


А !!! Или ты предлагаешь создать индикаторые буффера, и именно их и использовать в OnCalculate(), чтобы терминал сразу их заполнял ? А они уже, видны везде, и мы используем данные из них ? А ну, а ну... попробуем... Хотя, интересно, как быть с буффером времени, объема и спреда... Ну, сейчас поглядим.

Что-то пишет "declaration of 'Open' hides global declaration at line 13 Buffers_Core.mq5" - похоже, не получается подсунуть в OnCalculate созданный буффер...
 
George Merts:

А !!! Или ты предлагаешь создать индикаторые буффера, и именно их и использовать в OnCalculate(), чтобы терминал сразу их заполнял ? А они уже, видны везде, и мы используем данные из них ? А ну, а ну... попробуем... Хотя, интересно, как быть с буффером времени, объема и спреда... Ну, сейчас поглядим.

Индикаторные буферы для этой цели годятся больше, чем просто массивы, т.к. не нужно контролировать размер массива, сдвиги цен и т.д. Надо только в OnCalculate  в начале прописать дописывание в индикаторный буфер N (rates_total - prev_calculated) значений.

Но, честно говоря, не сталкивался с навязанной тягой хвостов. Наверное, сложных индикаторов не писал.

 
fxsaber:

Индикаторные буферы для этой цели годятся больше, чем просто массивы, т.к. не нужно контролировать размер массива, сдвиги цен и т.д. Надо только в OnCalculate  в начале прописать дописывание в индикаторный буфер N (rates_total - prev_calculated) значений.

Но, честно говоря, не сталкивался с навязанной тягой хвостов. Наверное, сложных индикаторов не писал.

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

Внутри класса данные запрашиваются с помощью виртуальной функции double GetPrice(int iIdx). То есть, когда ты хочешь построить этот самый канал регрессии третьей степени - тебе достаточно пронаследовать класс, и перегрузить в нем эту самую виртуальную функцию, возвращая значения цены по указанному индексу. После чего вызываешь GetCubic() - и рисуешь свои параболы.

Как передать в функцию GetPrice(int iIdx) значения из массива Close[iIdx] ?

Был бы массив виден везде - никаких вопросов бы не возникло. Можно было бы запомнить указатель или ссылку на него - опять же, никаких вопросов. А так - приходится сперва переписывать значения в промежуточный буффер, и потом отдавать их в виртуальной функции GetPrice().

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