При смене инструмента графика в Lua индикаторе OnDestroy() не вызывается

Страницы: 1
RSS
При смене инструмента графика в Lua индикаторе OnDestroy() не вызывается
 
Добрый день
Вопрос поднимался еще в 2017г  и был принят поддержкой :)

При смене инструмента графика OnDestroy() по прежнему не вызывается
Вопрос - скажем скрипт-индикатор создает метку на графике Меняете инструмент и метка остается, причем скрипт полностью ее теряет
Как ее удалить в коде скрипта перед тем как инструмент будет заменен или сохранить доступ к ней?
Глобальные переменные обнулились, идентификатор метки тоже утерян
 
На каждом I == 1 проверяете инструмент, если он не совпадает с предыдущим, удаляете метку. Т.е. удаляете после смены инструмента, не до.
 
Никто из сообщества не откликнулся. Обращаюсь к разработчикам.
Господа. Это не пожелание а вопрос некорректной работы терминала Терминал теряет метки.
Создав метку на одном инструменте и переключившись на другой инструмент метка полностью теряется.
Ее уже невозможно удалить ни стандартными функциями:
- DelLabel(), потому что после смены инструмента  id метки после переинициализации уже не существует
- DelAllLabels() даже при том что chart_tag прежний эту метку уже не находит
ни перебором в коде типа...

Код
local n = 0;
for _label_id = 1, 1000, 1 do
   local L = GetLabelParams(chart_tag, _label_id )--table or nil
   if L~= nil  then
      n = n + 1;
      if L.hint:find("PnL")  
         then DelLabel(chart_tag, _label_id)
      end;
   end
end 

В результате переключившись пару раз на другие инструменты и вернувшись на изначальный получите вот такую картинку :)

Какое решение найдут разработчики - не знаю Но ситуация требует исправления.

Возможно подключать OnDestroy() при смене инструмента, либо увязать это с параметром диаграммы - "Оставлять трендовые линии, фигуры и метки при смене инструмента"

 
Цитата
funduk написал:
На каждом I == 1 проверяете инструмент, если он не совпадает с предыдущим, удаляете метку. Т.е. удаляете после смены инструмента, не до.
Спасибо за ответ Но после смены инструмента ситуацию я только что описал - метку в коде уже не найти и соответственно не удалить
Кроме того часто бывают ситуации когда пкм на графике не дает уже "Удалить - Все метки в диаграмме"
Да и как после смены инструмента получить тикер предыдущего? После инита все переменные уже "обнулены"  в том числе и id метка.
Ну разве что в файле хранить, и постоянно сравнивать запись в файле с текущим  :what:  
 
Проблема с метками существует с древних времен - здесь и  здесь  и  здесь и с моим участием  здесь
По второй ссылке - ответ Daniil Pozdnyakov типовой "К сожалению, проблему, о которой ведётся речь, воспроизвести не удалось"н
Ну киньте индикатор что приводит пользователь по данной ссылке, переключите несколько раз между двумя инструментами график и увидите см файл - screen_1
Ну что еще нужно чтобы "воспроизвести" ошибку в работе терминала
По ссылке обсуждения с моим участием еще в 2021 еще на версии терминала 9.3 ответ того же  Daniil Pozdnyakov   "Описанная в данном обращении проблема была устранена в версии 9.4.0 терминала QUIK." а проблема как была так и переходит уже несколько лет
 
Такой вопрос - где и как происходит прерывание расчетов в текущем цикле OnCulculate() при смене инструмента на графике? Цикл доходит до конца или прерывается случайным образом

Цель выполнить кусок кода по удалению текущей метки которая после смены инструмента уже "потеряется"
 
При наложении индикатора или при периинициализации при смене инструмента графика терминал даже ни видит переменных объявленных в Settings

А увидит он идентификатор только на втором проходе  Как тут метки не потерять :)

Тяжелая у вас работа парни (разработчики) За 20 лет как познакомился с этим монстром ничего не изменилось Кракозябы накапливаются и наслаиваются одни на другие

Код
-- ----- Первичное добавление индикатора -----
-- Init() > OnCalculate() > OnChangeSettings() > OnCalculate() 2 > OnCalculate() 3

