Робот создает много индикаторов при переключении таймфреймов. - страница 2

[Удален]  
Stanislav Korotky #:

Можете не бояться функции ChartIndicatorAdd и применять её, когда надо показать используемый в эксперте индикатор на графике (это бывает полезно). Только не забывайте освобождать дескриптор после добавления индюка на график, потому что его привязка к эксперту в этом случае уже лишняя (получается 2 "хозяина", и индюк не освобождается).

Спасибо, Станислав, мне удалось ! Всем спасибо, задача по итогу филигранно решена
 
Stanislav Korotky #:

Можете не бояться функции ChartIndicatorAdd и применять её, когда надо показать используемый в эксперте индикатор на графике (это бывает полезно). Только не забывайте освобождать дескриптор после добавления индюка на график, потому что его привязка к эксперту в этом случае уже лишняя (получается 2 "хозяина", и индюк не освобождается).

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

Последовательное удаление индикатора с графика и освобождение хэндла иногда не срабатывает при относительном слабом VPS, или при намеренно частом и быстром переключении таймфреймов на относительно мощном ПК, а хочется надежное решение.

При таких же условиях shortname в индикаторе может назначаться не так как ожидалось:

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

Станислав, правильно ли я понимаю вашу идею, что мне нужно:

1. Получить handle1 индикатора для копирования данных в советник.

2. Получить handle2 индикатора с теми же настройками, добавить его на график для визуализации и сделать IndicatorRelease(handle2).

3. В OnDeinit() советника:

     if(reason !=3) // Это прекращение работы эксперта. Освобождение хэндлов и удаление индикаторов
     {
      IndicatorRelease(handle1);
      RemoveBotIndicatorsFromChart(ChartID()); // Процедура перебора индикаторов по всем окнам графика и их удаления
      IndicatorRelease(handle2);
     }
   else // Это смена TF. Освобождение handle1 для переинициализации скрытого индикатора на новом TF, а отображаемый индикатор переключится сам
     {
      IndicatorRelease(hadle1);
      handle1 = INVALID_NANDLE;
     }
 
Sunriser #:

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


в аналогичном случае, чтобы видеть индикаторы советника - они в OnInit создаются iCustom и далее ChartIndicatorAdd, в OnDeinit при любом reason - если индикатор был успешно добавлен то он удаляется ChartIndicatorDelete

единственный нюанс - все индикаторы самопальные (или перелицованные стандартные) их ShortName назначается советником и передаётся в параметрах. Иначе с именованиями и уникальностью индикаторов чехарда.

 
Maxim Kuznetsov #:

в аналогичном случае, чтобы видеть индикаторы советника - они в OnInit создаются iCustom и далее ChartIndicatorAdd, в OnDeinit при любом reason - если индикатор был успешно добавлен то он удаляется ChartIndicatorDelete

единственный нюанс - все индикаторы самопальные (или перелицованные стандартные) их ShortName назначается советником и передаётся в параметрах. Иначе с именованиями и уникальностью индикаторов чехарда.

Вот именно так я и делал и это оказалось ненадежным. Если начать быстро тыкать по разным таймфреймам, то через какое-то время появляются "левые" индикаторы. 

Пробовал добавлять //#include <Init_Sync.mqh> // Делает синхронизированными Init/Deinit индикаторов - не помогло, впрочем у меня и не получилось воспроизвести ту проблему, из-за которой fxsaber написал эту библиотеку.

ChartIndicatorDelete может возвращать true, но при этом индикатор может не удалиться с первого раза, приходится повторно вызывать до тех пор, пока за цикл перебора никаких индикаторов найдено не будет. Разные костыли уж пробовал. Про shortname написал в предыдущем сообщении.

 
Sunriser #:

Вот именно так я и делал и это оказалось ненадежным. Если начать быстро тыкать по разным таймфреймам, то через какое-то время появляются "левые" индикаторы. 

Пробовал добавлять //#include <Init_Sync.mqh> // Делает синхронизированными Init/Deinit индикаторов - не помогло, впрочем у меня и не получилось воспроизвести ту проблему, из-за которой fxsaber написал эту библиотеку.

ChartIndicatorDelete может возвращать true, но при этом индикатор может не удалиться с первого раза, приходится повторно вызывать до тех пор, пока за цикл перебора никаких индикаторов найдено не будет. Разные костыли уж пробовал. Про shortname написал в предыдущем сообщении.

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

Насколько я помню, расчетная часть индикатора удаляется отложенным образом - MQ это сделали в расчете на быстрый старт индикатора, если он снова понадобится. Но с позиции кода, который запрашивает индикатор, это обычно не критично. Вы можете определить, получили хэндл от "старого"  закешированного индикатора или нового, вызвав BarsCalculated сразу после получения хендла: новый индикатор еще не будет рассчитан.

 
Sunriser #:
else // Это смена TF. Освобождение handle1 для переинициализации скрытого индикатора на новом TF, а отображаемый индикатор переключится сам

