В информации об обновлении терминала QUIK до версии 11.4.0 есть пункт в параграфе "Исправленные недоработки":
"Оптимизирована работа терминала и устранен ряд ошибок при его запуске под Wine."
У меня вопрос к разработчикам терминала: "Нужна ли вам обратная связь по подобным ошибкам и проблемам при работе терминала при запуске под Wine?"
Если ответ будет положительным, предлагаю в этой теме или в специально созданной для этого теме сообщать о таких вещах, чтобы была возможность подтянуть качество работы в среде Linux.
Если ответ будет отрицательным или не последует, тогда будем считать, что политика по поддержке QUIK в Linux не изменилась.
Берём следующий скрипт. Если в первой строке стоит flag = true, то скрипт нормально запускается и останавливается из меню скриптов. Если в первой строке поставить flag = false, происходит зависание терминала при остановке скрипта. В зависимости от значения переменной flag либо имеется sleep(0) в функции main(), либо отсутствует на пути выполнения кода.
У меня зависание воспроизводится в терминалах версий 10.0.0 и 10.0.1.
Три вопроса: 1) Может ли кто-то ещё подтвердить, что зависание происходит (чтобы исключить особенность моего компьютера)? 2) Знает ли кто-то причину такого поведения? 3) Что разработчики терминала могут сказать по этому поводу?
Сам скрипт:
Код
local flag = true -- если установить в false, то при остановке скрипта происходит зависание (убирается sleep(0) в функции main)
local foregroundColor = RGB(0, 0, 0)
local backgroundColor = RGB(192, 255, 192)
local interrupted = false
local tableId
local function setTableColors(foregroundColor, backgroundColor)
local nRows, nCols = GetTableSize(tableId)
if nRows and nCols then
for row = 1, nRows do
for col = 1, nCols do
SetColor(tableId, row, col,
backgroundColor, foregroundColor,
backgroundColor, foregroundColor)
end
end
end
end
local function ensureWindowOpened()
if tableId == nil then
return
end
if IsWindowClosed(tableId) then
CreateWindow(tableId)
SetWindowPos(tableId, 0, 0, 300, 100)
SetWindowCaption(tableId, "hang_test")
InsertRow(tableId, 1)
InsertRow(tableId, 2)
SetCell(tableId, 1, 1, "11")
SetCell(tableId, 1, 2, "12")
SetCell(tableId, 2, 1, "21")
SetCell(tableId, 2, 2, "22")
SetSelectedRow(tableId, 1)
end
setTableColors(foregroundColor, backgroundColor)
end
local function closeWindow()
local t = tableId
tableId = nil
if t then
DestroyTable(t)
end
end
function OnInit(scriptPath)
tableId = AllocTable()
AddColumn(tableId, 1, "col1", true, QTABLE_STRING_TYPE, 5)
AddColumn(tableId, 2, "col2", true, QTABLE_STRING_TYPE, 5)
SetTableNotificationCallback(tableId, function(tId, msg, par1, _)
if msg == QTABLE_SELCHANGED then
SetSelectedRow(tId, 1)
end
end)
ensureWindowOpened()
end
local function run()
ensureWindowOpened()
if tableId then
SetSelectedRow(tableId, 2)
end
end
function OnStop(flag)
pcall(closeWindow)
interrupted = true
end
function main()
message("STARTED", 1)
while not interrupted do
run()
if flag then
sleep(0)
end
end
pcall(closeWindow)
message("SHUTDOWN", 1)
end
Уже есть функция getOrderByNumber, которая по коду класса и номеру заявки возвращает заявку из таблицы заявок. Предлагаю добавить аналогичную функцию для сделок. Сейчас для поиска используется
При использовании приведённых ниже демонстрационных скриптов наблюдается повышенная нагрузка на CPU и медленный вывод содержимого в таблицы QLua. При этом вывод в заголовки окон этих таблиц производится нормально. Просьба проверить оптимальность реализации отрисовки содержимого таблиц. Используется светлая тема терминала 9.3.3.3, на тёмной не проверялось, наверное, ещё хуже будет.
Файлы RunDemo1.lua, ...m RunDemo9.lua каждый имеет свои настройки и запускают общий файл Demo.lua. Каждый скрипт выводит окно и периодически с некоторым таймаутом, заданным в Demo.lua, обновляет свою таблицу на экране. Скрипты надо запускать одновременно.
Просьба к разработчикам ответить на вопрос: считается ли такая скорость отрисовки нормальной или её стоит оптимизировать?
Файл Demo.lua:
Код
---
--- Настройки заданы в переменной config, которая к моменту запуска уже определена.
---
local interrupted = false
local tableId
local timeout = 20 -- можно уменьшать, чтобы проблема стала более явной
local nRow = 30 -- количество строк в таблице, можно увеличивать, чтобы проблема стала более явной
local nCol = 10 -- количество столбцов в таблице, можно увеличивать, чтобы проблема стала более явной
function OnInit(scriptPath)
tableId = AllocTable()
for colId = 1, nCol do
AddColumn(tableId, colId, "#" .. colId, true, QTABLE_STRING_TYPE, 20)
end
end
function OnStop()
interrupted = true
local tId = tableId
tableId = nil
if tId then
DestroyTable(tId)
end
end
function updateTable()
if tableId == nil then
return
end
if IsWindowClosed(tableId) then
CreateWindow(tableId)
SetWindowPos(tableId, config.x, config.y, config.dx, config.dy)
for rowId = 1, nRow do
InsertRow(tableId, rowId)
end
end
local dt = os.date(" %Y-%m-%d %X", os.time())
SetWindowCaption(tableId, config.name .. dt)
for rowId = 1, nRow do
for colId = 1, nCol do
SetCell(tableId, rowId, colId, dt)
end
end
end
function main()
while not interrupted do
updateTable()
sleep(timeout)
end
end
Файл RunDemo1.lua:
Код
---
--- Этот скрипт нужно запустить.
---
config = {
name = "RunDemo1",
x = 0,
y = 0,
dx = 1400,
dy = 100,
}
dofile(getScriptPath() .. "/Demo.lua")
Файл RunDemo2.lua:
Код
---
--- Этот скрипт нужно запустить.
---
config = {
name = "RunDemo2",
x = 0,
y = 100,
dx = 1400,
dy = 100,
}
dofile(getScriptPath() .. "/Demo.lua")
Содержимое файлов 3-9 аналогично, отличаются только y-координаты окна.
Поскольку пользователи жалуются, что терминал тормозит, а МосБиржа запрещает разработчикам терминала тестирование в реальных условиях, то предлагаю сделать специальный режим работы терминала, который можно включить по желанию пользователя для профилирования. Пусть в этом режиме собирается нужная статистика по времени работы, количеству вызовов функций и пр. внутри терминала, чтобы её можно было бы потом отправить разработчикам для анализа. Важно сделать вывод результата работы в понятном текстовом виде, чтобы пользователь понимал, что именно он отправляет разработчикам, и не переживал по поводу конфиденциальности. Думаю, что тогда получится выявить много узких мест.
Если уже сейчас имеется способ запуска терминала под какого-то рода отладчиком с профилированием, тогда дайте знать, как это сделать. Для java есть, к примеру visualvm с мониторингом кучи, тредов, сборщика мусора и профилированием.
Судя по ответу разработчиков QUIK https://forum.quik.ru/messages/forum10/message59594/topic5823/#message59594 пользователям QLua имеет смысл перейти на версию 5.4.1, которая более корректно работает по сравнению с версией 5.3.5. При этом пользователи, использующие популярные внешние библиотеки, будут вынуждены как-то подправить код и найти новые версии этих библиотек (на языке Lua или скомпилированные под 64-битную версию Windows 10/11).
У меня есть просьба к тем представителям сообщества, кто уже успешно осуществил такой переход: давайте сделаем что-то типа небольшого дистрибутива, который будет в открытом доступе (GitHub ???), и откуда можно будет скачать эти библиотеки и относительно просто подключить для использования в терминале QUIK (скажем, положив внутрь папки с терминалом в подпапку типа lua54libs).
Судя по вопросам, обсуждавшимся на форуме, в состав такого дистрибутива имеет смысл включить: socket для работы с сокетами; luasec для ssl; какие-то библиотеки для работы с SQL; какие-то библиотеки для реализации графического интерфейса типа iup.
Если есть ещё какие-то полезные библиотеки, напишите в этой теме.
Ещё раз подчеркну, что этот дистрибутив был бы полезным не только для программистов, но и для рядовых пользователей, которые не владеют навыками сборки в Visual C++ из исходников.
Кто что думает? Реально ли такое сделать для всеобщего блага? Тем более, что особых усилий прилагать не надо, просто в одном месте собрать и "причесать".
После первичной установки QUIK из дистрибутива и запуске LUA скриптов по умолчанию теперь используется версия LUA 5.4.1.
Ошибка в работе функции SetUpdateCallback QLUA, приводящая к чрезмерному потреблению памяти.
Некорректное отображение значений в подсказке параметров свечи в левом верхнем углу графика.
В некоторых случаях не отображалась подсказка параметров свечи на графике.
При замене заявки снимался признак «Заявка маркет-мейкера».
Аварийное завершение работы терминала при добавлении двух криптопровайдеров.
Некорректный расчет значения поля «max» на форме ввода заявки для маржинальных инструментов при установленном признаке «Исходя только из собственных средств»
В некоторых случаях в таблице «Клиентский портфель» некорректно рассчитывался параметр «Стоимость портфеля».
В таблице «Купить/Продать» некорректно отображались дисконты по фьючерсным контрактам.
Новая версия терминала 8.13 для отладки должна была появиться в этой папке: ftp://ftp.quik.ru/public/updates/8.13/ но там на момент написания этого сообщения пусто. Не повезло 13-й версии, к сожалению.
1) Добавить функцию обратного вызова OnTimer(), которая будет вызываться терминалом с некоторой периодичностью. Надо понять, как указывать период срабатывания. Конкретно для моих задач хватит срабатывания раз в секунду, но мало ли кому чаще надо. Предлагаю обсудить, кому интересно.
Пускай первый раз функция OnTimer() запускается сразу после OnInit() и возвращает число число миллисекунд, через которое будет сделан следующий вызов функции OnTimer(). Если возвращается не число, то пусть следующий вызов будет через 1 секунду.
Реализация на стороне терминала кажется несложной.
2) Дать пользователю возможность из main-потока подать команду на запуск своей функции в потоке коллбэков. Нормальное название не придумал, но надо что-то типа
Код
executeAsCallback(function() ... end)
В принципе, имея п.2, пользователь сможет самостоятельно реализовать п.2, если только в main-потоке не выполняются тяжёлые вычислительные задачи.
Надо всё это для того, чтобы можно было выполнять в потоке коллбэков регулярные задачи, которые удобнее и архитектурно правильнее делать там, а не в main.
Может, я что-то не до конца понимаю, и мне кто-нибудь прояснит ситуацию по приведённым ниже пунктам.
1) isConnected(), конечно, хорошая функция, но мне кажется, что её корректное использование таково: если она вернула 0, то разработчик может предусмотреть запрет на выполнение каких-то действий в скрипте, поскольку информация в терминале не соответствует действительности (устарела). А вот если isConnected() вернула 1, то это ничего не гарантирует: может, нужные шлюзы ещё не подключены, может информация не до конца загрузилась с сервера. Т.е. мы можем избежать гарантированных ошибок при isConnected() == 0, но не сделать ошибок при isConnected() == 1 эта функция не помогает.
2) При разрыве соединения и повторном подключении терминала к серверу в какой-то момент происходит пропадание информации в ТТТ (и других) и её повторное появление. При работе скриптов в момент "пропадания" информации справочные функции типа getSecurityInfo() могут вернуть пустые таблицы. Это приводит к тому, что скрипт, скажем, читает информацию о размере лота, а там его нет. Неприятно.
По второму пункту хотелось бы понять, как избежать постоянных проверок, что информация отсутствует. Возможно, что при перезагрузке данных в таблицах имеет смысл блокировать запросы к функциям типа getSecurityInfo(), пока они не могут вернуть данные. Пусть скрипты подождут на этой блокировке.
Может кто поделиться своим опытом по данному поводу? Из каких ещё функций, кроме getSecurityInfo(), будут получаться пустые таблицы в моменты перезагрузки данных? Могут ли разработчики прокомментировать это (и отразить в документации, что возвращается, если нет данных)?
1) Некорректная работа кнопки «max» в специализированной форме ввода заявки.
2) Фильтр по времени в настройках графика теперь недоступен при использовании интервалов длительностью в «День», «Неделю» и «Месяц».
3) Зависание программы при вызове функции QLUA DestroyTable.
4) В некоторых случаях создание таблиц «Позиции участника по деньгам» и «Позиции участника по инструментам на выбранных счетах» было недоступно.
5) В некоторых случаях в таблицах «Позиции по инструментам» отображались дубликаты позиций.
6) Некорректное автозаполнение полей торгового счета и кода клиента в панели торговли таблицы котировок.
7) В некоторых случаях программа аварийно завершала работу при запуске.
8) Некорректная работа фильтра классов и инструментов Таблицы обезличенных сделок.
9) Программа аварийно завершала работу в некоторых случаях после разрыва связи с сервером QUIK и последующим восстановлением соединения.
10) В некоторых случаях оценка позиций в таблице «Состояние счета» выполнялась по инструменту некорректного класса.
11) В некоторых случаях на форме ввода заявки рассчитывался некорректный объём комиссии.
12) На форме ввода заявки FX-плагина рассчитывался некорректный объём комиссии.
13) В некоторых случаях программа аварийно завершала работу.
14) Для индикаторов на LUA значения параметров свечей не учитывали младшие разряды, если они равны «0».
15) Некорректная работа программы на Windows Server 2003.
16) В некоторых случаях не отображались имеющиеся позиции по деньгам и инструментам.
17) Программа аварийно завершала работу при работе скриптов на LUA с данными графиков. Набор функций для работы с данными графиков описан в пункте 3.10 Руководства пользователя LUA – Интерпретатор языка LUA / 3. Функции взаимодействия скрипта LUA и Рабочего места QUIK / 3.10 Функции для работы с графиками.
В терминале версии 8.8 вызываем пункт меню "Перезаказ данных", отмечаем галочку "Архив данных для построения графиков". После перезагрузки терминала кажется, что архив не был очищен (в QLua-скриптах количество свечей в datasource-объектах заметно больше 3000 свечей).
Если же руками почистить папки archive и archive\bak, то количество свечей становится 3000.
1. Некорректный расчет стоимости портфеля по клиентам со схемой кредитования МД+ при использовании валюты в качестве базового индикатора при настройке множеств с зависимыми ценами. 2. После редактирования пользователем настроек индикатора его целочисленные параметры ошибочно становились вещественными. 3. При смене учетной записи на графиках ошибочно отображались заявки и сделки предыдущего пользователя. 4. Ошибка, которая в некоторых случаях приводила к отображению пустых строк в Таблице заявок. 5. Ошибка, которая при закрытии таблицы, созданной при помощи скрипта Lua, могла приводить к зависанию Рабочего места QUIK. 6. В некоторых случаях в таблицах «Позиции по деньгам» и «Позиций по инструментам» могли отображаться ранее удалённые позиции. 7. Ошибка, из-за которой в некоторых случаях не отображались данные в таблице «Состояние счёта».
Исправленные недоработки, касающиеся QLua: 1) Аварийное завершение работы Рабочего места QUIK, происходившее при повторном заполнении таблиц (например, из QPILE-скрипта). 2) В некоторых случаях не освобождалась память при использовании скриптов на языке Lua. Плюс: Излишнее потребление памяти при использовании тиковых графиков
В терминале в таблице текущий параметров по инструменту CLK0 вижу дату экспирации 30.04.2020, но до погашения, якобы, осталось 20 дней. Это на бирже в одном месте поправили, а в другом — забыли, или терминал глючит?
Очень хорошо, что 17 апреля 2020 года вы выпустили версию терминала 8.5.1, а мы смогли её протестировать. Довольно быстро пользователи выявили несколько проблем, которые надо исправить.
У меня есть один вопрос и две просьбы.
Вопрос. Когда нам стоит ожидать следующую версию для тестирования?
Возможно, что ещё какие-то недоделки всплывут. Чем регулярнее релизы, тем оперативнее будет обратная связь. Мы все хотим иметь надёжный софт к сроку релиза на МосБирже.
Просьба 1 в том, чтобы файлы выкладываемого обновления позволяли обновиться сразу с версии 8.4, а не накатывать сначала 8.5.1 (нерабочий релиз с точки зрения QLua), а потом ещё какие-то файлы. Так нам всем будет удобнее.
Просьба 2 в том, чтобы от разработчиков появилось уведомление в этой ветке, чтобы как можно больше пользователей сразу включились в работу по тестированию.
Поскольку QPILE на срочном рынке при 19-значных номерах работать не будет и уже несколько лет не обновляется и не поддерживается, предлагаю удалить QPILE из терминала 8-й версии. Освободившиеся горячие клавиши отдать для более насущных нужд (например, для QLua).
Прочитал уведомление "Уведомление в связи с обновлением торговой системы срочного рынка Московской биржи (Spectra 6.3)", где говорится о 19-значных номерах заявок и сделок.
Там было написано так: Внимание! Это крайне важно!
В связи с этим вопросы:
1) Если внутри QLua для номеров заявок и сделок используются переменные числового типа, то появятся ли отрицательные значения в этих переменных?
2) Если появятся, то будет ли корректно работать постановка/снятие заявок через sendTransaction?
Просьба добавить любые другие подробности касательно того, с какими проблемами могут столкнуться роботописатели?
Берём терминал 7.16.3.14, нажимаем F9 и получаем окно с настройками клиентского места. Там есть пункты Программа -> шрифты, где можно указать шрифты для заголовков столбцов, строк, числовых данных и текстовых данных, а также для окон диалогов. Кнопка "Стандартные" устанавливает везде шрифт Segoe UI.
Однако, тут нет пункта для установки шрифта для диаграмм. У меня диаграммы создаются со шрифтом Arial, который потом можно заменить на Segoe UI.
Кажется, что здесь некоторая недоделка. По-хорошему, шрифт диаграмм также должен быть в настройках клиентского места.
Это не сообщение о какой-то ошибке или проблеме, наоборот, это сообщение, которое может помочь программирующим на qlua скрипты роботов.
Допустим, что Ваш скрипт создаёт одно или несколько окон на своей вкладке. Если не прилагать усилий и просто создавать окна через CreateWindow, эти окна получают некоторый размер и местоположение, определяемые автоматически. Не всегда это удобно. Можно после создания указать конкретное местоположение и размеры окна с помощью функции SetWindowPos(tableId, x, y, dx, dy). Однако, откуда взять значения x, y, dx, dy? Их можно подбирать методом последовательных приближений, но ведь это неудобно!
Предлагается следующий подход. Сначала Вы располагаете графики, окна Вашего скрипта и прочие элементы так, чтобы было удобно. Потом запускаете предлагаемый ниже код. Он создаёт пустое окно, которое можно перемещать и изменять его размер с помощью мышки, накладывая это окно ровно поверх каждого окна Вашего скрипта. При этом в заголовке накладываемого окна динамически обновляются параметры x, y, dx, dy, которые нужно будет подставить в функцию SetWindowPos(tableId, x, y, dx, dy) в Вашем скрипте. При этом подбор параметров можно осуществить сразу, а не методом последовательных приближений.
Вот такой вот калибровщик положения и размеров окон получается.
Если я изобрёл велосипед, а все нормальные программисты пользуются подобными штуками, отнесусь к этому с пониманием.
Код
--
-- Подгонка размеров окна.
--
local interrupted = false
function OnStop()
interrupted = true
end
function main()
local tId = AllocTable()
CreateWindow(tId)
local topPrev, leftPrev, bottomPrev, rightPrev = 0, 0, 0, 0
while not interrupted do
if IsWindowClosed(tId) then
break
end
local top, left, bottom, right = GetWindowRect(tId)
if top == nil or left == nil or bottom == nil or right == nil then
break
end
if topPrev ~= top or leftPrev ~= left or bottomPrev ~= bottom or rightPrev ~= right then
SetWindowCaption(tId, "x=" .. tostring(left)
.. ",y=" .. tostring(top)
.. ",dx=" .. tostring(right - left)
.. ",dy=" .. tostring(bottom - top))
topPrev = top
leftPrev = left
bottomPrev = bottom
rightPrev = right
else
sleep(50)
end
end
end
Просьба к разработчикам терминала обратить внимание на это сообщение и дать свои конструктивные комментарии.
Допустим, что у нас есть экземпляр DataSource, который содержит в себе 5-минутные свечки:
Код
local ds = CreateDataSource(classCode, secCode, INTERVAL_M5)
Если ds используется в потоке коллбэков, то есть гарантия, что пока в коде коллбэка идёт работа с этим экземпляром (например, итерирование по индексу от 1 до ds:Size()), данные внутри него (количество свечей, их high, low, close, volume) не меняются.
Вопрос в том, как добиться стабильности внутреннего состояния в main-потоке? Ведь если я запомню в переменной размер DataSource
Код
local size = ds:Size()
перед началом цикла, то в процессе итерирования могут как добавиться новые свечи, так и обновиться старые (скажем, сначала обновилась последняя свеча, а потом добавилась новая). При этом могут возникать неприятные эффекты типа в потоке main прочитали high последней свечи, потом поток коллбэков обновил свечу так, что новое значение close стало больше уже прочитанного значения high, а потом поток main увидел последнее значение close, которое больше прочитанного ранее high.
Не уверен, что будет происходить с содержимым DataSource при смене торговой сессии, скорее всего, ничего хорошего.
Чтобы гарантированно иметь консистентные данные, можно, например, использовать ds:SetUpdateCallback, в котором заранее производить копирование состояния ds или его изменений в другой объект, и складывать в очередь, разгребая которую из потока main до опустошения, можно всегда получить последнее консистентное состояние ds. Сейчас у меня реализован этот вариант, но кажется, что он излишне нагружает скрипт, т.к. свечки нужны в потоке main раз в 5 минут, а обновление свечей в потоке коллбэков идёт постоянно.
Не уверен, что у меня есть 100% рабочий рецепт получения консистентных данных из DataSource в потоке main, но можно пытаться делать многократное чтение данных, когда параметры каждой свечи с номером i читаются до тех пор, пока не окажется, что ds:Size() не изменился и ds:T(i), ..., ds:C(i) совпадают с прочитанными ранее, после чего полагаем, что свеча i актуальна и можно переходить к следующей.
В более сложных ситуациях подобного рода проблему полностью решил бы следующий подход, когда есть возможность запуска функции в потоке коллбэков с API типа следующего:
Код
ExecuteCallback(function()
-- обращение к данным ds, которое будет произведено в потоке коллбэков
end)
В языке программирования Java в GUI-приложениях на Swing аналогом является вызов
Код
SwingUtilities.invokeLater(Runnable doRun)
Вопросы/пожелания к разработчикам: 1) рассмотреть возможность введения подобной возможности в терминал; 2) либо отказать, либо реализовать в сжатые сроки.
Наблюдаю проблему в терминале 7.14.1.7 уже второй раз.
Строим графики цен нескольких инструментов в одном окне на низком таймфрейме (5 мин, например). Накладываем уровни Фибоначчи на график одной из цен. Ждём некоторое время, пока появляются новые свечи и график не сдвинется так, что уже не видно тех точек, по которым уровни Фибоначчи были построен. У меня обычно это наступает на следующий день после построения уровней. Возможно, надо чтобы был рестарт сервера, когда графики исчезают, а потом снова появляются.
В результате видим вот такие два графика. Первый -- это если проскроллировать график цен в прошлое, чтобы были видны точки, по которым строились уровни, а второй -- если проскроллировать график цен обратно. Когда большая свеча уходит из окна, график цен меняет свой масштаб по вертикали и при этом уровни уносит чёрт знает куда.
Пусть на совести биржи останется тот факт, что сделка прошла ровно в момент 23:50. Однако, вопрос к разработчикам терминала: почему на графике RIU7 свечка, начинающаяся в 23:50, имеет объём 2, когда в сделке был объём 1?
Где правда?
Если серьёзно, то это ошибка терминала, ведь свечи строит терминал, а не биржа.
Вопросы, по-видимому, к разработчикам и продвинутым пользователям.
В настоящий момент у меня в терминале идёт получение данных в ТТП по примерно 20 акциям и 20 фьючерсам, в таблицу обезличенных сделок идёт информация по всем акциям и фьючерсам, открыто 13 вкладок с графиками, стаканами и разного рода таблицами (всего 83 окна, включая созданные lua-скриптами), работает 12 торговых lua-скриптов (вызывают примерно раз в час функцию collectgarbage).
Перед началом вчерашней торговой сессии (дата уже сменилась на 21.06.2017) были перезаказаны данные со всеми отмеченными галочками. После завершения вчерашней торговой сессии на текущий момент (торговая дата ещё 21.06.2017) терминал занимает 3.1 Гб оперативной памяти.
Операционная система Windows 10 x64 версия 1607.
Вопросы:
1) насколько близки пределы по выделенной памяти, количеству lua-скриптов, после достижения которых будет выскакивать out of memory или появляться другие проблемы?
2) можно ли как-нибудь понять, сколько памяти тратится на работу lua-скриптов (чтобы решить, имеет ли смысл снижать её потребление)?
В файловом архиве имеется файл ftp://ftp.quik.ru/public/INDICATORS.zip, который содержит код индикаторов технического анализа. Этот код новички могут рассматривать как пособие по созданию собственных индикаторов.
Однако, в связи с нововведением
Цитата
Изменен вывод информации функциями O, H, L, C, V, T по свечкам, сформированным на пустых интервалах. Теперь, для таких свечек, функция T возвращает время интервала, а функции O, H, L, C, V возвращают nil. Для корректной проверки существования свечи на графике добавлена новая функция CandleExist(). Подробное описание приведено в п. 7.2.5 Руководства пользователя Интерпретатора языка Lua.
в терминале QUIK 7.7, теперь на графиках бывают отсутствующие свечи со значениями nil в качестве цен. Соответственно, предложенные индикаторы перестают работать, т.к. раньше такого не было.
Не могли бы разработчики скорректировать исходный код этих индикаторов, чтобы они учитывали особенность нововведения?
2016-09-14 13:26:11.668 [ERROR] QuotesExecutor:OnTransReply(): transId = 21371449, order_num=0, class_code=nil, sec_code=nil, status=11, balance=0, message=Не удалось сохранить транзакцию
При этом заявка на биржу не уходит. Логика программы-исполнителя заявок с этим справляется, но интересно, из-за чего такое случается? Что-то не так с сервером QUIK? Что скажут разработчики?
Вчера, 12.05.2016, произошла такая ситуация. В работающие в одном терминале (версия 6.17; версия сервера 5.2.6.118, аутсорсинг Арка) скрипты должен был придти коллбэк OnTrade().
В один скрипт, занимающийся мониторингом коллбэков, он пришёл (есть строка лога с параметрами OnTrade).
В другом скрипте, торговом, коллбэк OnTrade либо не вызывался, либо вызвался, но почему-то не дошёл до места, где формируется строка лога. Торговый скрипт интенсивно торгует уже более года и там нет ошибок в коде. Никаких выбросов исключений в потоке main, ошибок связи с интернетом зарегистрировано не было.
Это уже третий случай за последние три недели. Собственно, поэтому коллбэки мониторить и начали.
В связи с этим вопросы к разработчикам.
1) Может ли по какой-то причине не вызываться коллбэк OnTrade() в одном из скриптов на уровне терминала?
2) Правда ли, что в случае выброса исключений в коде функции коллбэка в потоке коллбэков скрипт должен упасть с выдачей какого-то сообщения об ошибке?
3) Может ли причина быть в связке терминал версии 6.17 и сервер версии 5.2.6.118? Посмотрите по серверным логам, если это возможно, что всё хорошо с отправкой информации по этой сделке.
1) Если в стакане отсутствуют биды/офера, то в таблице, которую возвращает getQuoteLevel2 поле bid/offer является не таблицей, как написано в документации, а пустыми строками. Наверное, надо либо исправить документацию, либо QLua.
2) В документации в разделе "Функции для заказа стакана котировок" опечатка в последнем пункте (должно быть IsSubscribed_Level_II_Quotes):
3) Допустим, что я заказываю получение стакана по какому-нибудь малоликвидному опциону с помощью Subscribe. Как понять, что уже можно получать данные с помощью функции getQuoteLevel2? Эксперименты показали, что первое событие OnQuote придёт только после изменения стакана, а мне нужен и первый снапшот, как только данные стали доступными. Как понять: стакан пуст или ещё не пришли данные с сервера? Можно, конечно, долбиться раз в N секунд командой getQuoteLevel2 если стакан пуст, но как-то это неправильно выглядит.
Просьба к разработчикам прокомментировать написанное и принять меры, если это будет признано необходимым.
Предположим, что скрипту на Lua в течение одной секунды по сигналам торговой системы нужно отправить 1000 лимитных заявок по разным инструментам и счетам, после чего успокоиться на 60 минут. Известно, что на бирже у брокера логин с производительностью 200 транзакций в секунду. Числа в этом примере условные.
Вопросы:
1) Что мы увидим: а) в скрипте Lua будут вылезать какие-то ошибки из-за большой частоты отправки заявок на сервер QUIK или б) сервер все эти заявки успешно примет в свою очередь и будет отправлять на биржу, ориентируясь на производительность логина брокера (при этом, понятное дело, ответы от биржи будут приходить в течение примерно 5 секунд).
2) Если мы увидим вариант 1а), то как понять (без экспериментов), с какой интенсивностью можно слать заявки из скрипта?
3) Если правильное функционирование сервера QUIK -- это вариант 1б), а ошибки внутри скрипта Lua вылезут, что делать (кто должен настраивать сервер QUIK, если он стоит на аутсорсинге ARQA)?
Предположим, что в скрипте заведена таблица t. В потоке коллбэков в функции OnAllTrade() в таблицу t вставляются элементы. Пусть ключом будет цена, а значением -- номер сделки. В потоке main из этой таблицы происходит чтение данных по ключу. Поскольку потоки работают параллельно, то не исключена, например, такая ситуация.
1) В потоке коллбэка в таблицу вставляется новый элемент, что приводит к необходимости перестройки внутренней структуры таблицы t (не знаю, как реализована таблица внутри Lua, но по аналогии c реализацией хэш-таблиц в Java допускаю, что иногда при вставках приходится существенно поменять внутренности объекта).
2) Процесс внутренней перестройки таблицы ещё не закончен, её внутреннее состояние неконсистентно, а в параллельном потоке main() начинается чтение из таблицы t по какому-то ключу.
Вопросы:
а) Есть ли гарантия, что из таблицы будет корректно прочитан элемент (возможно, nil), а не произойдёт какая-то ошибка?
б) А если в п.1 элементы удаляются из таблицы?
Спрашиваю потому, что одно дело обеспечить целостность примитивных данных, другое дело -- объектов со сложной внутренней структурой. Разработчики QLua не зря добавили специальные "Потокобезопасные функции для работы с таблицами Lua". Если добавление/удаление данных из lua-таблиц в самой lua-машине реализовано потокобезопасно, то это положительно отвечает на вопросы а) и б). Если нет -- тогда беда.
В моих скриптах реализован перехват ошибок и печать информации об их причинах следующим образом:
Код
local status, errMessage = xpcall(function()
...
end, function(err)
logger:error(tostring(err))
logger:error(debug.traceback())
end)
if not status and errMessage ~= nil then
logger:error(errMessage)
end
В обычных ситуациях возникновения ошибок по вине программиста в лог печатается информация об ошибке и трасса стека типа:
Код
2015-09-01 12:00:00.123 [ERROR] D:\Quik\lua\ScriptName.lua:123: Attempt to call method 'MethodName' (a nil value).
2015-09-01 12:00:00.123 [ERROR] stack traceback:
.....
Иногда (скажем, раз в неделю) скрипты падают с сообщениями вида:
Поскольку трассы стека нет и сообщение об ошибке весьма краткое, полагаю, что это внутренняя ошибка QUIK. Как быть с ошибками такого вида? В идеале хотелось бы понять, что их вызывает и как быть, чтобы их больше не было.
Воспроизведение таких ошибок, по-видимому, весьма проблематично.
Разработчики QUIK могут как-нибудь помочь в этом деле?
Чтобы получить свечные данные, можно использовать открытый график и getCandlesByIndex, а можно не открывать график и применять DataSource. Второй способ лучше, т.к. пользователь может случайно закрыть график и скрипт перестанет получать данные.
Чтобы получить данные стакана, можно открыть стакан, а можно не открывать стакан, а вызвать функцию Subscribe_Level_II_Quotes. Второй способ лучше, т.к. пользователь может случайно закрыть стакан и скрипт перестанет получать данные.
По аналогии, хочется, чтобы функция getParamEx выдавала данные по инструменту всегда, вне зависимости от того, открыта ТТП с этим инструментом и нужными полями или нет. Можно ли как-то гарантировать эту функциональность? Если нет, то может имеет смысл добавить функцию Subscribe_Param(classCode, secCode)?
В QUIK есть функция getTradeDate() для получения даты торговой сессии. Эту же информацию можно получить в виде строки с помощью функции getInfoParam("TRADEDATE"). Также с помощью getInfoParam("SERVERTIME") можно получить текущее время сервера в виде строки. Скомбинировав дату и время, и учтя переход через 24:00, можно получить текущую дату/время сервера.
Кажется, что этот способ несколько мудрёный для рядового lua-пользователя.
Предлагается добавить в qlua функцию getServerTime(), которая возвращает текущее время сервера в виде числа (примерно то же самое возвращает os.time()). Если при этом будет возвращаться время с миллисекундами/микросекундами после десятичной запятой, то будет совсем хорошо.
Время в виде числа таблицу с полями year, month, day, hour, min, sec, isdst можно будет перевести с помощью стандартной функции os.date("*t", time). Либо можно добавить аргумент в функцию getServerTime() по смыслу аналогичный аргументу стандартной функции os.date(), чтобы получать не только таблицы, но и строки времени различного формата.
Если будете добавлять эту функцию, обеспечьте, пожалуйста, монотонность течения времени (к примеру, результаты getInfoParam("LASTRECORDTIME") этому свойству не удовлетворяют).
Уже существует функция getCandlesByIndex, которая выдаёт несколько последовательных свечей с графика. Иногда хотелось бы получать свечу по её времени. Скажем, пусть будет что-то вроде функции getCandleByTime(datetime), которая выдаёт свечу либо с указанным временем, либо, если именно такого времени нет, то самую последнюю свечу, время которой ещё меньше указанного момента в datetime. Если такой свечи нет, пусть выдаётся nil.
Можно это реализовать с помощью двоичного поиска, запрашивая по одной свече с помощью getCandlesByIndex, но это недружественно для пользователя. Возможно, что разработчики QUIK могут сделать более эффективную реализацию (не знаю, как устроены графики внутри QUIK).
Предлагается обсудить это предложение. Возможно, доработать его, чтобы было как можно более удобно такой функциональностью пользоваться как можно более широкому кругу пользователей. А потом пусть будет зарегистрировано такое пожелание для дальнейшей реализации.