Код
Settings=
{
Name = "Example1",
chart_ID = ''         -- идентификатор графика
}

function Init()
   if Settings.chart_ID == '' then message('Init() Chart ID не указан!!!') end;
   return 1
end

function OnCalculate(index)
    if index == Size() then
      if Settings.chart_ID == '' then message('OnCalculate Chart ID не указан!!!'); end;
   end
   return nil
end

 
Сергей, добрый день. Получили от Вас информацию на почте. По итогам разбора продублируем наш ответ в данной теме форума.
 
За то за это время разработчики сделали для пользователей очень удобную весч - якорек на графике для переключения инструменов.
Классно, можно переключать десяток инструментов имея один открытый график. А то, что метки всех инструментов торчат
на одном и том же графике по всем углам, это не проблема шерифа.
 
Цитата
Kolossi написал:
это не проблема шерифа
Похоже не все понимают о чем речь... или не посмотрели ссылки на предыдущие обращения с аналогичной тематикой :)
Причина моего обращения в техподдержку и этой темы в следующем:
1. При добавлении скрипта индикатора на график  на первом проходе OnCalculate() скрипт не видит параметры настроек.  Вызов OnChange() происходит между 1 и 2ым проходами Проблема известная но тем не менее...
2. Метки созданные на графике при смене инструмента не удаляются в связи с отсутствием вызова OnDestroy()  перед заменой актива Это приводит к образовании новых меток по количеству переходов с актива на актив

Для детального понимания процессов я прикладываю скрипт индикатора для наблюдения за порядком расчетов и лог файл
Скрипт создает единственную метку с динамически меняющимися параметрами на вновь образующемся баре Метка создается на первом тике бара с удалением предыдущей
В течении бара метку можно сдвинуть в удобное место, на новом баре она займет "свое" место  на HighestHigh(10) по оси Y и смещением на 3 бара влево по оси времени. В текстовый параметр запишем Close() посл свечи а в Hint номер посл бара
Сам тест
- добавляем скрипт индикатора и сразу же вводим идентификатор графика
- смотрим DebugView

В отладчике смотрим порядок вызова функций при добавлении индикатора:
Init() > OnCalculate() > OnChangeSettings() > OnCalculate() 2 > OnCalculate() 3
Первый вывод - первый проход до вызова OnChange входящие параметры скрипта недоступны, т.е. никакие расчеты этого цикла некорректны Поэтому делаем обход этого прохода
Понаблюдав за меткой, отображением цены закрытия и номера бара, переместив ее в удобное место - переключаем таймфрейм - предыдущая метка удаляется и создается новая так же как на поступлении нового бара
При смене таймфрейма  сразу вызывается OnCalculate()  без инита и без опроса параметров скрипта.  Все работает корректно

Теперь  переключаемся на другой инструмент (пусть из табл тек торгов)
 В логе видим инициализацию и цикл расчетов на новом активе
   Init() > OnChangeSettings() > OnCalculate() 1
Делаем выводы по порядку следования функций.
Метка создается новая, к метке от предыдущего инструмента доступа нет, OnDestroy() не вызвается, метка "теряется" и доступ к ней скрипт не имеет
Повторяем процедуру несколько раз и наблюдаем наслоение меток на графике и на одном и на втором инструментах
  см скрин   test-2_переключ-инструментов.jpg
Удаляем индикатор с графика
Одна метка при этом остается на графике и не видна из меню пкм-удалить...
Удаляется после выделения клавишей DEL    
Смотрим какие функции используются в коде для удаления меток
Детально анализируем  лог файл в DebugView
Делаем выводы

Код скрипта индикатора
Код
Settings=
{
Name = "test_Example-2",
chart_ID = ''       -- идентификатор графика
}

n_init = 0         -- переменная для подсчета заходов в функцию Init
n_OnCalcCount = 0   -- переменная для подсчета OnCalculate
n_OnChange = 0      -- счетчик OnChangeSettings
bars_prev = 0       -- номер посл бара
TF_prev = -4;      -- таймфрейм
delay = 1.0;      -- задержка в цикле рассчетов параметров для метки (параметров счета)
LastSecond = 0;      -- время последнеих рассчетов 
chart_tag = '';      -- идентификатор графика
label_params = {};   -- параметры метки
Label_ID = nil;      -- идентификатор графика
Labels = {};         -- Массив номеров установленных меток - для контроля

