Скрипты QUIK — документация SDK
Скрипты пишутся на Lua 5.4 поверх нашего SDK и исполняются в вашем терминале QUIK. Вы пишете только логику через готовые функции — подключение, ACCOUNT и доступ к QUIK мы берём на себя. Текущая версия — мониторинг (только чтение): данные, события, вывод. Торговых функций пока нет.
Как это работает
- В ЛК → Скрипты создаёте скрипт, привязываете к подключению QUIK, пишете код и жмёте Сохранить.
- Запустить — код уходит в ваш шлюзовой скрипт QUIK, компилируется и начинает работать (вызываются ваши обработчики). Остановить — выгружает.
- Вывод
alert(...)появляется в журнале под редактором. Статус (работает / ошибка / остановлен) виден там же. - Если перезапустить QUIK — запущенные скрипты поднимутся автоматически при переподключении шлюза.
Требование: шлюзовой скрипт подключения должен быть запущен в QUIK (Lua 5.4, рядом обе dll).
Ограничения и песочница
- Пишите через обработчики (
on_timerи т.п.), а не свой бесконечный цикл: все скрипты работают в одном потоке шлюза, иwhile true do … endего подвесит. - Доступен только SDK и безопасная часть стандартной Lua. Недоступны сырой QUIK API (
sendTransaction,getItem…), файлы (io), запуск процессов (os.execute). - Только чтение — заявки из скрипта пока выставлять нельзя (появится в следующей версии, под торговым PIN и лимитами).
- Ошибка компиляции или выполнения показывается статусом «ошибка» с текстом.
Данные
Последняя цена инструмента sec (тикер). Класс определяется автоматически; можно указать явно ("TQBR", "SPBFUT"…). Вернёт 0, если цены ещё нет.
local p = price("GAZP")
log("Газпром: " .. p)Открытые позиции по всем счетам. Каждый элемент:
{ symbol="SBER", name="Сбербанк", classcode="TQBR",
qty=10, avg_price=286.5, last=287.1, kind="stock", account="L01-..." }
-- account — торговый счёт (trdacc); у фьючерсов дополнительно: varmargin, kind="futures"for _, p in ipairs(positions()) do log(p.symbol .. ": " .. p.qty .. " шт, ср.цена " .. p.avg_price) end
Деньги по счетам. kind — "stock" или "futures" (без аргумента — все). Форма зависит от рынка:
-- фондовый: { kind="stock", currency="SUR", balance=..., locked=..., account="..." }
-- срочный: { kind="futures", currency="SUR", free=..., go=..., varmargin=..., account="..." }
-- free — свободно, go — ГО, всего = free + go; account — торговый счёт (trdacc)for _, m in ipairs(money("futures")) do
if m.free < 5000 then alert("Мало свободных: " .. m.free, "warn") end
endАктивные (не исполненные, не снятые) заявки. Каждый элемент:
{ symbol="SBER", classcode="TQBR", side="B", -- "B" покупка, "S" продажа
price=280, qty=10, balance=10, order_num="123456789" }События
Регистрируются один раз (обычно в начале скрипта). Обработчик вызывается при наступлении события.
Вызывать fn() каждые ms миллисекунд.
on_timer(10000, function()
log("тик каждые 10 секунд")
end)Каждые ms мс вызывать fn(price) с последней ценой инструмента.
on_price("SBER", 5000, function(p)
if p > 300 then alert("SBER выше 300: " .. p) end
end)fn(order) при любом изменении заявки. order = { symbol, classcode, side, price, qty, balance, active } (active — активна ли ещё).
on_order(function(o)
if not o.active then log("заявка закрыта: " .. o.symbol) end
end)fn(trade) при своей сделке. trade = { symbol, price, qty, is_buy, classcode } (is_buy — покупка ли).
on_trade(function(t)
alert("Сделка: " .. t.symbol .. " " .. t.qty .. " @ " .. t.price)
end)Вывод
Сообщение в журнал личного кабинета (видно в вебе). level — "info" (по умолч.), "warn", "error".
alert("Внимание: просадка", "warn")Сообщение в окно отладки самого QUIK (в вебе не видно). Удобно для локальной отладки.
Константа — латинское имя подключения, к которому привязан скрипт.
Хранилища позиций
Хранилище — именованный журнал позиций (ЛК → Хранилища), независимый от подключения. Робот записывает в него сделки, а система ведёт стек открытий по каждому инструменту (по каким ценам открыли), закрытия и итоговый PnL. Хранилище нужно заранее создать в ЛК — его латинское имя робот и указывает в вызове.
Записать сделку в хранилище name. Поля таблицы t:
sec— тикер инструмента (обязательно).op—"B"покупка /"S"продажа (илиbuy=true/false).qty— объём в лотах, > 0 (обязательно).price— цена сделки (нужна для расчёта PnL при закрытии).class— класс инструмента (необязательно; определится сам).price_step,step_price— шаг цены и его стоимость (для PnL фьючерсов; подтянутся сами, если не заданы).writeoff—trueдля списания (см. ниже).
-- открыть/долить: копит стек открытий
store.fill("scalper", { sec="GAZP", op="B", price=145.20, qty=10 })
-- закрыть (конверсия): считает PnL и пишет в журнал закрытий
store.fill("scalper", { sec="GAZP", op="S", price=146.00, qty=10 })- Конверсия (по умолчанию) — закрытие с расчётом прибыли; запись попадает в журнал закрытий и в итоговый PnL.
- Списание (
writeoff=true) — просто снимает лоты без расчёта PnL. Нужно для ручного переноса позиции (например, с фьючерса на спот), когда прибыль считать не надо.
Открытие (набор позиции) — всегда конверсия; на него writeoff не влияет.
-- списать 5 лотов без расчёта прибыли
store.fill("carry", { sec="SiH6", op="S", qty=5, writeoff=true })on_trade(function(t)
store.fill("scalper", { sec=t.symbol, buy=t.is_buy,
price=t.price, qty=t.qty })
end)Модули
Общий код можно вынести в модуль (ЛК → Модули) и подключать в скриптах через require("имя"). Модуль — это Lua-файл, который возвращает таблицу функций. Модули общие для всех ваших скриптов и не привязаны к подключению. Имя латинское — им и подключается модуль.
Загружает модуль name и возвращает то, что модуль вернул (обычно таблицу). Модулю доступен тот же SDK (price, positions, money, store…). Результат кэшируется на время работы скрипта; модуль может require другие модули (циклы запрещены).
risk:local M = {}
function M.low_free(limit)
for _, m in ipairs(money("futures")) do
if (m.free or 0) < limit then return true end
end
return false
end
return Mlocal risk = require("risk")
on_timer(15000, function()
if risk.low_free(5000) then
alert("Мало свободных средств на срочном!", "warn")
end
end) Модуль можно опубликовать — тогда он доступен другим пользователям в каталоге и подключается по глобальному имени require("префикс.имя").
- Публиковать может пользователь с ролью автор (выдаёт администратор) и заданным префиксом в профиле (3–10 латинских букв/цифр, уникален).
- Свои приватные модули подключаются по короткому имени (
require("risk")), опубликованные чужие — по полному (require("acme.risk")). - Внутри опубликованного модуля другие опубликованные модули тоже подключайте по полному имени (
prefix.name).
local risk = require("acme.risk") -- чужой опубликованный модуль
local util = require("util") -- свой приватный модульИзменили модуль — перезапустите скрипты, которые его подключают: код модулей уходит в шлюз в момент запуска скрипта.
Доступная часть Lua
Стандартные модули и функции, доступные в скрипте:
math, string, table, pairs, ipairs, next, select, tostring, tonumber, type, error, assert, pcall, os.time, os.clock, os.date
Примеры
on_timer(10000, function()
alert("GAZP: " .. price("GAZP"))
end)local level, fired = 300, false
on_price("SBER", 3000, function(p)
if p >= level and not fired then
alert("SBER пробил " .. level .. ": " .. p, "warn")
fired = true
elseif p < level then
fired = false
end
end)on_timer(15000, function()
for _, m in ipairs(money("futures")) do
local total = (m.free or 0) + (m.go or 0)
if total > 0 and (m.free / total) < 0.2 then
alert("Свободно меньше 20% ГО: " .. m.free, "warn")
end
end
end)on_timer(60000, function()
local n = 0
for _, p in ipairs(positions()) do n = n + 1 end
alert("Позиций в портфеле: " .. n)
end)