Ошибка скрипта после переподключения

Страницы: 1
RSS
Ошибка скрипта после переподключения
 
Использую мобильный интернет для торговли. После потери соединения Quik 8.11 начинает переподключаться. После переподключения останавливается скрипт и запускается только руками.
Все расчеты в
is_run = True
function main()
....while is_run do
...
end

Функцию OnStop() не использую, пробовал с ней, результат такой-же.
function OnStop()
....is_run = false
end

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

Поэтому возникают следующие вопросы:
1) Скрипт молча останавливается или ошибку какую выдает?
2) Если вручную переподключиться, скрипт остановится?
3) Если ли в скрипте колбеки onConnected, onDisconnected, onCleanUp? Если есть, то что в них?
4) Используется ли проверка подключеия isConnected? Если используется, то как именно?

В идеале показали бы скрипт, предварительно удалив из него то, что считаете ком.тайной.
 
Цитата
BlaZed написал:
Скрипт не должен завершаться при разрыве соединения, если, конечно, это специально не реализовано.

Поэтому возникают следующие вопросы:
1) Скрипт молча останавливается или ошибку какую выдает?
2) Если вручную переподключиться, скрипт остановится?
3) Если ли в скрипте колбеки onConnected, onDisconnected, onCleanUp? Если есть, то что в них?
4) Используется ли проверка подключеия isConnected? Если используется, то как именно?

В идеале показали бы скрипт, предварительно удалив из него то, что считаете ком.тайной.
1. Останавливается без ошибок
2. Работает
3. Нет
4. Нет

-- параметры
is_run=true
ticker_list = {"EUR_RUB__TOM", "USD000UTSTOM"}
iNterval=INTERVAL_M15
corrTime=3
pFile="C:\\QUIK\\script\\"
cBars=1

--настройка параметров
function strText(int)
local m=tostring(int)
local mLen=string.len(int)

if mLen==1 then
Output="0" ..tostring(m)
else Output=m
end
return Output
end


function main()
while is_run do
for key, instrument in pairs(ticker_list) do --в цикле перебираем бумаги из ticker_list
classcode=getSecurityInfo("",instrument).class_code --получаем класс бумаги (TQBR,SPBFUT,CETS,ect.) по ее тикеру
out_file=io.open(pFile..instrument..".csv","w") --открываем с режимом для перезаписи

ds=CreateDataSource(classcode, instrument, iNterval ) --создаем источник данных
ds:SetUpdateCallback(NewChartData) --обновление последних данных (NewChartData)
local Size=ds:Size()
if Size>0 then

if cBars>Size then
cBars=Size-1
end

out_file:write("<DATE>,<TIME>,<OPEN>,<HIGH>,<LOW>,<CLOSE>,<VOL>\n") -- записываем название колонок

for i=Size-cBars, Size, 1 do
local O=ds:O(i)
local H=ds:H(i)
local L=ds:L(i)
local C=ds:C(i)
local V=ds:V(i)
local T=ds:T(i)

sTime=os.time(T)
datetime=os.date("!*t",sTime)

--вывод в файл
out_file:write(tostring(datetime.year)..tostring(strText(datetime.month))..tostring(strText(datetime.day))..","..tostring(strText(datetime.hour + corrTime))..tostring(strText(datetime.min))..tostring(strText(datetime.sec))..","..tostring(O)..","..tostring(H)..","..tostring(L)..","..tostring©..","..tostring(V).."\n")
out_file:flush() --сохраняем изменения
end
out_file:close() --закрываем файл
end
end
sleep(3000)   -- приостановка на 3 секунды
end
end
 
2. Если вручную переподключить соединение с интернетом, так же останавливается. После ручного запуска - работает до ручной остановки или переподключения интернета
 
При потере связи скрипт ругается на строчку
Код
      classcode=getSecurityInfo("",instrument).class_code --получаем класс бумаги (TQBR,SPBFUT,CETS,ect.) по ее тикеру
и вываливается с ошибкой
Код
C:\Scripts\Testers\1.lua:27: attempt to index a nil value
Я же спрашивал выдает ли скрипт какую ошибку... а говорите что молча останавливается

