Блог им. _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
1.5К | ★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

Читайте на SMART-LAB:
Фото
Снижение военной премии в нефти: что это меняет для доллара и G10
Во второй половине понедельника – начале вторники рынки активно пересматривают премию за худший сценарий на энергетическом рынке, что цепочкой...
Фото
12 марта Группа Ренессанс страхование опубликует МСФО за 2025 год
Напоминаем, что 12 марта 2026 года RENI опубликует МСФО Группы за 2025 год, а также проведет День инвестора, чтобы рассказать о ситуации на...
Фото
Как заработать на росте цен на удобрения
Дарья Фёдорова Конфликт на Ближнем Востоке и перекрытие Ормузского пролива вызвали ралли не только цен на нефть и газ, но также алюминий и...
Фото
Гендиректор Инарктики продал свои акции компании. Что это может значить?
Вечером в пятницу (6 марта ) вышел сущфакт о том, что Соснов Илья Геннадьевич, гендиректор Инарктики, продал свои акции компании. В нашем...

теги блога _sk_

....все тэги



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