Старатель написал: А логические ошибки, когда в непредсказуемом месте вылезает nil, типа attempt to compare number with nil и т.п., они могут как-то в будущем повлиять? QUIK перегружать нужно?
Когда после ошибки в одном скрипте начинают сыпаться ошибки в других, или в нем же после рестарта, это показывает, что стек был покоцан, дальше уже как повезет, насколько сильно и т.д., где-то закончится небольшой утечкой, где-то уже серьезные повреждения, которые вылезут позже.
Я про логические ошибки скрипта, когда где-то что-то недосмотрел, не проверил на nil полученные данные и т.п. И в какой-то момент вместо данных там оказался nil. Скрипт остановился. Это может повлиять на будущую работу?
Надо делать так, как надо. А как не надо - делать не надо.
А логические ошибки, когда в непредсказуемом месте вылезает nil, типа attempt to compare number with nil и т.п., они могут как-то в будущем повлиять? QUIK перегружать нужно?
Надо делать так, как надо. А как не надо - делать не надо.
local run
local file
local function log(s)
file:seek('set')
file:write(s)
file:flush()
end
function c(func, ...)
log('1')
local arg = {...}
log('2')
end
function OnInit(path)
local err
file, err = io.open(path..'.log', 'w+')
if file == nil then
message(err, 3)
else
run = true
end
end
function OnAllTrade(alltrade)
end
function OnParam(class, sec)
end
function OnStop()
run = nil
end
local f2 = function() end
function main()
if not run then return end
while run do
for i = 1, 100 do
log('0')
c(f2, i, 1, 2, 3)
log('3')
end
sleep(1)
end
file:close()
end
В логе:
Цитата
1
Как и в прошлый раз поток main скрипта прибит. Основной поток остался в состоянии ожидания.
Скрытый текст
Надо делать так, как надо. А как не надо - делать не надо.
Похоже, источник проблемы - функция с переменным числом аргументов. Возникает либо при вызове функции
Код
c(func, ...)
либо при формировании таблицы аргументов
Код
local arg = {...}
Код демонстрационного скрипта:
Код
local run = true
function c(func, ...)
local arg = {...}
end
local f1 = function() end
function OnAllTrade(alltrade)
c(f1, alltrade)
end
function OnParam(class, sec)
end
function OnStop()
run = nil
end
local f2 = function() end
function main()
while run do
for i = 1, 100 do
c(f2, i, 1, 2, 3)
end
sleep(1)
end
end
Надо делать так, как надо. А как не надо - делать не надо.
Никто и не обещал, что ошибка появляется всегда и сразу. Можно запустить несколько копий скрипта, как тут, сделать перезаказ обезличенных сделок... В общем, ошибка именно в этом коде и именно в этом месте присутствует. А как гарантированно воспроизвести - без понятия. Надо смотреть сорцы, откуда там nil.
Надо делать так, как надо. А как не надо - делать не надо.
local run = true
function OnAllTrade(alltrade)
end
function OnParam(class, sec)
end
function main()
local getinfo = debug.getinfo
while run do
for i = 1, 100 do
getinfo(1)
end
sleep(1)
end
end
function OnStop()
run = nil
end
Ошибка в строке getinfo(1)
Цитата
bad argument #1 to 'getinfo' (number expected, got nil)
Надо делать так, как надо. А как не надо - делать не надо.
Здесь будут публиковаться кривые ошибки, возникающие, очевидно, из-за двухпоточной схемы работы QLua. Некоторые ошибки указаны здесь: Потокобезопасные функции в Lua 5.3
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: Этот флаг никак не должен менять порядок сделок в хранилище
Сам по себе да, а вкупе с шаловливыми ручками? Поставить флажок, накачать чего, снять флажок, накачать еще.
Проверьте. При снятии флага пропущенные сделки закачиваются только при перезаказе. Так что как раз теоретически в пределах одного тикера накрутить невозможно. А что на практике - так это не шаловливые ручки виноваты.
Надо делать так, как надо. А как не надо - делать не надо.
Anton написал: Где-то этот лок захвачен и не выпущен, возможно, в одном из (других) скриптов, возможно, косячок в самом квике.
7500 и 5364 - потоки двух скриптов. Они большую часть времени стоят на SleepEx. Один из них, известно точно, периодически просыпается и шлёт отладочную информацию. Так что, лок захвачен явно не ими. А вот, где поток третьего скрипта, не пойму, может прибит уже?
Скрытый текст
Цитата
Anton написал: Там совсем другая картина, квик пытается получить колбек через lua_getglobal и падает из-за access violation.
Помимо описанных ошибок и падений в теме, несколько раз были и зависания. Но зависает не скоро, и написать демонстрационный скрипт, гарантированно приводящий к зависанию в течение разумного времени после запуска не представляется возможным.
Надо делать так, как надо. А как не надо - делать не надо.
Anton написал: Квик хочет вызвать колбек OnAllTrade и заполняет для него табличку с очередной сделкой. Все данные из ТВС уже вытащены, почти вся табличка заполнена, в последнюю очередь квик создает вложенную табличку datetime, пытается воткнуть в нее строку "day" и в этот момент виснет на lua_pushstring, как написал выше. В общем, это все мало что дает, косяк где-то в синхронизации все равно.
Первые два трейда - это видимо, два скрипта из трёх запущенных. Один из которых, как я написал, выше, раз в минуту шлёт отладочную информацию. Второй просто молча работает (вроде, работает).
А третий скрипт, я также предполагал, что застрял перед вызовом одного из колбеков, потому и не отображается в логе. Что касается бесконечной рекурсии, то их нет в скрипте. И я почти на 100% уверен, что QUIK "завис" не из-за логической ошибки в скрипте. За эту версию говорит также тот довод, что неоднократно похожая проблема наблюдалась на скриптах из этой темы.
Надо делать так, как надо. А как не надо - делать не надо.
QUIK не совсем завис, а только основной поток находится в ожидании чего-то. Один из скриптов в main периодически шлёт отладочную информацию через PrintDbgStr.
Надо делать так, как надо. А как не надо - делать не надо.
QUIK 8.8.4.3. Стандартная схема оформления. Иногда после нескольких дней работы зависает. При этом загрузка ЦП процессом 0 Сначала грешил на потокобезопасные функции. Но анализ логов показывает, что зависании происходит вне потокобезопасных функций (но это не точно )) Можно ли по стеку определить последнюю вызванную QLua функцию?
Надо делать так, как надо. А как не надо - делать не надо.
id = AllocTable()
AddColumn(id, 1, "", true, QTABLE_STRING_TYPE, 20)
CreateWindow(id)
local col = InsertRow(id, 1)
local value = "Text"
message(tostring(SetCell(id, 1, col, tostring(value), tonumber(value) or 0)))
Надо делать так, как надо. А как не надо - делать не надо.
Anton написал: Падает на lua_getglobal. В qlua.dll основным потоком квика вызывается некая функция, она пытается вызвать lua_getglobal(state, "OnAllTrade") и, если успешно, далее заполняет табличку all_trade и вызывает полученную луа-функцию. То есть это как раз место, где вызывается OnAllTrade.
Где вы это смотрите?
Надо делать так, как надо. А как не надо - делать не надо.
local run, id
local AllTrades = {}
local get, process = 0, 0
function OnAllTrade(alltrade)
if not run then return end
table.sinsert(AllTrades, alltrade)
local n = getNumberOf('all_trades')
SetCell(id, 1, 1, tostring(n), n)
if n == 1 then
get = 1
process = 0
else
get = get + 1
end
SetCell(id, 1, 2, tostring(get), get)
end
function main()
id = AllocTable()
AddColumn(id, 1, 'all', true, QTABLE_INT_TYPE, 10)
AddColumn(id, 2, 'get', true, QTABLE_INT_TYPE, 10)
AddColumn(id, 3, 'process', true, QTABLE_INT_TYPE, 10)
CreateWindow(id)
SetWindowPos(id, 0, 0, 193, 61)
InsertRow(id, -1)
run = true
while run do
if #AllTrades ~= 0 then
while #AllTrades ~= 0 do
table.sremove(AllTrades, 1)
process = process + 1
end
SetCell(id, 1, 3, tostring(process), process)
else sleep(1) end
end
end
function OnStop()
run = nil
DestroyTable(id)
end
Запускаю несколько копий. Делаю перезаказ обезличенных сделок. Предполагается, что все скрипты обработают одинаковое количество сделок. Ан, нет. Спустя чуть больше часа разрываю соединение, чтобы проверить. Часть скриптов потеряла по одной сделке.
Скрытый текст
Надо делать так, как надо. А как не надо - делать не надо.
local run = true
local function work(alltrade, n)
for i = 1, n do
local d = alltrade.flags % 2
d = bit.band(alltrade.flags, 2)
end
end
local AllTrades = {}
function OnAllTrade(alltrade)
table.ssort({0, 0}, function()
AllTrades[#AllTrades+1] = alltrade
work(alltrade, 10)
return true
end)
end
function main()
while run do
while #AllTrades ~= 0 do
local alltrade = table.sremove(AllTrades, 1)
table.ssort({0, 0}, function()
work(alltrade, 100)
return true
end)
end
sleep(1)
end
end
function OnStop()
run = nil
end
Можно также запустить несколько копий, чтоб наверняка. Изредка выскакивает ошибка
Цитата
bad argument #1 to 'ssort' (table expected, got nil)
в строке
Код
table.ssort({0, 0}, function()
Иногда падает. Причём, может длительное время работать без сбоев. После появления первой ошибки и перезапуска скрипта, ошибки начинают сыпаться чаще.
Надо делать так, как надо. А как не надо - делать не надо.
Anna Lozenko написал: сформировать архив рабочего места QUIK
Это не моя работа. Вся необходимая информация, когда и при каких обстоятельствах возникает ошибка, вам предоставлена более трёх месяцев назад:
Цитата
Старатель написал: После расширения планок в результате стоп-торгов в поле ввода заявки не рассчитывается максимальное возможное количество лотов по ценам выше/ниже каких-то (непонятных) границ (и эти границы не связаны с макс./мин. возможной ценой инструмента).
Цитата
Старатель написал: после расширения лимитов в следующий клиринг ситуация исправляется
Так, ситуация, скрины, которой представлены в сообщении #5, продолжалась до следующего клиринга 14:00 12.08.20
Есть ощущение, что вы не понимаете, что делаете. Что вы искали через два дня после события - большой вопрос. Подробно про клиринг, стоп-торги и расширение ценового коридора (планок) можно прочесть на сайте биржи.
В помощь могу написать скрипт:
Скрытый текст
Код
local run = true
function main()
while run do
for sec in getClassSecurities("SPBFUT"):gmatch("([^,]+)") do
local price = getParamEx("SPBFUT", sec, "PRICEMIN").param_value
if price and price ~= 0 then
local qty = CalcBuySell("SPBFUT", sec, "", Account, price, true)
if qty <= 0 then
message(sec .. ' B: ' .. qty, 2)
end
end
price = getParamEx("SPBFUT", sec, "PRICEMAX").param_value
if price and price ~= 0 then
local qty = CalcBuySell("SPBFUT", sec, "", Account, price, false)
if qty <= 0 then
message(sec .. ' S: ' .. qty, 2)
end
end
end
sleep(60000)
end
end
function OnStop()
run = nil
return 100
end
Запускаете и ждёте. Но ждать придётся долго, может несколько недель или месяцев, т.к. стоп-торги бывают не каждый день.
Надо делать так, как надо. А как не надо - делать не надо.
local run = true
function main()
local id = AllocTable()
AddColumn(id, 1, 'Количество', true, QTABLE_INT_TYPE, 13)
CreateWindow(id)
InsertRow(id, -1)
while run do
local len = getNumberOf('all_trades')
SetCell(id, 1, 1, tostring(len), len)
sleep(100)
end
end
function OnStop()
run = nil
end
Скрипт 2:
Скрытый текст
Код
local run = true
local AllTrades = {}
function OnAllTrade(alltrade)
table.sinsert(AllTrades, alltrade)
--[[table.ssort({0, 0}, function()
AllTrades[#AllTrades+1] = alltrade
return true
end)]]
end
function main()
while run do
while #AllTrades > 0 do
table.sremove(AllTrades, 1)
end
sleep(1)
end
end
function OnStop()
run = nil
end
При запущенных обоих скриптах изредка в строке
Код
while #AllTrades > 0 do
возникает странная ошибка:
Цитата
attempt to compare number with function
Для воспроизведения можно Получить заново данные по обезличенным сделкам.
Надо делать так, как надо. А как не надо - делать не надо.
Andrey Bezrukov, Никакого архива, конечно же, не будет. В этом нет смысла. Вероятность воспроизвести точно такую же ситуацию не высока, и ваш ответ ("проблема не воспроизводится") очевиден. Вы можете только подтвердить или опровергнуть гипотезу:
Цитата
Старатель написал: Первый список загружается вместе с QUIK. Второй загружается вместе с файлом настроек уже после того, как стартуют скрипты.
А заодно проверить в своём коде терминала, что в момент подмены списков таблица trade_accounts сначала очищается, а затем вставляются списки из info.wnd. И в этот момент как раз существует гипотетическая вероятность получения nil из вышеприведённого кода. Как-то так, других вариантов у меня нет.
И зарегистрировать пожелание на доработку: стартовать скрипты после полной загрузки настроек. Если, конечно пользы от этого будет больше, чем вреда.
Пример ещё нескольких функций, которые зависят от последовательности загрузки настроек: getNumCandles, getLinesCount, getCandlesByIndex
Надо делать так, как надо. А как не надо - делать не надо.
Выяснилось следующее: имеются два списка trade_accounts. Первый - в acnt.dat, второй - в info.wnd. Первый список загружается вместе с QUIK. Второй загружается вместе с файлом настроек уже после того, как стартуют скрипты. И, видимо, так сошлись звёзды, что в этот раз, скрипт обратился к таблице trade_accounts как раз в момент подмены списков, когда таблица была очищена.
Внимание вопрос: это баг или было сделано злонамерено? Почему бы не стартовать скрипты уже после полной загрузки настроек?
Надо делать так, как надо. А как не надо - делать не надо.