Тут решение сразу же напрашивается такое.
Вынести расчет classcode (а так же out_file и ds) за пределы бесконечного цикла с проверкой наличия соединения isConnected(), и поместить в массив, а в цикле уже брать значения из массива.
Нет никакого смысла каждый раз их заново находить, достаточно одного раза.
 
Ну или можно обернуть в проверку соединения
Код
function main()
  while is_run do
    if(isConnected()==1)then
--- ТУТ ВАШ КОД --
    end
    sleep(3000)
  end
end
но код вам явно причесать не помешало бы, слишком много ненужных повторов действий
 
Цитата
BlaZed написал:
Ну или можно обернуть в проверку соединения
Код
   function   main ()
   while  is_run  do 
     if ( isConnected () =  =  1 ) then 
 --- ТУТ ВАШ КОД -- 
     end 
     sleep ( 3000 )
   end 
 end   
но код вам явно причесать не помешало бы, слишком много ненужных повторов действий
Благодарю за отклик и скорую помощь! Сделаю как вы советуете.
 
Цитата
BlaZed написал:
Ну или можно обернуть в проверку соединения
Эта конструкция не сработала. Попробую первый вариант, вынести 'classcode (а так же out_file и ds)' в OnInit()
 
Я заметил, что classcode=getSecurityInfo("",instrument).class_code может быть nill даже когда связь установлена, вероятно не успевают загрузиться данные getSecurityInfo().
В init тоже не вариант..
Здесь бы очень подошло что-то вроде try-exeptions как в python, но я не знаю пока как это делать на lua
 
Цитата
BlaZed написал:
Ну или можно обернуть в проверку соединения
Забираю свои слова обратно, это работает. Хотя странно повело по началу, наверное мне показалось
 
Все таки if (isConnected () ==  1) then работает через раз, все-таки не показалось. Долго работало нормально, а сегодня после очередного дисконнекта скрипт снова отвалился, с той же ошибкой в 27 строке - nil . Сорри за столько сообщений, но я не нашел как редактировать или удалить написанные сообщения
 
В общем, если у кого вдруг похожая проблема, решение банальное - проверкой на nil. Сейчас работает надежно, независимо от  коннекта к серверу:
while do
....if classcode~=nil then
........body

....end
end
Отдельное спасибо BlaZed, за то, что натолкнул на мысли
 
Цитата
Sergey написал:
Сейчас работает надежно, независимо от  коннекта к серверу:
Ну как вам сказать... скрипт ругался на невозможность получить getSecurityInfo("",instrument).class_code


Цитата
Sergey написал:
if classcode~=nil then
Такая проверка не поможет, ибо classcode у вас глобальная и после первой же итерации всегда будет не nil если инструмент существует, и по такому условию просто каждую итерацию скрипт будет пропускать
 
Цитата
BlaZed написал:
Цитата
Sergey написал:
Сейчас работает надежно, независимо от  коннекта к серверу:
Ну как вам сказать... скрипт ругался на невозможность получить getSecurityInfo("",instrument).class_code


Цитата
Sergey написал:
if classcode~=nil then
Такая проверка не поможет, ибо classcode у вас глобальная и после первой же итерации всегда будет не nil если инструмент существует, и по такому условию просто каждую итерацию скрипт будет пропускать
classcode не глобальная - локальная в цикле for
 
попробуйте сами:
function main()
....while is_run do
....sleep(3000)
........for key, instrument in pairs(ticker_list) do
............classcode=getSecurityInfo("",instrument).class_code
............if classcode~=nil then
................тут без изменений

............end
........end
....end
end
 
Цитата
Sergey написал:
classcode не глобальная - локальная в цикле for
Неа, она у вас именно глобальная. Обратитесь из любой другой функции к переменной classcode и удивитесь.

Цитата
Sergey написал:
попробуйте сами:
Не согласен, так же как и раньше выдаст ошибку на строчке
Код
classcode=getSecurityInfo("",instrument).class_code
и до проверки classcode==nil просто не дойдет