function Init()
   n_init = n_init + 1
PrintDbgStr("Init() = "..n_init)
   n_OnCalcCount = 0
   n_OnChange = 0
   bar_prev = 0
   TF_prev = -4      -- контроль смены таймфрейма
   sec_code_prev = ''   -- контроль перекл на др актив
   
   return 1
end

function OnChangeSettings()
--   n_OnCalcCount = 0
   n_OnChange = n_OnChange + 1
   chart_tag = Settings.chart_ID
PrintDbgStr("OnChangeSettings() = "..n_OnChange..', n_OnCalcCount = '..n_OnCalcCount)
end

function OnDestroy()
PrintDbgStr("OnDestroy() #Labels Array "..#Labels);
   if #Labels > 0 then -- Удаляет ранее установленные метки
      for i=1,#Labels,1 do
         local del = DelLabel(chart_tag, Labels[i]);   
      if del then PrintDbgStr("OnDestroy() Del id "..tostring(Labels[i]));  end;
      end;
   end;
   -- стараемся найти и удалить потерянные метки 
   PrintDbgStr("OnDestroy() LbDelete_2() "..LbDelete_2() .. ' labels were removed');
 
end


function OnCalculate(index)


    -- Пропускаем первый проход между Init() и OnChangeSettings() при первичном  добавлении индикатора
    -- для исключения ошибки чтения параметра при первом запуске индикатора
    -- Init() > OnCalculate() > OnChangeSettings() > OnCalculate() 2 > OnCalculate() 3
   if n_OnChange == 0 then 
      while index <= Size()  do
         if index == Size() then PrintDbgStr('Пропускаем цикл до вызова OnChangeSettings() после Init(), index = ' .. index); end;
         return
      end;
   end
  
    -- предпоследний бар
   if index == Size() - 1 then
PrintDbgStr('---- Begin Cycle Number '..(n_OnCalcCount+1))
       
      DSInfo   = getDataSourceInfo();
      Sec_Code = DSInfo.sec_code;
            
      if chart_tag == '' then message('OnCalculate Chart ID не указан!!!'); end;
PrintDbgStr("Seccode " .. Sec_Code ..",  chart_ID = " .. chart_tag)
            
   else
       -- последняя свеча
      if index == Size() then
          -- раз в секунду (или больше)   
         if os.time() > LastSecond  then            -- if os.time() > LastSecond + 2*delay-1 then
            LastSecond = os.time();
         
             -- потиковое обновление (с задержкой)   
            label_params['TEXT'] = tostring(C(index))
            label_params['HINT'] = tostring(index)

            -- корректируем параметры метки   
            if Label_ID  ~= nil and TF_prev == DSInfo.interval then
               -- сохраняем прежнее положение метки если переместили в теч текущ бара)
                -- при смене таймфрейма метка будет удалена и создана заново
               local ly = GetLabelParams(chart_tag, Label_ID)   --table or nil
               if ly ~= nil then   -- and ly.yvalue ~= nil 
                  label_params['YVALUE'] = ly.yvalue
                  label_params['DATE']   = ly.date
                  label_params['TIME']   = ly.time         
               end;
--PrintDbgStr('index == Size() = ' .. Size() .. ', Label_ID  ' .. Label_ID .. ', C(index) ' .. tostring(C(index))   )   
               SetLabelParams(chart_tag, Label_ID, label_params);
--   PrintDbgStr('SetLabelParams Label_ID = '..Label_ID)
            end         
                           
            -- первый тик нового бара или первый проход и метка еще не создавалась или смена таймфрейма
            -- удаляем предыдущую и создаем новую метку с новыми координатами (метку можно смещать в удобное место...)
            if bars_prev < Size() or Label_ID == nil or TF_prev ~= DSInfo.interval then
               bars_prev = Size()
               -- удаляем метку если она уже была и создаем новую
               if Label_ID ~= nil then LbDelete() end;   
               Label_ID = labeldraw(chart_tag, index)
               TF_prev = DSInfo.interval
            
            end;


         end -- every second
         -- завершение цикла
         n_OnCalcCount = n_OnCalcCount+1
   --PrintDbgStr('END Cycle index == Size() ' .. Size()..', n_OnCalcCount = '..n_OnCalcCount)
      end -- index == Size()         
         
   end -- if index > 1 
   
   return nil
