RPC-сервис для вызова процедур из QLUA -- Lua-библиотеки торгового терминала QUIK (ARQA Technologies).
- Зачем?
- Как это работает?
- Как пользоваться?
- Схемы сообщений Protocol Buffers
- Схемы сообщений JSON
- Примеры и гайды
- Разработчикам
- FAQ
- English version
Торговый терминал QUIK -- одно из немногих средств для торговли на российском рынке. Он предоставляет API в виде библиотеки QLua, написанной на Lua. Написать торговую программу, работающую с QUIK, на чём либо отличном от Lua до сих пор было не так просто (хотя и предпринимаются попытки вытащить API QLua в другие языки, например, в C# -- QUIKSharp).
Данный сервис представляет собой RPC-прокси над API библиотеки QLua. Сервис исполняется в терминале QUIK в виде Lua-скрипта и имеет прямой доступ к библиотеке QLua. Общение сторонних программ с сервисом осуществляется посредством ZeroMQ ("сокеты на стероидах"), реализуя паттерн REQ/REP (Request / Response), по протоколу TCP. Запросы на вызов удалённых процедур и ответы с результатами выполнения этих процедур передаются либо в бинарном виде, сериализованные с помощью Protocol Buffers, либо в символьном виде, сериализованные в JSON.
Помимо вызова удалённых процедур сервис также может рассылать оповещения о событиях терминала QUIK, реализуя паттерн PUB/SUB (Publisher / Subscriber).
Соответственно, выбор языка программирования для взаимодействия с QLua ограничивается лишь наличием на этом языке реализации ZeroMQ, коих довольно большое количество.
DLL-файлы из qlua_redist/...
были взяты от QUIK 9.2.3.15. Соответственно, библиотека расчитана на работу с терминалом примерно этой версии и может не(корректно) работать в терминалах QUIK версий, отличных от указанной.
Распакуйте архив built/quik_lua_rpc.tar.xz
в каталог установленного терминала Quik (например, D:/QUIK/
).
Результаты антивирусной проверки built/quik_lua_rpc.tar.xz
: VirusTotal.
- Установите Docker и Docker-compose для вашей операционной системы.
- Клонируйте этот репозиторий.
- Хорошая идея - заменить библиотеки в каталоге
quik_redist
на версии из вашего Quik (результаты антивирусной проверки 03.12.2021: lua53.dll, qlua.dll). - Откройте консоль в каталоге репозитория.
- Соберите образ Docker.
docker-compose build --force-rm
- Создайте установочный архив.
docker-compose run quik-lua-rpc
- Распакуйте архив
built/quik_lua_rpc.tar.xz
в каталог установленного терминала Quik (например,D:/QUIK/
).
В терминале QUIK в меню Lua-скриптов добавить и запустить скрипт %PATH_TO_SERVICE%/main.lua
, где %PATH_TO_SERVICE%
-- путь до папки с программой включительно (например, D:/QUIK/lua/quik-lua-rpc
).
Конфигурации точек подключения находятся в файле %PATH_TO_SERVICE%/config.json
.
Краткая справка по формату конфигурационного файла на примере:
{
// Точки подключения. Может быть сколько угодно различных точек подключения со своими настройками.
"endpoints": [
{
// Тип точки подключения:
// "RPC" -- для удалённого вызова процедур,
// "PUB" -- для рассылки событий терминала.
"type": "RPC",
// Тип протокола сериализации/десериализации сообщений:
// "json" -- JSON
// "protobuf" -- Protocol Buffers
"serde_protocol": "json",
// Признак активности/неактивности точки. Ненужные на данный момент точки можно деактивировать.
"active": true,
// TCP-адрес точки подключения.
// На данный момент ZeroMQ не поддерживает ipc-абстракцию под Windows,
// поэтому для транспорта остаётся TCP.
"address": {
"host": "127.0.0.1",
"port": 5560
},
// Секция настройки аутентификации для точки подключения.
"auth": {
// Механизм аутентификации ZeroMQ:
// "NULL" или пустая строка (нет аутентификации),
// "PLAIN" (пара логин/пароль без шифрования трафика),
// "CURVE" (ключевая пара и шифрование трафика).
"mechanism": "CURVE",
// Секция настройки PLAIN-аутентификации.
// Может отсутствовать при выборе механизма NULL или CURVE.
"plain": {
// Список пользователей для точки подключения.
"users": [
{"username": "test_user", "password": "test_password"}
]
},
// Секция настройки CURVE-аутентификации.
// Может отсутствовать при выборе механизма NULL или PLAIN.
"curve": {
// Серверная ключевая пара CURVE
// (сгенерировать новую пару можно с помощью скрипта curve_keypair_generator.lua)
"server": {
"public": "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7",
"secret": "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6"
},
// Список публичных CURVE-ключей пользователей
"clients": ["Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID"]
}
}
},
{
"type": "PUB",
"serde_protocol": "json",
"active": true,
"address": {
"host": "127.0.0.1",
"port": 5561
},
"auth": {
"mechanism": "PLAIN",
"plain": {
"users": [
{"username": "admin", "password": "letmein"}
]
}
}
}]
}
Убедитесь, что используемые вами порты открыты.
Схемы сообщений расположены внутри директории qlua/rpc
в виде файлов .proto.
** В РАЗРАБОТКЕ **
В общих чертах, формат сообщений такой:
Запрос:
{
"method":"НАЗВАНИЕ_QLUA-ФУНКЦИИ",
"args": {
// АРГУМЕНТЫ QLUA-ФУНКЦИИ
}
}
Ответ:
{
"method": "НАЗВАНИЕ_QLUA-ФУНКЦИИ",
"result": // РЕЗУЛЬТАТ QLUA-ФУНКЦИИ (число, объект, строка -- в зависимости от вызываемой функции)
}
Ответ в случае ошибки сервиса:
{
"method":"НАЗВАНИЕ_QLUA-ФУНКЦИИ",
"error": {
"code": // ЧИСЛОВОЙ КОД ОШИБКИ,
"message": "ИНФОРМАЦИЯ ОБ ОШИБКЕ"
}
}
!!! Все дробные числа передаются как строки (что в аргументах, что в ответе от сервиса).
- Java:
- к версии сервиса v1.0: https://github.com/Enfernuz/quik-lua-rpc-java-client/releases/tag/v1.0
- к версии сервиса v2.0: https://github.com/Enfernuz/quik-lua-rpc-java-client
- Python:
- к версии сервиса v1.0: https://github.com/euvgub/mmvddss
- к версии сервиса v2.0: https://gitlab.com/abrosimov.a.a/qlua
Инструкцию для разработчиков для версий v1.x можно найти здесь: https://github.com/Enfernuz/quik-lua-rpc/blob/master/CONTRIBUTING.md
Для версий v2.x документация находится в разработке.
Q: Используешь Protocol Buffers, но не используешь gRPC. Как так?
A: Для Lua пока не запилили генерацию стабов gRPC. Сообщите, когда появится.
Q: А что насчёт Thrift? Там вроде есть поддержка Lua.
A: Если мне память не изменяет, там в зависимостях библиотеки, для которых исходники только под UNIX (например, luabpack
).
If you deliberately want to have the English version of this README or just want some answers, feel free to reach me via GitHub or email. I'm planning to do some English translation, but the laziness is unbearable... Go on, kick my ass a little :)