Ограничение 50 транзакций в секунду

Страницы: 1
RSS
Ограничение 50 транзакций в секунду
 
Добрый день.
При попытке "снять все заявки" (их у меня больше сотни) начало появляться сообщение:
Количество транзакций превышает максимально разрешённое 50 в секунду.
Кто автор этой ошибки
1. КВИК
2. Брокер
3. Биржа?

Почему оно возникает несколько раз при попытке "Снять все активные заявки" через контекстное меню (клик правой кнопкой по таблице заявок). На скриншоте видно, что команда сгенерировалась 6 раз.
 
Цитата
Let_it_go написал:
Кто автор этой ошибки
Ошибку вернул сервер QUIK на стороне брокера.

Цитата
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 заявок? Или она не снимет ни одной заявки, ведь сервер увидит что его мучают и не снимет ничего?
 
Let_it_go,

Сервер снимет 50 заявок, остальные 10 останутся активными, а на транзакцию придет ошибка "Количество транзакций превышает..."
 
Заведите себе объект, который вычисляет количество отправленных заявок в последнюю секунду (реализация через очередь). Если количество заявок больше, скажем, 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_, спасибо большое за ваш пример!
для себя опытным путём определил, что
Код
while eventsCounter:getCount() > 45 do
    sleep(10)
end
пролазит в ограничение 50 транзакций от брокера,
не вызывая ошибок сервера квика.
 
_sk_, код в целом работает, но иногда сбоит.
Причем если смотреть по таблице транзакций (время и микросекунды),
то иногда не вижу чтобы в 1 секунду были ровно 50 транзакций (бывало 23),
а ошибка есть.
Или что странно там по 5-10 транзакций пишутся с одинаковой секундой и микросекундой (1/1000000),
но это вообще не реально выглядит, по логам скрипта время различается,
хотя бы на несколько миллисекунд.

Возможно Sergey Gorokhov - сможете объяснить как хотят транзакции между квиком и сервером
и как замеряется этот интервал - 50 транзакций в секунду?
 
Вполне может еще сетевой буфер влиять: несколько транзакций по факту накапливаются на вашей стороне в один сетевой пакет, после чего весь макет одновременно уезжает серверу, где они все сразу обрабатывает
Это можно объяснить как меньшее кол-во заявок в секунду по вашим замерам, так и одновременность их обработки.

Попробуйте связаться с брокером и уточнить у него по чем для вас встанет для вас увеличение допустимого количества транзакций в секунду. Вдруг это будет обозримая цифра.
Ну либо придётся менять алгоритм, избавляюсь от простой идеи одновременного снятия буквально всех заявок. Наверняка ведь вашу торговую идею можно реализовать иначе, красивее и без внезапного снятия буквально всех выставленных заявок.
 
Цитата
swerg написал:
Это можно объяснить как меньшее кол-во заявок в секунду по вашим замерам, так и одновременность их обработки.
Уточнение:
Этим можно объяснить.... и далее по тексту.
 
Цитата
Михаил Е написал:
Возможно 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
 
На QUIK 8.6.0.97 данный код работает без превышения транзакций
уже несколько дней
Страницы: 1
Читают тему
Наверх