Блог им. _sk_

Ограничитель количества транзакций на чистом QLua

    • 21 декабря 2022, 13:37
    • |
    • _sk_
  • Еще
При торговле с помощью роботов в терминале QUIK рано или поздно встаёт вопрос об ограничении количества отправляемых в секунду транзакций, чтобы не начинались ошибки вида: «Превышен лимит отправки транзакций для данного логина».

Простой способ, когда вводятся ограничения на уровне каждого торгового робота, приводит к ситуациям, когда заявки отправляются медленно из-за этого ограничения, а свободная пропускная способность ещё есть. Для введения общего ограничения для всех роботов сразу нужно использовать какой-то общий ресурс. В качестве такого ресурса может выступать база данных, собственная dll или что-то ещё. Но чистый QLua не позволяет использовать базу данных без каких-либо внешних библиотек, а dll не всякий умеет писать. К счастью, существует реализация ограничителя на базе файловой системы с помощью чистого QLua.

Создаётся некая папка D:\throttle\, где работает ограничитель интенсивности. Во время работы QLua-скрипты формируют в этой папке столько файлов, сколько транзакций в секунду разрешено, например 10. При каждой попытке послать транзакцию скрипты, грубо говоря, конкурируют за эти файлы. Если ресурса хватило, то транзакция отправляется, если нет, то скрипт ждёт 10 мс и повторяет попытку заново.

Создание ограничителя, предоставляемого модулем Throttle.lua, производится командами

local Throttle = require("Throttle") -- указать путь к файлу модуля
local throttle = Throttle:new("D:/throttle/", 10)

Цикл проверки/ожидания ресурса и последующая отправка транзакции выглядит примерно так:
while not throttle:isAllowed() do
  sleep(10)
end
sendTransaction(...)
Приятным свойством данного подхода является то, что все торговые скрипты, работающие с общей папкой, будут иметь общее ограничение, вне зависимости от числа применяемых терминалов QUIK. В принципе, папку D:\throttle\ можно даже разместить на сетевом диске, тогда терминалы QUIK с роботами с разных компьютеров будут иметь общее ограничение по количеству транзакций.

Наконец, вот код модуля Throttle.lua:
---
--- Ограничитель интенсивности на базе файловой системы.
---
--- В папке folder создаются служебные файлы, содержащие штампы с идентификатором объекта и текущим временем.
--- Функция isAllowed() выдаёт разрешение или запрещает использование ресурса.
--- Количество используемых служебных файлов capacity обеспечивает ограничение интенсивности уровнем не более
--- чем capacity разрешений в секунду.
---
--- Алгоритм реализации использует датчик случайных чисел и не гарантирует, что на практике уровень интенсивности
--- будет в точности равен capacity разрешений в секунду при высоких нагрузках.
---

local M = {}

--- Конструктор.
-- @param self объект
-- @param folder имя папки со служебными файлами; оканчивается символом '/'
-- @param capacity количество используемых служебных файлов
local function new(self, folder, capacity)
    os.execute("mkdir \"" .. folder .. "\"")
    local object = {
        folder = folder,
        capacity = capacity,
        id = math.random(1000000, 9999999)
    }
    setmetatable(object, self)
    self.__index = self
    return object
end

M.new = new

local function getFilename(self)
    return self.folder .. string.format("%03d.dat", math.random(1, self.capacity))
end

local function getStamp(self)
    return self.id .. ":" .. os.time()
end

local function getIdTime(stamp)
    if type(stamp) ~= "string" then
        return nil, nil
    end
    local i = string.find(stamp, ":", 1, true)
    if i then
        return tonumber(string.sub(stamp, 1, i - 1)), tonumber(string.sub(stamp, i + 1))
    else
        return nil, nil
    end
end

--- Узнать, разрешено ли использование ресурса.
-- @param self объект
-- @return true/false
local function isAllowed(self)
    local filename = getFilename(self)
    local file = io.open(filename, "r")
    if file then
        local stamp = file:read()
        file:close()
        local id, time = getIdTime(stamp)
        if id == nil or time == nil then
            return false
        end
        if time == os.time() then
            return false
        end
    end
    file = io.open(filename, "w+")
    if file then
        local stamp1 = getStamp(self)
        file:write(stamp1)
        file:close()
        file = io.open(filename, "r")
        if file then
            local stamp2 = file:read()
            file:close()
            return stamp1 == stamp2
        else
            return false
        end
    else
        return false
    end
end

M.isAllowed = isAllowed

return M

Успехов в торговле!
  • обсудить на форуме:
  • Quik Lua
★4
16 комментариев
привет.
Lua реально выучить новичку самостоятельно? Просто тупо документацию из квика по языку читать?
avatar
Артур, я книгу автора языка читал, на английском языке. Но на русском тоже есть вариант: eligovision.ru/media/upload/lua.pdf
avatar
Артур, вполне реально. На ютубе есть ролики для обычного lua (понимание как код пишется), а для qlua есть справка внутри Quik.
avatar
мьютекс на базе файловой системы. прикольно )
avatar
Андрей К, так и есть.
avatar
_sk_, Не понятно только зачем насиловать диск для решения такой задачи.
avatar
nicknh, поэтому я RAM-диск сделал.
avatar
Какой лимит заявок у КВИКа?
avatar
Егор NiKO, у самого квика его может и нет, у брокера может быть своя настройка, а у биржи 30 транзакций на один логин на срочном рынке.
avatar
Вы че, HFT занимаетесь, что вам транзакций не хватает? )
avatar
3Qu, скриптов, инструментов и клиентов много. Скажем, 5 скриптов * 5 инструментов * 5 клиентов = 125. Если в одну секунду посылать, будет превышение.
avatar
«Превышен лимит отправки транзакций для данного логина»

 

А это на чьей стороне ограничение? И оно чем-то грозит, кроме того, что вылезающие за лимит в моменте транзакции отклонятся?

avatar
Replikant_mih, ограничение брокера. Вот, например, что делает ВТБ:
www.banki.ru/services/responses/bank/response/10461425/
Транзакции будут отклоняться. Чтобы не было ошибок подобного рода и нужен ограничитель.
avatar
_sk_, Ага, понял, спасибо!
avatar
Мда, чего только не приходится изобретать народу.
Мрак какой-то.
Приоритетов итп похоже нету никаких, кто первый встал, того и тапки.
Стало даже немножко страшно за тех, кто в таких инфраструктура бабки крутит…
avatar
 Интересное решение на базе записи на диск Действительно чего только не придумаешь если в руках только палка и верёвка
avatar

теги блога _sk_

....все тэги



UPDONW
Новый дизайн