Тут дело в том, что ошибка плавающая, и будет появляться если удачно совпадет момент чтения данных из getSecurityInfo с моментом подключения к серверу, когда старые данные уже удалились, но еще не загрузились новые.
При вашем sleep(3000) это может быть, ну скажем 1 раз из 10 раз, а поставьте sleep(100), так сразу увидите, что ошибка никуда не делась.
 
Цитата
BlaZed написал:
Цитата
Sergey написал:
classcode не глобальная - локальная в цикле for
Неа, она у вас именно глобальная. Обратитесь из любой другой функции к переменной classcode и удивитесь.

Цитата
Sergey написал:
попробуйте сами:
Не согласен, так же как и раньше выдаст ошибку на строчке
Код
  classcode =  getSecurityInfo ( "" ,instrument).class_code  
и до проверки classcode==nil просто не дойдет

Тут дело в том, что ошибка плавающая, и будет появляться если удачно совпадет момент чтения данных из getSecurityInfo с моментом подключения к серверу, когда старые данные уже удалились, но еще не загрузились новые.
При вашем sleep(3000) это может быть, ну скажем 1 раз из 10 раз, а поставьте sleep(100), так сразу увидите, что ошибка никуда не делась.
Похоже что вы правы, без sleep() вылетает сразу. Вариант вынести все в OnInit()? Но ведь там тоже нет гарантии что переменная classcode успеет записаться сразу после инициализации скрипта, даже при условии проверки соединения и не вылетит с ошибкой
 
Цитата
Sergey написал:
Вариант вынести все в OnInit()? Но ведь там тоже нет гарантии что переменная classcode успеет записаться сразу после инициализации скрипта, даже при условии проверки соединения и не вылетит с ошибкой
Именно вариант с OnInit() в данном случае самый надежный, надо всего лишь добавить парочку дополнительных проверок.

Смотрите

во первых, меняем ticker_list, делаем его двухуровневым массивом
Код
ticker_list = {{"EUR_RUB__TOM"},{"USD000UTSTOM"},{"SiM1"},{"SiU1"}}
во-вторых, переносим все одноразовые предварительные вычисления в OnInit(), данные скидываем в массив, сюда же добавляем дополнительные проверки
Код
function OnInit()
  if(isConnected()==1)then
    for key,value in pairs(ticker_list) do --в цикле перебираем бумаги из ticker_list
      while(getSecurityInfo("",ticker_list[key][1])==nil)do sleep(100) end -- Ждем загрузки данных по инструменту
      ticker_list[key][2]=getSecurityInfo("",ticker_list[key][1]).class_code --получаем класс бумаги (TQBR,SPBFUT,CETS,ect.) по ее тикеру
      ticker_list[key][3]=CreateDataSource(ticker_list[key][2],ticker_list[key][1],iNterval) --создаем источник данных
    end
  end
end
в-третьих, убираем ненужные вычисления из main(), а данные берем из массива, который заполнили в OnInit()
Код
function main()
  while is_run do
    for key,value in pairs(ticker_list) do --в цикле перебираем бумаги из ticker_list
      instrument=value[1]
      classcode=value[2]
      ds=value[3]
      while(ds:Size()==0) do sleep(100) end -- Ждем загрузки данных графика
--ТУТ ВАШ КОД--
    end
    sleep(3000)   -- приостановка на 3 секунды
  end
end

Примерно так.
Думаю должно работать без ошибок
 
Ну и причесать код бы не помешало, а то смотреть больно
вместо
Код
sTime=os.time(T)
datetime=os.date("!*t",sTime)
out_file:write(tostring(datetime.year)..tostring(strText(datetime.month))..tostring(strText(datetime.day))..","..tostring(strText(datetime.hour + corrTime))..tostring(strText(datetime.min))..tostring(strText(datetime.sec))..","..tostring(O)..","..tostring(H)..","..tostring(L)..","..tostring(C)..","..tostring(V).."\n")
то же самое, только в нормальном виде
Код
datetime=os.date("!*t",os.time(T)+corrTime*3600)
out_file:write(string.format("%04d%02d%02d,%02d%02d%02d,%s,%s,%s,%s,%s\n",datetime.year,datetime.month,datetime.day,datetime.hour,datetime.min,datetime.sec,O,H,L,C,V))
и функция strText() как бы нафиг не нужна, ее возможности есть в string.format()
 
