| Цитата | 
|---|
| 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;
 |