Заметил, что отправка транзакций - выставление и снятие заявок - трудоёмкая операция. Торгую 50-ю акциями. Если у меня висит 50 заявок, то при их массовом одновременном снятии квик подвисает на несколько секунд. При быстром выставлении такого же числа заявок он тоже зависает. Поэтому вопросы. 1. Наблюдения верны? Отправка транзакций - ресурсоёмкая процедура? 2. Хочу отправлять транзакции из OnParam. Это плохая идея? С точки зрения логики работы программы это было бы очень удобно. Сейчас у меня отправка заявок идёт в функции main, там в бесконечном цикле перебираются одна за другой 50 акций на соблюдение условия выставления/снятия. Хочу перенести этот блок в OnParam. Заявок ставится много, они всё время перевыставляются. В день отправляется до 10 тысяч заявок, то есть с учётом снятия это 20 000 транзакций.
QUIK clients support
Сообщений: Регистрация: 27.01.2015
18.07.2019 07:49:09
Цитата
Let_it_go написал: Заметил, что отправка транзакций - выставление и снятие заявок - трудоёмкая операция. Торгую 50-ю акциями. Если у меня висит 50 заявок, то при их массовом одновременном снятии квик подвисает на несколько секунд. При быстром выставлении такого же числа заявок он тоже зависает. Поэтому вопросы. 1. Наблюдения верны? Отправка транзакций - ресурсоёмкая процедура? 2. Хочу отправлять транзакции из OnParam. Это плохая идея? С точки зрения логики работы программы это было бы очень удобно. Сейчас у меня отправка заявок идёт в функции main, там в бесконечном цикле перебираются одна за другой 50 акций на соблюдение условия выставления/снятия. Хочу перенести этот блок в OnParam. Заявок ставится много, они всё время перевыставляются. В день отправляется до 10 тысяч заявок, то есть с учётом снятия это 20 000 транзакций.
Добрый день.
1. Нет, отправка 50 транзакций не должна подвешивать рабочее место QUIK.
2. Если в OnParam будут выполняться долгие циклы по перебору 50 инструментов и проверять не выполнилось ли условие для отправки транзакции, то тут могут наблюдаться зависания.
Выложите свой скрипт, мы посмотрим.
Пользователь
Сообщений: Регистрация: 29.03.2017
18.07.2019 12:05:10
функция для снятия всех заявок. в неё передаётся таблица с тикерами.
Код
function CleanActive (ticker_list) --переписать её, чтобы искать с конца.
local row={}
for i=0,getNumberOf("orders")-1,1 do
row=getItem("orders",i)
local sec=row.sec_code
if table_contains(ticker_list, sec) and orderflags2table(row.flags).active then
res,ms=killOrder(tostring(row.order_num),sec,row.class_code)
end
end
end
Код
function table_contains(table, element)
for _, value in pairs(table) do
if value == element then return true end
end
return nil
end
Я запускаю CleanActive из OnStop и из самого начала функции main. Это очень часто вешает квик, приходится его убивать через окно с процессами.
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
18.07.2019 13:07:36
Цитата
Let_it_go написал: Я запускаю CleanActive из OnStop и из самого начала функции main. Это очень часто вешает квик, приходится его убивать через окно с процессами.
Добрый день. Функция OnStop() это тоже функция обратного вызова, соответственно тяжелые и долгие операции в ней будут подвешивать терминал. Допустим у Вас на момент остановки скрипта в терминале 10 000 заявок, при этом большинство из них сняты (делаю вывод из вашего описания из #1 поста), тогда в функции CleanActive() скрипт будет пробегать по всем заявкам, это 10 000 итераций, так же в таблице ticker_list у Вас, допустим, 50 инструментов, линейный пробег по всем еще увеличивает количество итераций (берем среднее значение=25, т.к. не обязательно, что инструмент row.sec_code будет самым последним), итого 10 000 * 25=250 000 итераций. Пока все эти циклы будут выполняться, терминал будет ждать завершения OnStop() и соответственно висеть. Могу только посоветовать оптимизировать логику работы функции CleanActive - использовать функцию SearchItems для поиска всех активных заявок по инструментам из ticker_list. Так же можно убрать линейный забег в функции table_contains, этим Вы уже в разы уменьшите количество итераций, в интернете много примеров как это сделать, вот например:
Код
function addToTable(table, key)
table[key] = true
end
function removeFromTable(table, key)
table[key] = nil
end
function tableContains(table, key)
return table[key] ~= nil
end
Если будут затруднения с использованием функции SearchItems, пишите.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 29.03.2017
19.07.2019 07:02:22
Nikolay Pavlov, посмотрел описание функции SearchItems. Почему вы её рекламируете по сравнению с
Код
for i=0,getNumberOf("orders")-1,1 do
В ней тоже задаётся список строчек с какой по какую искать. Если у меня за день 10 000 заявок, скрипт будет пробегать по всем. Разве не так?
Пользователь
Сообщений: Регистрация: 29.03.2017
19.07.2019 07:13:40
Nikolay Pavlov, переменная ticker_list из моего примера:
Код
1=SBER;2=GAZP;3=GMKN;4=LKOH;................
Ключ - число, значение - тикер. Ваш совет:
Код
function tableContains(table, key)
return table[key] ~= nil
end
не подойдёт в чистом виде. Разве что переделать тикер лист в
Код
'SBER'=1; 'GAZP' = 2; 'GMKN' = 3;
тогда ваша функция сработает. Но и в этом случае она где-то там невидимо для меня будет перебирать всю таблицу в поисках ключа. Спасибо за помощь!
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
19.07.2019 07:23:03
Цитата
Let_it_go написал: Разве что переделать тикер лист в Код'SBER'=1; 'GAZP' = 2; 'GMKN' = 3;тогда ваша функция сработает. Но и в этом случае она где-то там невидимо для меня будет перебирать всю таблицу в поисках ключа.Спасибо за помощь!
Добрый день. Вам нужно переделать ticker_list в набор вида:
Код
'SBER'=true; 'GAZP'=true; 'GMKN'=true;...
Для этого, Вам достаточно в месте, где Вы формируете таблицу ticker_list использовать вышеописанную функцию:
Код
function addToTable(table, key)
table[key] = true
end
в этом случае, перебора никакого не будет, (даже "где-то там невидимо..."), т.к. обращение выполняется напрямую по ключу, это в разы быстрее чем перебирать все значения таблицы в цикле. Нужно просто вместо вашей старой функции table_contains использовать:
Код
function tableContains(table, key)
return table[key] ~= nil
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
19.07.2019 07:31:29
Цитата
Let_it_go написал: посмотрел описание функции SearchItems. Почему вы её рекламируете по сравнению с Кодfor i=0,getNumberOf("orders")-1,1 doВ ней тоже задаётся список строчек с какой по какую искать. Если у меня за день 10 000 заявок, скрипт будет пробегать по всем. Разве не так?
Данная функция сделает это гораздо быстрее.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 29.03.2017
19.07.2019 07:40:15
Nikolay Pavlov, спасибо за совет! вопрос по SearchItems. Никогда с ней не работал.
Хочу получить мои сделки за сегодня по BANEP
Код
function fn (t)
if t.sec_code=='BANEP' then
return true
end
end
tbl=SearchItems('trades', 0, getNumberOf("trades")-1, fn, "qty,class_code, sec_code")
у меня за день и правда 90 сделок, но не понятно в чём толк этой функции? ----------------
Если написать чуть-чуть иначе:
Код
function fn (t)
if t.sec_code=='BANEP' then
return t
end
end
tbl=SearchItems('trades', 0, getNumberOf("trades")-1, fn)
то он пишет такое:
Цитата
1=18;2=20;3=21;
19,21,22 - это номера моих сделок с Башнефтью. С учётом сдвига всё верно. Но как получить все поля по этим сделкам?
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
19.07.2019 07:56:43
Цитата
Let_it_go написал: 19,21,22 - это номера моих сделок с Башнефтью. С учётом сдвига всё верно. Но как получить все поля по этим сделкам?
Функция возвращает только индексы заявок, которые удовлетворяют условиям Вашей функции fn(), дальше нужные заявки нужно забрать функцией row=getItem("orders",i), где i, это индекс из таблицы, которую вернула функция SearchItems.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
19.07.2019 08:04:56
Так же стоит обратить внимание на то, что написано в документации по функции SearchItems
fn – функция обратного вызова, возвращающая одно из следующих значений:
true – текущий индекс учитывается в результате;
false – текущий индекс не учитывается в результате;
nil – поиск прерывается, функция SearchItems возвращает таблицу с индексами, найденными ранее, включая текущий индекс.
Так что Вам лучше переписать функцию fn, вот пример чтобы выбрать все активные заявки из Вашего списка ticker_list (если функцию table_contains() так же переписать на поиск по ключу, как я писал выше, все должно отрабатывать быстро):
Код
function fn (ord_sec_code, ord_flags)
if table_contains(ticker_list, ord_sec_code) and orderflags2table(ord_flags).active then
return true
else
return false
end
end
tbl=SearchItems('trades', 0, getNumberOf("trades")-1, fn, "sec_code,flags")
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
19.07.2019 08:06:39
Конечно же должно быть обращение к таблице 'orders'
Код
function fn (ord_sec_code, ord_flags)
if table_contains(ticker_list, ord_sec_code) and orderflags2table(ord_flags).active then
return true
else
return false
end
end
tbl=SearchItems('orders', 0, getNumberOf("orders")-1, fn, "sec_code,flags")
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 29.03.2017
22.07.2019 15:39:30
Nikolay Pavlov, спрошу про другой случай. Я знаю, что в нужной мне таблице только один элемент с нужным параметром. Например, я ищу в depo_limits текущий остаток по SBER. Как мне в SearchItems оборвать поиск сразу после того как SBER был найден?
Я делаю что-то в таком духе:
Код
function fn(t)
if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then
return true
else
return false
end
end
tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)
и второй вопрос, как мне в функцию fn передать переменную sec?
Пользователь
Сообщений: Регистрация: 30.01.2015
22.07.2019 19:55:17
Если пользовательская функция сравнения в search items возвращает nil, то поиск прерывается и текущий элемент в таблице результатов не попадает.
значит, необходимо перед вызовом searchitems создать флаг ин иницализировать его скажем в nil, при нахождении вашего единственного элемента таблицы изменить флаг на true.
при этом в самом начале пользовательский функции сравнения проверять этот флаг. Если он true, значит на пред итерации был найден ваш элемент и необходимо прервать поиск - вернуть nil из функции сравнения.
Пасхалочка для Алексея Иванникова:
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
24.07.2019 07:12:12
Цитата
Let_it_go написал: и второй вопрос, как мне в функцию fn передать переменную sec?
Добрый день. По первому вопросу s_mike Вам дал исчерпывающий ответ. По второму вопросу про переменную sec, достаточно ее объявить на уровень выше объявления функции fn, она будет видна внутри функции fn, это можно сделать на глобальном уровне, или же непосредственно перед вызовом функции SearchItems, например:
Код
sec='SBER'
client_code='12345'
function main()
function fn(t)
if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then
return true
else
return false
end
end
--или здесь...
--sec='SBER'
--client_code='12345'
tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
function fn(t)
if stop_search then return nil end --stop_search - это флаг. Изначально равен nil
if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then
stop_search=true
return true
else
return false
end
end
function get_position (sec)
stop_search=nil --убиваем флаг, выставленный на прежних запусках функции.
tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)
limit = getItem("depo_limits", tbl_indxs[1]) --найден 1 индекс, его и берём.
local lot=lot[sec]--lot[sec] ранее определена
return limit.currentbal/lot,limit.locked_buy/lot, limit.locked_sell/lot, limit.awg_position_price
end
Пользователь
Сообщений: Регистрация: 29.03.2017
24.07.2019 18:15:35
Вот рабочий вариант, внедрённый в робота. Увы, приходится объявлять переменную paper как глобальную, потому что sec внутри fn не видна.
Код
function fn(t)
if stop_search then return nil end --stop_search - это флаг. Изначально равен nil
if t.sec_code == paper and t.client_code==client_code and t.limit_kind==2 then
stop_search=true
return true
else
return false
end
end
function get_position (sec)
paper=sec
stop_search=nil --убиваем флаг, выставленный на прежних запусках функции.
tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)
if tbl_indxs then
limit = getItem("depo_limits", tbl_indxs[1]) --найден 1 индекс, его и берём.
local lot=lot[sec]--lot[sec] ранее определена
return limit.currentbal/lot,limit.locked_buy/lot, limit.locked_sell/lot, limit.awg_position_price
else
return 0,0,0,0
end
end
Пользователь
Сообщений: Регистрация: 09.02.2015
QUIK software testing
24.07.2019 19:04:46
Цитата
Let_it_go написал: Увы, приходится объявлять переменную paper как глобальную, потому что sec внутри fn не видна.
Потому что у Вас функции get_position и fn объявлены на одном уровне, а переменная sec это локальная переменная функции get_position, сделайте вот так, и должно работать:
Код
function get_position (sec)
function fn(t)
if stop_search then return nil end --stop_search - это флаг. Изначально равен nil
if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then
stop_search=true
return true
else
return false
end
end
stop_search=nil --убиваем флаг, выставленный на прежних запусках функции.
tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)
if tbl_indxs then
limit = getItem("depo_limits", tbl_indxs[1]) --найден 1 индекс, его и берём.
local lot=lot[sec]--lot[sec] ранее определена
return limit.currentbal/lot,limit.locked_buy/lot, limit.locked_sell/lot, limit.awg_position_price
else
return 0,0,0,0
end
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'