В новой версии терминала QUIK 8.5.2 произведён апгрейд языка Lua для написания торговых скриптов с версии 5.1 до версии 5.3. Это нужно для того, чтобы корректно обрабатывать 19-значные номера заявок и сделок на срочном рынке МосБиржи. Типа number в Lua 5.1 не подходит: там все числа хранятся как double, соответственно целые числа до 2^53 = 9 007 199 254 740 992 записываются без потери точности, а 19-значные номера заявок и сделок будут больше этой границы.
Версия Lua 5.3 обратно несовместима с Lua 5.1. Я почти не использовал внешние библиотеки и для меня было два важных изменения: отказ от module (это было сделано в версии 5.2) и введение целочисленной арифметики (версия 5.3).
Для избавления от использования module пришлось переработать много кода, хотя изменения были несложные. Приведу пример. Раньше был такой код Arrays.lua для работы с массивами:
--
-- Выполнение действий с массивами.
--
local pairs = pairs
local type = type
module(...)
--- Создать копию массива (таблицы)
-- @return копию массива (таблицы)
function copy(array)
local copy_array = {}
if type(array) ~= "table" then
return array
end
for k, v in pairs(array) do
if type(v) == "table" then
copy_array[k] = copy(v)
else
copy_array[k] = v
end
end
return copy_array
end
--- Узнать, начинается ли индексация в массиве с нуля или с единицы.
-- @return 0 или 1
function base(array)
if array[0] ~= nil then
return 0
else
return 1
end
end
--- Вычислить число элементов в массиве.
-- @return число элементов в массиве
function size(array)
local n = 0
for _, _ in pairs(array) do
n = n + 1
end
return n
end
--- Проверить пустой или нет массив.
-- @return true/false
function isEmpty(array)
for _, _ in pairs(array) do
return false
end
return true
end
--- Получить первый индекс массива, где ничего не записано. Поиск начинается с 1.
-- @return первый индекс массива, где ничего не записано
function firstEmptyIndex(array)
local i = 1
while array[i] ~= nil do
i = i + 1
end
return i
end
Для переработки надо:
1) удалить module и запоминание функций до него;
2) завести таблицу с функциями, которые были в модуле;
3) вернуть эту таблицу с помощью return.
В результате код становится таким:
--
-- Выполнение действий с массивами.
--
local Arrays = {}
--- Создать копию массива (таблицы)
-- @return копия массива (таблицы)
local function copy(array)
local copy_array = {}
if type(array) ~= "table" then
return array
end
for k, v in pairs(array) do
if type(v) == "table" then
copy_array[k] = copy(v)
else
copy_array[k] = v
end
end
return copy_array
end
Arrays.copy = copy
--- Узнать, начинается ли индексация в массиве с нуля или с единицы.
-- @return 0 или 1
local function base(array)
if array[0] ~= nil then
return 0
else
return 1
end
end
Arrays.base = base
--- Вычислить число элементов в массиве.
-- @return число элементов в массиве
local function size(array)
local n = 0
for _, _ in pairs(array) do
n = n + 1
end
return n
end
Arrays.size = size
--- Проверить пустой или нет массив.
-- @return true/false
local function isEmpty(array)
return next(array) == nil
end
Arrays.isEmpty = isEmpty
--- Получить первый индекс массива, где ничего не записано. Поиск начинается с 1.
-- @return первый индекс массива, где ничего не записано
local function firstEmptyIndex(array)
local i = 1
while array[i] ~= nil do
i = i + 1
end
return i
end
Arrays.firstEmptyIndex = firstEmptyIndex
return Arrays
Второе важное изменение касается целочисленной арифметики. В Lua 5.3 есть 2 типа чисел: integer и float. Для первых реализована целочисленная арифметика, вторые нужны для представления вещественных чисел. Можно считать, что в Lua 5.1 были только float-числа. Номера заявок и сделок теперь будут представляться типом integer, и там хватит места для 19-значных чисел.
В терминале QUIK все торговые данные про цены сделок, их объёмы и т.п. приходят в виде float. Раньше, до версии 8.5.2, если количество акций в сделке или цена оказывались целым числом, то в случае преобразования в строку функцией tostring() результат не имел десятичной точки. Сейчас же она появляется всегда. Например, для цены RI 109120 в старых версиях терминала получается строка «109120», а в новых — «109120.0»; три фьючерса в сделке вместо строки «3» дают «3.0».
В принципе, это не сильно мешает, но во многих местах (логах, сообщениях, создаваемых скриптами таблицах с рыночной информацией и т.п.) вылезаются эти лишние ".0" в конце. Хуже обстоит дело в том месте, где отправляется транзакция на постановку заявки. Если в новой версии терминала указать в поле QUANTITY вместо «3» значение «3.0», то sendTransaction не отправит транзакцию и выдаст ошибку:
«Сообщение об ошибке: Число не может содержать знак разделителя дробной части».
Выйти из положения можно следующим образом, который подойдёт для Lua 5.3 и 5.1 сразу. Определим функцию tryInt, которая пытается преобразовать float-число в integer, если это возможно:
local tointeger = math.tointeger or (function(x) return x end)
--- Сделать вещественное число целым, если это возможно.
-- @param x вещественное число
-- @return целое число или исходное вещественное число, если преобразование невозможно
function tryInt(x)
return tointeger(x) or x
end
Теперь ищем все места, где заполняется таблица с параметрами транзакции для постановки заявки, и там вместо обычного
QUANTITY = tostring(выражение),
пишем
QUANTITY = tostring(tryInt(выражение)),
В принципе, этого должно быть достаточно для правильной работы скриптов.
Если же хочется сделать, чтобы не вылезали «лишние хвосты» вида ".0" в других местах, можно поставить аналогичные «ловушки» для выделения целочисленных значений в местах, где они
приходят в QLua-код. У меня это происходит в функциях обратного вызова OnOrder, OnTrade и OnTransReply.
В функции OnOrder я преобразую с помощью функции tryInt() поля balance и qty, в функции OnTrade — поля order_qty и qty, в функции OnTransReply — поле quantity. Поля с ценой price решил не трогать: пусть всегда имеют тип float.
Возможно, в вашем коде будут ещё какие-то изменения.
Если есть желание помочь и передать свой опыт, — напишите в комментариях, как вы добивались работоспособности QLua-кода в терминале QUIK 8.5.2.
Вроде, поместили функции в массив, и пользуйся на здоровье.
local Arrays = require(«util.Arrays»)
как у Вас терминал 8.5.2 не падал? у меня дак рекорд 7 дней и сегодня упал без дампа( но стал заметно стабильнее чем 8.5.1 тот совсем только два дня держался
А вот для целых чисел применение math.floor бессмысленно!
Отрицательное число это округлит до ближайшего меньшего целого.
www.lua.org/manual/5.3/
> = math.modf (-1.2345)
-1 -0.2345
local tostring__ = tostring
Function tostring(x)
If math.tointeger(x) then
Return string.format("%0i",x)
End
Return tostring__(x)
End
Ну и размер массива можно вычислить встроенной функцией, а не пользовательской. Функция появилась в 5.3 в пространстве table
Также там есть теперь и table.copy… Одним словом, выкинуть можно весь этот модуль полностью)))))
что-то у меня скомпиленный индикатор не хочет запускать
даже после перекомпиляции под lua 5.3.5
а без компиляции норм
upd: разобрался, надо использовать x64 luac, а я случайно собрал x86 luac из исходников