Если в настройках получения параметров по инструментам вручную задать классы/инструменты, то при построении графиков будут доступны только эти выбранные классы/инструменты:
Надо делать так, как надо. А как не надо - делать не надо.
Если Вы наблюдаете у себя описанное в исходном сообщении данной темы поведение, то рекомендация остается прежней:
Цитата
Roman Azarov написал: Пришлите, пожалуйста, архив своего рабочего места QUIK (без ключей доступа) на почту нашей поддержки ( quiksupport@arqatech.com ) со ссылкой на данную тему форума для анализа.
Подтверждаю: "косяк" есть. Но в моём случае - это когда getDepoEx ничего не возвращает для того же набора параметров (FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT, LIMIT_KIND) При этом вызов getDepoEx сразу после ошибки
Код
local tblTotalLot = getDepoEx(FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT, LIMIT_KIND)
if type(tblTotalLot) == "table" then
...
else
message("getDepoEx error", 3)
tblTotalLot = getDepoEx(FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT, LIMIT_KIND)
end
возвращает уже нормальную таблицу с корректными значениями.
Ситуаций с левым currentbal не встречалось.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: Почему вдруг TotalLots стал integer в то время, как getDepoEx возвращает currentbal во float?
Исходя из кода, такое может быть, если getDepoEx ничего не вернул, тогда в TotalLots вы присваиваете 0 Это возможно, например, когда QUIK переключился к другому серверу, и таблица depo_limits очистилась (это нормальное событие) и ещё не успела заполнится, как раз, когда был вызван getDepoEx.
Цитата
Сирануш написал: я не правильно пытаюсь получить значения через local tblTotalLot = getDepoEx(FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT ,LIMIT_KIND) if tblTotalLot==nil then TotalLots=0 else TotalLots=tonumber(tblTotalLot.currentbal) end ?
Тут у каждого своё понимание о "правильности". Но такая запись может быть потенциально небезопасной, в зависимости от того, как вы обрабатываете полученные данные. Например, если QUIK переключается на другой сервер, то, как я написал выше, в TotalLots вы записываете 0, хотя по факту позиция может быть уже открыта.
Цитата
Сирануш написал: запустил терминал( сегодня суббота) и отключился от интернета вот что получилось: 10:48:01CORR_SPB TotalLots 2.0 mLots 1.0 x 2.0 10:48:01CORR_SPB TotalLots 1.0 mLots 2.0 x 1.0 Что теперь будешь предлагать, какую таблицу смотреть?
Выглядит весьма сомнительно, как будто в портфеле две записи для одного набора данных (FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT ,LIMIT_KIND) Вот вам и предложили выводить таблицу целиком.
Цитата
Сирануш написал: Зачем мне обязательно делать перебор полей?
Читайте мою подпись. Угадывать за вас, что у вас происходит, никто не будет.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: Смотрите таблицу, возвращаемую getDepoEx, сравнивайте, какие поля поменялись
Скрытый текст
Код
local run = true
function OnStop()
run = nil
end
function main()
local mLots
while run do
local tblTotalLot = getDepoEx(FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT, LIMIT_KIND)
if type(tblTotalLot) == "table" then
local TotalLots = tblTotalLot.currentbal
if mLots ~= TotalLots then
local t = {}
for k, v in pairs(tblTotalLot) do
t[#t+1] = tostring(k) .. "=" .. tostring(v)
end
message("mLots = " .. tostring(mLots) .. "\n" .. table.concat(t, ", "), 3)
mLots = TotalLots
end
else
message("getDepoEx error", 3)
return
end
sleep(1)
end
end
Надо делать так, как надо. А как не надо - делать не надо.
Не может. tonumber не меняет вещественное на целое.
Смотрите таблицу, возвращаемую getDepoEx, сравнивайте, какие поля поменялись
Скрытый текст
Код
local run = true
function OnStop()
run = nil
end
function main()
local mLots
while run do
local tblTotalLot = getDepoEx(FIRM_ID, CLIENT_CODE, SEC_CODE, ACCOUNT, LIMIT_KIND)
if type(tblTotalLot) == "table" then
local TotalLots = tblTotalLot.currentbal
if mLots ~= TotalLots then
local t = {}
for k, v in pairs(tblTotalLot) do
t[#t+1] = tostring(k) .. "=" .. tostring(v)
end
message("mLots = " .. tostring(mLots) .. "\n" .. table.concat(t, ", "), 3)
mLots = TotalLots
end
end
sleep(1)
end
end
Заодно можете и всю таблицу depo_limits вывести, как раннее вам советовали.
Надо делать так, как надо. А как не надо - делать не надо.
Сирануш написал: запустил терминал( сегодня суббота) и отключился от интернета вот что получилось: 10:48:01CORR_SPB TotalLots 2.0 mLots 1.0 x 2.0 10:48:01CORR_SPB TotalLots 1.0 mLots 2.0 x 1.0
А где строка с первоначальным mLots = 0 ?
Далее, обратите внимание на эту строку
Цитата
Сирануш написал: 10:54:40 CORR_SPB TotalLotsРєРѕРїРёСЏ 0 mLots 1.0 x 0
Почему вдруг TotalLots стал integer в то время, как getDepoEx возвращает currentbal во float?
Напрашивается вывод:
Цитата
Nikolay написал: Либо Вы приводите не все сообщения, либо не полный код.
Надо делать так, как надо. А как не надо - делать не надо.
BlaZed написал: если приведением к числу проверять корректность?
Вы скобочку не там поставили. tonumber(getParamEx(class, sec, param).param_value) всегда число, даже если такой бумаги/параметра в природе не существует.
Надо делать так, как надо. А как не надо - делать не надо.
swerg написал: а) получить вызов OnCalculate для индекса 4, где мы получили данные по основному и дополнительному источникам
Следует отметить, что в общем случае индексы на графике по основному источнику и в дополнительном, полученном через CreateDataSource, могут не совпадать. Если уж делать сигнал от второго источника, то через SetUpdateCallback. И менять значения индикатора функциями SetValue или SetRangeValue
Надо делать так, как надо. А как не надо - делать не надо.
Andrey Bezrukov написал: Окно скриптов Lua ведёт себя в соответствии с логикой ОС и устанавливает размер колонок в зависимости от метрик шрифта.
Цитата
Andrey Bezrukov написал: Тем самым оставляя больше места для пустой колонки.
Ошибка в том, что для окна со строго заданными размерами вы задаёте ширины колонок в зависимости от шрифта. Ширина пустой колонки должна быть необходимой и достаточной, чтобы уместить вертикальный скролл, не более.
Надо делать так, как надо. А как не надо - делать не надо.
Egor Zaytsev написал: При подключении именно 23 числа или в любой день пятницы сколько свечей? 3000+ текущая сессия?
Ага, в ПТ и ночь СБ было 3000 + последняя сессия. А утром в СБ (точное время не спрашивайте) сервер принудительно разрывает соединение и после подключения даёт не более 3000 свечей, включая последнюю сессию.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: Предложение3. Дать скриптеру возможность самостоятельно устанавливать/снимать блокировку в любом месте пользовательского кода
Мне кажется, это может порождать ошибки в скриптах пользователей, не являющихся профессиональными программистами.
Как и в любом другом коде. Кто-то даже с динамической типизацией справиться не может, далеко за примерами ходить не надо. Ну и что ж теперь? Тут, как говорится, не умеешь - не пользуйся.
Надо делать так, как надо. А как не надо - делать не надо.
Quik 8.13 функция CreateDataSource возвращает пустой набор данных, если таймфрейм отличается от стандартного., Quik 8.13 функция CreateDataSource возвращает пустой набор данных, если интервал отличается от стандартного.
Владимир написал: Не слишком ли жирно будет заставлять сервер подсчитывать свечи "нестандартных интервалов"?
Есть версия, что свечи нестандартных интервалов подсчитывались на месте, но только за текущую торговую сессию, начиная с вчерашней вечерки. Дело в том, что открыв график любого интервала, впоследствии вы сможете просмотреть графики текущей сессии по другим интервалам того же инструмента в офлайн, даже если ни разу не открывали их. Качаются ли все интервалы с сервера сразу или рассчитываются на месте по минуткам - не известно.
Надо делать так, как надо. А как не надо - делать не надо.
Anton написал: У квика не возникает необходимости вызвать колбек только в скрипте 1, он последовательно вызовет колбеки в скриптах 1, 2, 3, и всегда в этом порядке. Если какой-то из скриптов просто не определил колбек, ну слава богу, баба с возу. Так вот, если картинку перевернуть, то есть скрипт 1 самый тормозной (t1 самый длинный), то колбек в скрипте 1 все равно выполнится в момент t1, несмотря на то, что скрипты 2 и 3 уже закончили байткод и по идее можно было бы дернуть этот же колбек в них.
Со скриптом 1 понятно. Вы, наверное, хотели сказать, что в таком случае скрипты 2 и 3 вызовут колбек не по окончании работы своего байт-кода, а будут ждать скрипт 1, и вызовут колбек в момент t1 + dt (время на обработку колбека предыдущими скриптами). В любом случае, мы имеем взаимное и неочевидное (в том смысле, что не возможно предугадать) влияние скриптов друг на друга.
Надо делать так, как надо. А как не надо - делать не надо.
Anton, т.о., вы опровергаете раннее написанное вами
Цитата
Anton написал: Картинку выше для чистого луа можно мелко порезать горизонтальными линиями и в каждой полосе будет работать либо мейн, либо колбек
Допустим, работают три скрипта, в каждом из которых, выполняется байт-код в main продолжительностью t1, t2 и t3 соответвенно. В момент времени t возникает необходимость вызвать колбек в 1-м скрипте. При этом t < t1 < t2< t3. Вопрос: в какой момент будет вызван колбек, и повлияет ли скрипт 3 на работу скриптов 1 и 2?
Надо делать так, как надо. А как не надо - делать не надо.
Anton написал: В моменты конкуренции за разделяемый ресурс (луа-машину) основной поток квика ожидает освобождения ресурса потоком мейна того скрипта, в котором он собирается вызвать колбек; мейны других скриптов при этом продолжают выполняться и не влияют на ожидание.
Точно не влияют? Нужно, чтобы потоки мейнов всех скриптов освободили разделяемый ресурс (луа-машину), не?
Надо делать так, как надо. А как не надо - делать не надо.
Imersio Arrigo, смотрите сами. Пример приведён для техподдержки. И в нём конкретные цифры, которые показывают, что новая торговая сессия после 23.04 не началась.
Надо делать так, как надо. А как не надо - делать не надо.
local run, id = true
function OnStop()
run = nil
DestroyTable(id)
end
function main()
id = AllocTable()
AddColumn(id, 1, "", true, QTABLE_STRING_TYPE, 20)
CreateWindow(id)
SetTableNotificationCallback(id, function (id, event)
if event == QTABLE_CLOSE then
run = false
elseif event == QTABLE_VKEY then
SetColor(id, 2, QTABLE_NO_INDEX, 0x0000FF, 0, 0x0000FF, 0)
end
end)
for row = 1, 2 do
InsertRow(id, row)
SetCell(id, row, 1, tostring(row))
end
while run do sleep(500) end
end
Применить фильтр, чтобы осталась только строка 1. Нажать любую клавишу - вся таблица окрасится красным.
Надо делать так, как надо. А как не надо - делать не надо.
local run, id = true
function OnStop()
run = nil
DestroyTable(id)
return 100
end
function main()
id = AllocTable()
AddColumn(id, 1, "", true, QTABLE_STRING_TYPE, 20)
CreateWindow(id)
SetTableNotificationCallback(id, function (id, event)
if event == QTABLE_CLOSE then
run = false
elseif event == QTABLE_VKEY then
for row = 1, 2 do
SetColor(id, row, QTABLE_NO_INDEX, 0x0000FF, QTABLE_DEFAULT_COLOR, 0x0000FF, QTABLE_DEFAULT_COLOR)
end
end
end)
for row = 1, 2 do
InsertRow(id, row)
SetCell(id, row, 1, tostring(row))
end
while run do sleep(500) end
end
Запустить скрипт. Нажать любую клавишу - фон окрашивается красным. BUG 1: Применить фильтр, чтобы осталась только строка 1, - фон пропадает. BUG 2: Нажать любую клавишу - пропадает текст.
Надо делать так, как надо. А как не надо - делать не надо.
TGB написал: Идея оптимизации состоит в том, чтобы у пользователя была динамическая возможность задания/отмены C-функций, которые вызываются без выше описанной синхронизации (ввести особый список).
Roman Azarov, если будете это реализовывать, то предлагаю сделать возможным задавать не только отдельно функции, но и библиотеку целиком, например math.
3) Предложение3. Дать скриптеру возможность самостоятельно устанавливать/снимать блокировку в любом месте пользовательского кода, если такое возможно.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: Тогда это тоже атомарная операция:
Код
Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
Проверил в Lua 5.1. Скрипт:
Скрытый текст
Код
local a = {}
function OnInit()
for i = 1, 100000 do a[i] = 1 end
end
local run = true
function OnStop()
a = nil
run = false
end
function OnAllTrade()
a = nil
run = false
end
function OnParam()
a = nil
run = false
end
function main()
local r
run = true
a[0]=(a[1]or 0)
+ (a[2]or 0)
+ (a[3]or 0)
... -- Тут много строк "+ (a[i]or 0)"
+ (a[99999]or 0)
+ (a[100000]or 0)
r = run
message(tostring(r) .. '; ' .. a[0], 2)
end
И получил ошибку типа
Цитата
16492: attempt to index upvalue 'a' (a nil value)
Т.е., в Lua 5.1 лок может быть снят в процессе извлечения значения из таблицы. Т.ч., как сказал Антон:
Цитата
Anton написал: Вероятность, что в версии луа 55.99 станет неатомарным - есть.
Также в Lua 5.1 при выполнении байт-кода блокировка может быть снята в таких местах:
Код
a = b + c
-- тут блокировка может быть захвачена другим потоком
x = y - z
Стоит также отметить, что в Lua 5.1 байт-код выполняется значительно дольше по сравнению с 5.4. Возможно как раз из-за постоянной борьбы за блокировку между потоками.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: В 7-м квике не зависает даже более примитивный код:
Мне все лень было проверить, но вот тоже такое впечатление, что в Lua 5.1 более грамотно были сделаны локи многопоточности. А в 5.3 совсем халтуру какую-то сделали.
По всей видимости в 5.1 на каждой итерации цикла вызывались lua_unlock/lua_lock. А в 5.3 этого нет, если в цикле только байткод, что значительно уменьшает время вычислений таких циклов. Если цикл продолжительный, чтобы не было зависаний, можно вставить внутрь цикла любую с-функцию (не обязательно sleep). Причём, вставлять можно не на каждую итерацию, а через заданное количество циклов. Это позволит не подвешивать основной поток и при этом сохранить скорость вычислений байткода в циклах. Т.ч., нельзя назвать эти изменения в 5.3 "халтурой."
Надо делать так, как надо. А как не надо - делать не надо.
Roman Azarov написал: У себя подобного за целый день не увидели
Roman Azarov, вот тест, который воспроизводит ошибку практически сразу после перезаказа обезличенных сделок.
Скрытый текст
Можете поиграться со значением параметра n
Код
local n = 25
local run = true
function OnStop()
run = nil
end
function OnParam(class_code, sec_code)
p = {}
for i = 1, n do
p[tostring(i)] = tostring(i)
end
for k, v in pairs(p) do
p[k] = os.time()
p[k] = nil
end
end
function OnAllTrade(alltrade)
a = {}
for i = 1, n do
a[tostring(i)] = tostring(i)
end
for k, v in pairs(a) do
a[k] = os.time()
a[k] = nil
end
end
function main()
while run do
m = {}
for i = 1, n do
m[tostring(i)] = tostring(i)
end
for k, v in pairs(m) do
m[k] = os.time()
m[k] = nil
end
sleep(1)
end
end
Надо делать так, как надо. А как не надо - делать не надо.
Egor Zaytsev, сейчас уже 3000 + текущая сессия. Дело в том, что я смотрел в ВС 18.04. Дата торгов при этом отображалась 16.04. Если я правильно понимаю, текущая сессия сохраняется в info.log, а все предыдущие - в dat-файлах в папке archive. Так вот, в dat-файле было около 2000 свечей и в сумме с последней сессией 16.04 получалось всего 3000. TQBR и SPBFUT.
Надо делать так, как надо. А как не надо - делать не надо.
Артем, джентльмены соглашаются только с тем, кто прав. А умников, которые считают себя "профи" в каждом вопросе, а по факту даже не понимают сути обсуждаемого, надо на место ставить.
Что вы там обосновали? Про "небо голубое"? Аргументов от вас лично я так и не увидел.
Цитата
Артем написал: просто не работайте с одной и той же памятью из разных тредов
Спасибо, кэп, без вас бы не разобрались. Ветка про другое. Второй поток вообще может не знать про таблицу в первом, или может знать, но не работать с ней.
Надо делать так, как надо. А как не надо - делать не надо.
Артем написал: удалять значения из массива в цикле по этому же массиву это плохая практика
В Lua не запрещено, из Reference Manual:
Цитата
The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may set existing fields to nil.
Ошибка, обсуждаемая в ветке, может возникнуть при работе с таблицей в одном потоке. При чём здесь вообще потокобезопасные функции, которые к тому же, не работают с ассоциативными массивами?