вот эта часть потенциально порождает дополнительные индикаторы. Советник же тоже рестартует и начинает всё с начала с OnInit, вы уверены что он там будет искать и обязательно найдёт прежние индикаторы ? Получится чей OnInit впереди того и тапки

всегда удаляйте созданные экзепляры. 

 
Stanislav Korotky #:

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

Насколько я помню, расчетная часть индикатора удаляется отложенным образом - MQ это сделали в расчете на быстрый старт индикатора, если он снова понадобится. Но с позиции кода, который запрашивает индикатор, это обычно не критично. Вы можете определить, получили хэндл от "старого"  закешированного индикатора или нового, вызвав BarsCalculated сразу после получения хендла: новый индикатор еще не будет рассчитан.

Вот пример советника и индикатора.

Эксперт передает в индикатор строковый ключ IDKey = "madebyea", чтобы иметь возможность в будущем отличить индикатор, созданный советником от добавленного вручную.

Завершение инициализации советника иногда происходит позже инициализации индикатора и shortname с присутствующим IDKey эксперт начинает видеть не с первого принта, но далее принтуется нормально.

При смене TF эксперт находит индикатор с shortname снова без IDKey, не считает за своего и поэтому не пытается удалить его с графика:

2025.12.27 16:02:47.744 Indicator_01 (LTCUSDT_binance,M30)      PERIOD_M30 madebyea_CustomBB_PERIOD_M30 qTick: 10
2025.12.27 16:02:47.745 Expert_01 (LTCUSDT_binance,M30) indicatorsEnumeration win: 1 of: 2 i: 0 of: 1 Вижу индикатор: madebyea_Custom_PERIOD_M30
2025.12.27 16:02:47.745 Expert_01 (LTCUSDT_binance,M30) Expert. ind_buf[0]:10.0
2025.12.27 16:02:47.857 Indicator_01 (LTCUSDT_binance,M30)      PERIOD_M30 madebyea_Custom_PERIOD_M30 qTick: 11
2025.12.27 16:02:47.858 Expert_01 (LTCUSDT_binance,M30) indicatorsEnumeration win: 1 of: 2 i: 0 of: 1 Вижу индикатор: madebyea_Custom_PERIOD_M30
2025.12.27 16:02:47.858 Expert_01 (LTCUSDT_binance,M30) Expert. ind_buf[0]:11.0
2025.12.27 16:02:48.282 Expert_01 (LTCUSDT_binance,M30) Expert OnDeinit REASON_CHARTCHANGE: Символ или период графика был изменен
2025.12.27 16:02:48.295 Expert_01 (LTCUSDT_binance,M30) RemoveBotIndicatorsFromChart win: 1 of: 2 i: 0 of: 1 Вижу индикатор: Indicator_01
2025.12.27 16:02:48.295 Expert_01 (LTCUSDT_binance,M30) RemoveBotIndicatorsFromChart Индикатор с IDKey madebyea НЕ НАЙДЕН!
2025.12.27 16:02:48.296 Expert_01 (LTCUSDT_binance,H2)  Expert OnInit
2025.12.27 16:02:48.296 Expert_01 (LTCUSDT_binance,H2)  Expert. Получен новый ind_handle: 10
2025.12.27 16:02:48.297 Indicator_01 (LTCUSDT_binance,H2)       OnInit PERIOD_H2 createdBy?: madebyea

Билд 5440

Файлы:
 

Покопался в проблеме. Слегка модифицированные под себя исходники прикладываю. Логи тоже. Решение тоже.

Внимание! Присутствует баг терминала.

Примерное понимание - такое. Если тиков нет (они редко приходят) или переключение таймфреймов происходит очень быстро (до прихода очередного тика), терминал НЕ ТОРОПИТСЯ делать OnInit создаваемого индикатора. Единственное, что может его пошевелить - и это решение проблемы - холостой вызов CopyBuffer сразу после получения хендла в эксперте.

Это решение имеет один побочный минус - подокно индикатора появляется с заметной задержкой. Сами решайте - кому что важнее.

А теперь конкретно - БАГ. Если делать переключение таймфрейма в промежуток времени между тем, как мы заказали создание индикатора и его OnInit (то есть он не то что ещё не завершен, а точнее даже не начат из-за "неторопливости"), то последующая инициализация его происходит для нового таймфрейма и БЕЗ проверки того, что экземпляр этого же индикатора с точно такими же параметрами и новым таймфреймом уже есть (закешированная копия, которая в виде расчетной части остается в терминале на всякий случай, некоторое время до истечения таймаута неиспользования индикатора). Скорее всего, такая проверка стоит в терминале перед вызовом OnInit, но происходит для старого таймфрейма. Когда же приходит тик, а таймфрейм графика уже сменился, OnInit вызывается для нового таймфрейма. В результате получаются либо задвоенные полностью идентичные индюки (если пришел тик) или один из экземпляров остается висеть непроинициализированным (если меняем ТФ до тика), то есть он сам себе не установил еще нужный shortname.

В логах смотрите контекстные комментарии после двойной косой черты.

В эксперте определите макрос SHOW_ME_BUG, чтобы увидеть проблему.