Если функцию sendTransaction вызвать одновременно из двух потоков - один вызов из main, а другой из функции обратного вызова, то на корректную транзакцию может прийти ответ с ошибкой "Неверный формат заявки".
Ниже приведён скрипт, воспроизводящий проблему. В нём нужно перед запуском заменить номер счёта в первой строке. Для появления ошибки может потребоваться несколько запусков скрипта.
В терминале версии 7.2.2.3 ошибки не было. В версиях 7.4, 7.5 и 7.6 ошибка есть.
Скрипт:
Скрытый текст
Код
local accountName = "SPBFUT00000" -- заменить на правильный номер счёта
local classCode = "SPBFUT"
local secCode = "SRZ6"
local priceMin = nil
local logFile = nil
local running = true
local testStarted = false
local activeOrders = {}
function Log(message)
if logFile ~= nil then
local timestamp = os.date("[%Y-%m-%d %X]")
logFile:write(timestamp .. " " .. message .. "\n")
logFile:flush()
end
end
function LogTable(message, tbl)
local res = {}
for key, value in pairs(tbl) do
local vtype = type(value)
if vtype == "nil" then
res[#res + 1] = key .. " = <nil>"
elseif vtype == "number" then
res[#res + 1] = key .. " = " .. value
elseif vtype == "string" then
res[#res + 1] = key .. " = " .. string.format("%q", value)
else
res[#res + 1] = key .. " = ?"
end
end
Log(message .. table.concat(res, "; "))
end
function PlaceOrders(price, count, id)
for i = 1, count do
local transaction = {
["ACTION"] = "NEW_ORDER",
["CLASSCODE"] = classCode,
["SECCODE"] = secCode,
["ACCOUNT"] = accountName,
["OPERATION"] = "B",
["PRICE"] = tostring(price),
["QUANTITY"] = "1",
["TRANS_ID"] = tostring(id),
}
LogTable("Placing order: ", transaction)
local message = sendTransaction(transaction)
Log("Result: " .. id .. ", [" .. message .. "]")
id = id + 1
end
end
function CancelOrders(id)
for ordernum, value in pairs(activeOrders) do
local transaction = {
["ACTION"] = "KILL_ORDER",
["CLASSCODE"] = classCode,
["SECCODE"] = secCode,
["ORDER_KEY"] = tostring(ordernum),
["TRANS_ID"] = tostring(id),
}
LogTable("Cancelling order: ", transaction)
local message = sendTransaction(transaction)
Log("Result: " .. id .. ", [" .. message .. "]")
id = id + 1
end
end
function OnTransReply(transaction)
LogTable("OnTransReply: ", transaction)
if not testStarted then
-- этот код вызывается только один раз для старта теста
Log("Starting test")
testStarted = true
-- ставим тестовые заявки
PlaceOrders(priceMin, 5, 3000)
end
if transaction.status == 3 then
activeOrders[transaction.order_num] = true
else
-- если попали сюда, значит произошла ошибка
Log("ERROR: " .. transaction.result_msg)
end
end
function OnStop()
running = false
end
function GetPriceMin()
local param = getParamEx(classCode, secCode, "pricemin")
if param == nil or param.result ~= "1" then
return 0
end
local value = tonumber(param.param_value)
if value == nil then
return 0
end
Log("pricemin = " .. value)
return value
end
function OnInit(scriptName)
logFile = io.open(scriptName .. ".log", "at")
end
function main()
-- получаем нижний лимит цены
priceMin = GetPriceMin()
while running and priceMin == 0 do
sleep(100)
priceMin = GetPriceMin()
end
-- отправляем первую заявку
PlaceOrders(priceMin, 1, 1000)
-- активное ожидание начала теста
while not testStarted do
end
-- ставим тестовые заявки
PlaceOrders(priceMin, 5, 2000)
-- ждём исполнение всех транзакций
sleep(2000)
-- снимаем все заявки
CancelOrders(4000)
-- ждём исполнение всех транзакций
sleep(2000)
logFile:close()
logFile = nil
end
Очень хорошо, что у Вас получилось воспроизвести ошибку "Неверный формат заявки". У нас она тоже изредка появляется, хотя мы не отправляем заявки из разных потоков, но в терминале одновременно работает несколько скриптов, каждый из которых шлёт заявки из своего main-потока. Теперь разработчики, скорее всего, быстро найдут и устранят причину (скорее всего, баг синхронного доступа к общему ресурсу). По нашему обращению не получилось этого сделать.
SG написал: Если функцию sendTransaction вызвать одновременно из двух потоков - один вызов из main, а другой из функции обратного вызова, то на корректную транзакцию может прийти ответ с ошибкой "Неверный формат заявки".
Ниже приведён скрипт, воспроизводящий проблему. В нём нужно перед запуском заменить номер счёта в первой строке. Для появления ошибки может потребоваться несколько запусков скрипта.
В терминале версии 7.2.2.3 ошибки не было. В версиях 7.4, 7.5 и 7.6 ошибка есть.
Скрипт: Скрытый текст
Код
local accountName = "SPBFUT00000" -- заменить на правильный номер счёта
local classCode = "SPBFUT"
local secCode = "SRZ6"
local priceMin = nil
local logFile = nil
local running = true
local testStarted = false
local activeOrders = {}
function Log ( message )
if logFile ~ = nil then
local timestamp = os.date ( "[%Y-%m-%d %X]" )
logFile:write(timestamp .. " " .. message .. "\n" )
logFile:flush()
end
end
function LogTable ( message , tbl)
local res = {}
for key, value in pairs(tbl) do
local vtype = type(value)
if vtype = = "nil" then
res[ # res + 1 ] = key .. " = <nil>"
elseif vtype = = "number" then
res[ # res + 1 ] = key .. " = " .. value
elseif vtype = = "string" then
res[ # res + 1 ] = key .. " = " .. string.format ( "%q" , value)
else
res[ # res + 1 ] = key .. " = ?"
end
end
Log( message .. table.concat (res, "; " ))
end
function PlaceOrders (price, count, id)
for i = 1 , count do
local transaction = {
[ "ACTION" ] = "NEW_ORDER" ,
[ "CLASSCODE" ] = classCode,
[ "SECCODE" ] = secCode,
[ "ACCOUNT" ] = accountName,
[ "OPERATION" ] = "B" ,
[ "PRICE" ] = tostring(price),
[ "QUANTITY" ] = "1" ,
[ "TRANS_ID" ] = tostring(id),
}
LogTable( "Placing order: " , transaction)
local message = sendTransaction (transaction)
Log( "Result: " .. id .. ", [" .. message .. "]" )
id = id + 1
end
end
function CancelOrders (id)
for ordernum, value in pairs(activeOrders) do
local transaction = {
[ "ACTION" ] = "KILL_ORDER" ,
[ "CLASSCODE" ] = classCode,
[ "SECCODE" ] = secCode,
[ "ORDER_KEY" ] = tostring(ordernum),
[ "TRANS_ID" ] = tostring(id),
}
LogTable( "Cancelling order: " , transaction)
local message = sendTransaction (transaction)
Log( "Result: " .. id .. ", [" .. message .. "]" )
id = id + 1
end
end
function OnTransReply (transaction)
LogTable( "OnTransReply: " , transaction)
if not testStarted then
-- этот код вызывается только один раз для старта теста
Log( "Starting test" )
testStarted = true
-- ставим тестовые заявки
PlaceOrders(priceMin, 5 , 3000 )
end
if transaction.status = = 3 then
activeOrders[transaction.order_num] = true
else
-- если попали сюда, значит произошла ошибка
Log( "ERROR: " .. transaction.result_msg)
end
end
function OnStop ()
running = false
end
function GetPriceMin ()
local param = getParamEx (classCode, secCode, "pricemin" )
if param = = nil or param.result ~ = "1" then
return 0
end
local value = tonumber(param.param_value)
if value = = nil then
return 0
end
Log( "pricemin = " .. value)
return value
end
function OnInit (scriptName)
logFile = io.open (scriptName .. ".log" , "at" )
end
function main ()
-- получаем нижний лимит цены
priceMin = GetPriceMin()
while running and priceMin = = 0 do
sleep ( 100 )
priceMin = GetPriceMin()
end
-- отправляем первую заявку
PlaceOrders(priceMin, 1 , 1000 )
-- активное ожидание начала теста
while not testStarted do
end
-- ставим тестовые заявки
PlaceOrders(priceMin, 5 , 2000 )
-- ждём исполнение всех транзакций
sleep ( 2000 )
-- снимаем все заявки
CancelOrders( 4000 )
-- ждём исполнение всех транзакций
sleep ( 2000 )
logFile:close()
logFile = nil
end
Добрый день,
Описанная в данном инциденте проблема была устранена в версии 7.7.0 терминала QUIK. Рекомендуем Вам обновить версию программы.