Добрый день. При попытке "снять все заявки" (их у меня больше сотни) начало появляться сообщение: Количество транзакций превышает максимально разрешённое 50 в секунду. Кто автор этой ошибки 1. КВИК 2. Брокер 3. Биржа?
Почему оно возникает несколько раз при попытке "Снять все активные заявки" через контекстное меню (клик правой кнопкой по таблице заявок). На скриншоте видно, что команда сгенерировалась 6 раз.
Let_it_go написал: Почему оно возникает несколько раз при попытке "Снять все активные заявки" через контекстное меню (клик правой кнопкой по таблице заявок). На скриншоте видно, что команда сгенерировалась 6 раз.
Потому что на бирже нет такой транзакции "Снять все активные заявки", впрочем как и на сервере QUIK. Такая транзакция есть только в терминале, а терминал на сервер все равно отправляет столько транзакций на снятие сколько активных заявок. А раз на сервере настроено ограничение, то сервер не пускает на биржу все транзакции, а только часть.
Спасибо за ответ. Это стало появляться совсем недавно. Брокер может делать такое ограничение, а может не делать? Это настраивается для всех клиентов, или брокер может вводить персональные ограничения для отдельных клиентов если видит, что они флудят заявками?
Let_it_go написал: Брокер может делать такое ограничение, а может не делать?
Да верно. Это опция, которая настраивается по усмотрению брокера, а НЕ ограничение сервера.
Цитата
Let_it_go написал: Это настраивается для всех клиентов, или брокер может вводить персональные ограничения для отдельных клиентов если видит, что они флудят заявками?
Брокер может указать как глобальную настройку так и индивидуальную, т.е. возможны оба варианта.
Ещё вопрос. У меня выставлено 60 заявок. У брокера ограничение 50 заявок. Я использую для массового снятия заявок функцию на Луа
Код
function killAllOrders(table_mask)
-- данная функция отправит транзакции на отмену АКТИВНЫХ заявок соответствующим фильтру указанному как входящий параметр table_mask
-- список всех возможных параметров : ACCOUNT,CLASSCODE,SECCODE,OPERATION,CLIENT_CODE,COMMENT
-- если вызвать функцию с параметром nil - снимутся ВСЕ активные заявки
local i,key,val,result_num=0,0,0,0
local tokill=true
local row={}
local result_str=""
for i=0,getNumberOf("orders")-1,1 do
row=getItem("orders",i)
tokill=false
if orderflags2table(row.flags).active then
tokill=true
if table_mask~=nil then
for key,val in pairs(table_mask) do
if string_lower(key)=='comment' then
if string_find(string_lower(row.brokerref),string_lower(val))==nil then tokill=false break end
else
if row[string_lower(key)]~=val then tokill=false break end
end
end
end
end
if tokill then
res,ms=killOrder(tostring(row.order_num),row[securityfiledname],row.class_code)
result_num=result_num+1
if res then
result_str=result_str..row.order_num..","
else
result_str=result_str.."!"..row.order_num..","
end
end
end
return true,"QL.killAllOrders(): Sended "..result_num.." transactions. order_nums:"..result_str
end
Вопрос. Эта функция снимет 50 заявок? Или она не снимет ни одной заявки, ведь сервер увидит что его мучают и не снимет ничего?
Заведите себе объект, который вычисляет количество отправленных заявок в последнюю секунду (реализация через очередь). Если количество заявок больше, скажем, 45, не отправляйте новые. Понятно, что ограничение неприятное и неудобное, но спамить сервер тоже не правильно.
_sk_ написал: Заведите себе объект, который вычисляет количество отправленных заявок в последнюю секунду (реализация через очередь). Если количество заявок больше, скажем, 45, не отправляйте новые. Понятно, что ограничение неприятное и неудобное, но спамить сервер тоже не правильно.
Извините, можете привести пример, как написать это эффективно?
Например достался код коннектора у которого, повезло, всего одна точка sendTransaction:
Код
-- отправка траназакции квику
function router:processTransaction(transaction, tJson)
trace("info", "NEW TRANSACTION: " .. tJson)
local ok = sendTransaction(transaction)
if ok ~= "" then
-- код, чтобы обработать ошибку
end
end
Как сделать, чтобы проходило не более 50ти в секунду, но при этом не тупо делать sleep(1000 / 50) ?
--
-- Подсчёт количества событий, произошедших за последние несколько секунд.
-- При регистрации очередного события в массив событий добавляется новый элемент с указанием текущего момента времени.
-- При подсчёте числа событий учитываются только те события, которые произошли не более чем указанное количество
-- секунд назад, а остальные события удаляются из массива.
--
local EventsCounter = {}
local function systime()
local d = os.sysdate()
local mcs = d.mcs or 0
d.ms = nil
d.mcs = nil
return os.time(d) + mcs * 0.000001
end
--- Конструктор.
-- @param self объект
-- @param interval количество секунд, на протяжении которых отслеживаются события
local function new(self, interval)
local object = {
interval = interval,
id = 0,
events = {},
}
setmetatable(object, self)
self.__index = self
return object
end
EventsCounter.new = new
--- Зарегистрировать событие.
-- @param self объект
local function registerEvent(self)
self.id = self.id + 1
self.events[self.id] = systime()
end
EventsCounter.registerEvent = registerEvent
--- Узнать, сколько событий произошло за последние несколько секунд.
-- @param self объект
-- @return количество событий, произошедших за последние несколько секунд
local function getCount(self)
local now = systime()
local count = 0
local remove = {}
for id, time in pairs(self.events) do
if now - time <= self.interval then
count = count + 1
else
remove[id] = true
end
end
for id, _ in pairs(remove) do
self.events[id] = nil
end
return count
end
EventsCounter.getCount = getCount
return EventsCounter
Использовать примерно так:
Код
local EventsCounter = require("EventsCounter")
local eventsCounter = EventsCounter:new(1)
-- Перед отправкой транзакции проверяем количество событий и притормаживаем, если надо
while eventsCounter:getCount() > 40 do
sleep(10)
end
-- Ваш код, который отсылает заявку
sendTransaction()
--
eventsCounter:registerEvent()
Недостатком является ожидание, пока предыдущие события уйдут в прошлое. А можно было бы что-то полезное делать. Но для такой реализации уже более сложный код надо писать.
_sk_, код в целом работает, но иногда сбоит. Причем если смотреть по таблице транзакций (время и микросекунды), то иногда не вижу чтобы в 1 секунду были ровно 50 транзакций (бывало 23), а ошибка есть. Или что странно там по 5-10 транзакций пишутся с одинаковой секундой и микросекундой (1/1000000), но это вообще не реально выглядит, по логам скрипта время различается, хотя бы на несколько миллисекунд.
Возможно Sergey Gorokhov - сможете объяснить как хотят транзакции между квиком и сервером и как замеряется этот интервал - 50 транзакций в секунду?
Вполне может еще сетевой буфер влиять: несколько транзакций по факту накапливаются на вашей стороне в один сетевой пакет, после чего весь макет одновременно уезжает серверу, где они все сразу обрабатывает Это можно объяснить как меньшее кол-во заявок в секунду по вашим замерам, так и одновременность их обработки.
Попробуйте связаться с брокером и уточнить у него по чем для вас встанет для вас увеличение допустимого количества транзакций в секунду. Вдруг это будет обозримая цифра. Ну либо придётся менять алгоритм, избавляюсь от простой идеи одновременного снятия буквально всех заявок. Наверняка ведь вашу торговую идею можно реализовать иначе, красивее и без внезапного снятия буквально всех выставленных заявок.
Михаил Е написал: Возможно Sergey Gorokhov - сможете объяснить как хотят транзакции между квиком и сервером
Вопрос слишком общий для того чтобы можно было дать на него предметный ответ. Легко можем ответить что они ходят по TCP протоколу, и ответ будет вписываться в вопрос. Однако, что-то подсказывает что вы не это хотите услышать, тогда что?
Цитата
Михаил Е написал: и как замеряется этот интервал - 50 транзакций в секунду?
Интервал замеряется сервером QUIK по времени получения транзакций. Ключевая особенность как раз в том что время получения транзакции это далеко не то же самое что время ее отправки до сервера. И да swerg, прав, проблема может возникать при буферизации. Почтой ответили более подробно.
swerg написал: Вполне может еще сетевой буфер влиять: несколько транзакций по факту накапливаются на вашей стороне в один сетевой пакет, после чего весь макет одновременно уезжает серверу, где они все сразу обрабатывает Это можно объяснить как меньшее кол-во заявок в секунду по вашим замерам, так и одновременность их обработки.
Попробуйте связаться с брокером и уточнить у него по чем для вас встанет для вас увеличение допустимого количества транзакций в секунду. Вдруг это будет обозримая цифра. Ну либо придётся менять алгоритм, избавляюсь от простой идеи одновременного снятия буквально всех заявок. Наверняка ведь вашу торговую идею можно реализовать иначе, красивее и без внезапного снятия буквально всех выставленных заявок.
:) Сначала там вообще была оплата за каждую транзакцию выше 20 в секунду, я подумал это какая-то дыра, даже если снимать все заявки в квике, когда заявок несколько десятков. Я предложил брокеру например платить фикс сумму в месяц, на что они просто сделали до 50 транзакций в секунду, дальше будет ошибка.
swerg написал: Вполне может еще сетевой буфер влиять: несколько транзакций по факту накапливаются на вашей стороне в один сетевой пакет, после чего весь макет одновременно уезжает серверу, где они все сразу обрабатывает Это можно объяснить как меньшее кол-во заявок в секунду по вашим замерам, так и одновременность их обработки.
Попробуйте связаться с брокером и уточнить у него по чем для вас встанет для вас увеличение допустимого количества транзакций в секунду. Вдруг это будет обозримая цифра. Ну либо придётся менять алгоритм, избавляюсь от простой идеи одновременного снятия буквально всех заявок. Наверняка ведь вашу торговую идею можно реализовать иначе, красивее и без внезапного снятия буквально всех выставленных заявок.
:) Сначала там вообще была оплата за каждую транзакцию выше 20 в секунду, я подумал это какая-то дыра, даже если снимать все заявки в квике, когда заявок несколько десятков. Я предложил брокеру например платить фикс сумму в месяц, на что они просто сделали до 50 транзакций в секунду, дальше будет ошибка.
Дыра - в смысле практически неконтролируемо получаю доп комиссию от брокера, и я не понимал как уследить, где было больше 20 тр. в секунду...
Кажется, подсчет транзакций можно сделать следующим образом - запоминаем транзакцию когда её отправляем - когда получили ответ от сервера, начинаем считать 1 секунду - можно поставить лимит времени, когда мы сами забудем транзакцию например, если соединение разорвалось и сервер не ответил
Код
--
-- Подсчёт количества событий, произошедших за последние несколько секунд.
-- При регистрации очередного события в массив событий добавляется новый элемент с указанием текущего момента времени.
-- При подсчёте числа событий учитываются только те события, которые произошли не более чем указанное количество
-- секунд назад, а остальные события удаляются из массива.
--
local EventsCounter = {}
local function systime()
local d = os.sysdate()
local mcs = d.mcs or 0
d.ms = nil
d.mcs = nil
return os.time(d) + mcs * 0.000001
end
--- Конструктор.
-- @param self объект
-- @param interval количество секунд, на протяжении которых отслеживаются события
-- @param bump максимальное количество секунд, на протяжении которого событие занимает очередь без регистрации
local function new(self, interval, bump)
local object = {
interval = interval,
bump = bump,
events = {},
}
setmetatable(object, self)
self.__index = self
return object
end
EventsCounter.new = new
--- Зарегистрировать событие.
-- @param self объект
local function registerEvent(self, trans_id)
self.events[trans_id] = systime()
end
EventsCounter.registerEvent = registerEvent
--- Запомнить событие до его регистрации
-- @param self объект
local function preRegisterEvent(self, trans_id)
self.events[trans_id] = systime() + self.bump
end
EventsCounter.preRegisterEvent = preRegisterEvent
--- Узнать, сколько событий произошло за последние несколько секунд.
-- @param self объект
-- @return количество событий, произошедших за последние несколько секунд
local function getCount(self)
local now = systime()
local count = 0
local remove = {}
for id, time in pairs(self.events) do
if now - time <= self.interval then
count = count + 1
else
remove[id] = true
end
end
for id, _ in pairs(remove) do
self.events[id] = nil
end
return count
end
EventsCounter.getCount = getCount
return EventsCounter
Отправка транзакции
Код
local EventsCounter = require("EventsCounter")
local eventsCounter = EventsCounter:new(1.0, 30.0)
function myTransactionSend(transaction)
-- Перед отправкой транзакции проверяем количество событий и притормаживаем, если надо
while eventsCounter:getCount() >= 50 do
sleep(10)
end
-- Ваш код, который отсылает заявку
sendTransaction()
eventsCounter:preRegisterEvent(tonumber(transaction.TRANS_ID))
end
Получение ответа на транзакцию:
Код
-- ответ на отправку транзакции
function OnTransReply(trans_reply)
eventsCounter:registerEvent(transReply.trans_id)
end