Заметил, что отправка транзакций - выставление и снятие заявок - трудоёмкая операция. Торгую 50-ю акциями. Если у меня висит 50 заявок, то при их массовом одновременном снятии квик подвисает на несколько секунд. При быстром выставлении такого же числа заявок он тоже зависает. Поэтому вопросы. 1. Наблюдения верны? Отправка транзакций - ресурсоёмкая процедура? 2. Хочу отправлять транзакции из OnParam. Это плохая идея? С точки зрения логики работы программы это было бы очень удобно. Сейчас у меня отправка заявок идёт в функции main, там в бесконечном цикле перебираются одна за другой 50 акций на соблюдение условия выставления/снятия. Хочу перенести этот блок в OnParam. Заявок ставится много, они всё время перевыставляются. В день отправляется до 10 тысяч заявок, то есть с учётом снятия это 20 000 транзакций.
Let_it_go написал: Заметил, что отправка транзакций - выставление и снятие заявок - трудоёмкая операция. Торгую 50-ю акциями. Если у меня висит 50 заявок, то при их массовом одновременном снятии квик подвисает на несколько секунд. При быстром выставлении такого же числа заявок он тоже зависает. Поэтому вопросы. 1. Наблюдения верны? Отправка транзакций - ресурсоёмкая процедура? 2. Хочу отправлять транзакции из OnParam. Это плохая идея? С точки зрения логики работы программы это было бы очень удобно. Сейчас у меня отправка заявок идёт в функции main, там в бесконечном цикле перебираются одна за другой 50 акций на соблюдение условия выставления/снятия. Хочу перенести этот блок в OnParam. Заявок ставится много, они всё время перевыставляются. В день отправляется до 10 тысяч заявок, то есть с учётом снятия это 20 000 транзакций.
Добрый день.
1. Нет, отправка 50 транзакций не должна подвешивать рабочее место QUIK.
2. Если в OnParam будут выполняться долгие циклы по перебору 50 инструментов и проверять не выполнилось ли условие для отправки транзакции, то тут могут наблюдаться зависания.
функция для снятия всех заявок. в неё передаётся таблица с тикерами.
Код
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. Это очень часто вешает квик, приходится его убивать через окно с процессами.
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' https://arqatech.com/upload/Public/quik_lua.zip
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' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: посмотрел описание функции SearchItems. Почему вы её рекламируете по сравнению с Кодfor i=0,getNumberOf("orders")-1,1 doВ ней тоже задаётся список строчек с какой по какую искать. Если у меня за день 10 000 заявок, скрипт будет пробегать по всем. Разве не так?
Данная функция сделает это гораздо быстрее.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: 19,21,22 - это номера моих сделок с Башнефтью. С учётом сдвига всё верно. Но как получить все поля по этим сделкам?
Функция возвращает только индексы заявок, которые удовлетворяют условиям Вашей функции fn(), дальше нужные заявки нужно забрать функцией row=getItem("orders",i), где i, это индекс из таблицы, которую вернула функция SearchItems.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Так же стоит обратить внимание на то, что написано в документации по функции 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' https://arqatech.com/upload/Public/quik_lua.zip
Конечно же должно быть обращение к таблице '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' https://arqatech.com/upload/Public/quik_lua.zip
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?
Если пользовательская функция сравнения в search items возвращает nil, то поиск прерывается и текущий элемент в таблице результатов не попадает.
значит, необходимо перед вызовом searchitems создать флаг ин иницализировать его скажем в nil, при нахождении вашего единственного элемента таблицы изменить флаг на true.
при этом в самом начале пользовательский функции сравнения проверять этот флаг. Если он true, значит на пред итерации был найден ваш элемент и необходимо прервать поиск - вернуть nil из функции сравнения.
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' https://arqatech.com/upload/Public/quik_lua.zip
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
Вот рабочий вариант, внедрённый в робота. Увы, приходится объявлять переменную 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
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' https://arqatech.com/upload/Public/quik_lua.zip