Использую мобильный интернет для торговли. После потери соединения 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. Нет
--настройка параметров 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)
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(), и поместить в массив, а в цикле уже брать значения из массива. Нет никакого смысла каждый раз их заново находить, достаточно одного раза.
Я заметил, что classcode=getSecurityInfo("",instrument).class_code может быть nill даже когда связь установлена, вероятно не успевают загрузиться данные getSecurityInfo(). В init тоже не вариант.. Здесь бы очень подошло что-то вроде try-exeptions как в python, но я не знаю пока как это делать на lua
Все таки if (isConnected () == 1) then работает через раз, все-таки не показалось. Долго работало нормально, а сегодня после очередного дисконнекта скрипт снова отвалился, с той же ошибкой в 27 строке - nil . Сорри за столько сообщений, но я не нашел как редактировать или удалить написанные сообщения
В общем, если у кого вдруг похожая проблема, решение банальное - проверкой на nil. Сейчас работает надежно, независимо от коннекта к серверу: while do ....if classcode~=nil then ........body
....end end Отдельное спасибо BlaZed, за то, что натолкнул на мысли
Такая проверка не поможет, ибо classcode у вас глобальная и после первой же итерации всегда будет не nil если инструмент существует, и по такому условию просто каждую итерацию скрипт будет пропускать
Такая проверка не поможет, ибо classcode у вас глобальная и после первой же итерации всегда будет не nil если инструмент существует, и по такому условию просто каждую итерацию скрипт будет пропускать
попробуйте сами: 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 ................тут без изменений
Тут дело в том, что ошибка плавающая, и будет появляться если удачно совпадет момент чтения данных из getSecurityInfo с моментом подключения к серверу, когда старые данные уже удалились, но еще не загрузились новые. При вашем sleep(3000) это может быть, ну скажем 1 раз из 10 раз, а поставьте sleep(100), так сразу увидите, что ошибка никуда не делась.
Тут дело в том, что ошибка плавающая, и будет появляться если удачно совпадет момент чтения данных из getSecurityInfo с моментом подключения к серверу, когда старые данные уже удалились, но еще не загрузились новые. При вашем sleep(3000) это может быть, ну скажем 1 раз из 10 раз, а поставьте sleep(100), так сразу увидите, что ошибка никуда не делась.
Похоже что вы правы, без sleep() вылетает сразу. Вариант вынести все в OnInit()? Но ведь там тоже нет гарантии что переменная classcode успеет записаться сразу после инициализации скрипта, даже при условии проверки соединения и не вылетит с ошибкой
Sergey написал: Вариант вынести все в OnInit()? Но ведь там тоже нет гарантии что переменная classcode успеет записаться сразу после инициализации скрипта, даже при условии проверки соединения и не вылетит с ошибкой
Именно вариант с OnInit() в данном случае самый надежный, надо всего лишь добавить парочку дополнительных проверок.
Смотрите
во первых, меняем ticker_list, делаем его двухуровневым массивом
во-вторых, переносим все одноразовые предварительные вычисления в 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
ticker="FIVE" --код инструмента/бумаги classcode="TQBR" --код класса инструмента/бумаги, если нужен фондовый рынок - вводить TQBR вместо SPBFUT iNterval=INTERVAL_D1 --таймфрейм
и подставить все в:
ds=CreateDataSource(classcode, ticker, iNterval ) --создаем источник данных
в этом случае работает.
Похоже ошибка либо в getSecurityInfo(), либо в методе .class_code
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 спасибо за помощь!