BlaZed спасибо! Мне теперь разбираться и проверять на пару дней.  
 
Цитата
BlaZed написал:
Ну и причесать код ...
Есть очень необычная странность, для акций с приставкой -гдр. У меня не работает выгрузка, например если:
ticker_list = {{"FIVE"}, {"TCSG"}}
 
Но если сделать прямо:

ticker="FIVE" --код инструмента/бумаги
classcode="TQBR" --код класса инструмента/бумаги, если нужен фондовый рынок - вводить TQBR вместо SPBFUT
iNterval=INTERVAL_D1 --таймфрейм

и подставить все в:

ds=CreateDataSource(classcode, ticker, iNterval ) --создаем источник данных

в этом случае работает.

Похоже ошибка либо в  getSecurityInfo(), либо в методе  .class_code
 
Проблема в .class_code. На этих инструментах он выдает "EQRP_INFO" а должен возвращать "TQBR"
 
Вопрос по этому поводу задал здесь https://forum.quik.ru/forum10/topic6471/
 
Цитата
Sergey написал:
Проблема в .class_code. На этих инструментах он выдает "EQRP_INFO" а должен возвращать "TQBR"
Ну просто у вас существует два инструмента с одинаковым sec_code, но разными class_code
А функция getSecurityInfo возвращает данные по первому из найденных под заданные параметры инструменту
Надо для таких случаев явно указывать нужный class_code

Если использовали мой код, то вот небольшие изменения
Код
ticker_list = {{"SiM1"},{"SiU1"},{"FIVE","TQBR"},{"TCSG","TQBR"}}
function OnInit()
  if(isConnected()==1)then
    for key,value in pairs(ticker_list) do --в цикле перебираем бумаги из ticker_list
      local n=10
      while (getSecurityInfo((ticker_list[key][2] or ""),ticker_list[key][1])==nil)and(n>0) do sleep(1000) n=n-1 end -- Ждем загрузки данных по инструменту 10 секунд
      if(n==0)then message("Инструмент "..ticker_list[key][1].." не найден") ticker_list[key]=nil break end
      ticker_list[key][2]=getSecurityInfo((ticker_list[key][2] or ""),ticker_list[key][1]).class_code --получаем класс бумаги (TQBR,SPBFUT,CETS,ect.) по ее тикеру
      ticker_list[key][3]=CreateDataSource(ticker_list[key][2],ticker_list[key][1],iNterval) --создаем источник данных
    end
  end
end

 
Кстати, а в чем смысл для каждого инструмента искать class_code?
По мне лучше указывать явно нужные sec_code и class_code, и понадежнее будет, да и код станет проще.
 
Цитата
BlaZed написал:
Кстати, а в чем смысл для каждого инструмента искать class_code?
По мне лучше указывать явно нужные sec_code и class_code, и понадежнее будет, да и код станет проще.
Сейчас пока так и сделал, сделал с явным указанием кода. Но пригодится это когда инструментов много и с разных рынков. На основании некоторых предварительных критериев формируются динамические списки по ним и затем уже читаются lua скриптом. BlaZed спасибо за помощь!
 
Цитата
BlaZed написал:
Ждем загрузки данных по инструменту
Не нужно Нельзя в OnInit никаких ожиданий делать. Если данных нет, то они и не появятся пока из OnInit не выйдете.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Нельзя в OnInit никаких ожиданий делать. Если данных нет, то они и не появятся пока из OnInit не выйдете.
Вы правы, не подумал об этом.
Да и основной поток ожиданиями напрягать тоже далеко не самая лучшая идея.
Благодарю.

Sergey, код из OnInit лучше перенести в main перед вечным циклом
 
Цитата
BlaZed написал:
Цитата
Старатель написал:
Нельзя в OnInit никаких ожиданий делать. Если данных нет, то они и не появятся пока из OnInit не выйдете.
Вы правы, не подумал об этом.
Да и основной поток ожиданиями напрягать тоже далеко не самая лучшая идея.
Благодарю.

Sergey , код из OnInit лучше перенести в main перед вечным циклом
Хорошо
Страницы: 1
Читают тему
Наверх