end

function labeldraw(tag, index)
 
   local highest = 0.0   
   for j = 0, 14 do
      if H(index-j) > highest then highest = H(index-j) end;
   end

   local _t =    T(index-3)
   --PrintDbgStr(_t.year.._t.month.._t.day..' '.._t.hour..':'.._t.min..':'.._t.sec)
   local Y = tostring(_t.year)
   local m = tostring(_t.month)   if #m  == 1 then  m = "0"..m  end;
   local d = tostring(_t.day)      if #d  == 1 then  d = "0"..d  end;
   local hh = tostring(_t.hour)   if #hh == 1 then hh = "0"..hh end;
   local mm = tostring(_t.min)      if #mm == 1 then mm = "0"..mm end;
   local ss = '00'; -- tostring(_t.sec) if #ss == 1 then ss = "0"..ss end;

   label_params['DATE'] = tonumber(Y..m..d);
   label_params['TIME'] = tonumber(hh..mm..ss);
   label_params['YVALUE'] = highest;
   label_params['R'] = 0; -- DOUBLE Красная компонента цвета в формате RGB. Число в интервале [0;255]
   label_params['G'] = 0; -- DOUBLE Зеленая компонента цвета в формате RGB. Число в интервале [0;255]
   label_params['B'] = 255; -- DOUBLE Синяя компонента цвета в формате RGB. Число в интервале [0;255]
   label_params['TRANSPARENCY'] = 0;
   label_params['TRANSPARENT_BACKGROUND'] = 1;
   label_params['FONT_FACE_NAME'] = 'Verdana';
   label_params['FONT_HEIGHT'] = 12;

   local label_id = AddLabel(tag, label_params) -- number
   if label_id  ~= nil then
       Labels[#Labels+1] = label_id
      PrintDbgStr('Create Label_id: '..tostring(label_id)) 
   else 
      message('Don\'t create label')
   end

   return label_id  -- number

end


----  удаление меток
-- ищем и удаляем все метки независимо как и кем установленные :) 
-- функцию используем полной очистки от меток и контроля 
function LbDelete_2()
--   local _labels = {}
    local n = 0;
   for _label_id = 1, 10000, 1 do
      local L = GetLabelParams(chart_tag, _label_id )--table or nil  Табл параметров метки - все значения имеют тип – STRING
      if L ~= nil  then
         local del = DelLabel(chart_tag, _label_id)
         if del == true then 
            n = n + 1;
PrintDbgStr('LbDelete_2() Label number '..tostring(_label_id).. ' deleted ')
         end; 
      end
   end
   Label_ID = nil;
   Labels = {}
   return n;
end
-- Удаляет ранее установленные метки сохраненые в массиве
function LbDelete()
   local n = 0
   if #Labels > 0 then 
      for j=1,#Labels,1 do          
         if DelLabel(chart_tag, tonumber(Labels[j])) then 
            n = n + 1
PrintDbgStr("LbDelete() id "..tostring(Labels[j]) .. ' deleted')
          end
      end;
      Labels = {};
      Label_ID = nil;
   end;
   return n;
end;

 
Andrey Golik,
Цитата
Andrey Golik написал:
Сергей, добрый день. Получили от Вас информацию на почте. По итогам разбора продублируем наш ответ в данной теме форума.
Добрый день Есть какие то ориентиры по времени устранения описанной проблемы
 
Сергей, здравствуйте.

К сожалению, сориентировать по срокам не можем.
Как только версия Рабочего места QUIK с исправлением будет выпущена - Вас сразу же проинформируют об этом (уведомление поступит на электронный адрес, указанный в письме, по которому был заведен тикет).
Приносим свои извинения за доставленные неудобства и задержку.
Страницы: 1
Читают тему
Наверх