flash написал: Добрый день, уважаемые разработчики. Обнаружил баг при передаче неполного стакана по DDE. Версия QUIK 13.1.1.15, брокер БКС.
В QUIK стакан выглядит так:
При передаче этого стакана по DDE приходит следующее:
Код
Rows x Cols: 9x3
CellType: String. Value = Покупка | CellType: String. Value = Цена | CellType: String. Value = Продажа
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: String. Value = (empty string) | CellType: String. Value = (empty string)
CellType: String. Value = (empty string) | CellType: Double. Value = 10300 | CellType: Double. Value = 1
Тут видно что в стакане на скрине всего 8 заполненных строк + одна строка заголовка, остальные строки пустые. При передаче по DDE приходит 8 + 1 строка, т.е. количество строк правильное, и видимо было намерение передать именно 8 заполненных строк, не передавая пустые. Но передаются все строки с начала стакана подряд, включая пустые, заполненная строка в итоге передана только одна, остальные данные, таким образом, не передаются.
У вас где-то ошибка. вот результат вывода стакана по DDE
Описание полей в методе on_trans_reply
Пользователь
Сообщений: Регистрация: 30.01.2015
30.10.2026 18:21:42
Цитата
VPM написал: Дествительно не подумал и повелся на маркетинговые мифы о "Си-скоростях". Любое значение Lua — это сложная структура TValue, и побитовые операторы в Lua 5.4 действительно не являются прямыми ассемблерными инструкциями ЦП.
, Спасибо за замечание и системное погружение в исходный Си-код языка. Это позволяет строить более осознанную архитектуру, понимая такт процессора.
Вывод Lua = Таблица, Lua ~= Ассемблер.
Несмотря на то, что на уровне исполнения это вызов функций ВМ, оператор & в Lua 5.4.1 работает быстрее, чем вызов старой внешней библиотеки bit.band(flags, 0x4). Следовательно вывод что встроенный оператор & всё же предпочтительнее для Квика сохраняется и это главное!
Согласен.
Описание полей в методе on_trans_reply
Пользователь
Сообщений: Регистрация: 30.01.2015
30.10.2026 09:42:02
Цитата
VPM написал: Поскольку поддержка отмалчивается, проведу разбор самостоятельно, для себя и таких как я (хотя и слабо разбираюсь в этом), а что делать?
1. Опечатка в тексте руководства ARQA Technologies очевидна, авторы справки перепутали номера битов и шестнадцатеричные (HEX) маски. Авторы опечатались в HEX-записи. Они хотели написать бит 20 (маска 0x100000) и бит 21 (маска 0x200000). Но почему то написали 0x21 и 0x22? Видимо механически скопировали номера битов, забыв перевести их в степени двойки и ошибочно записав номера битов 20 и 21 как 0x20 / 0x21, а затем сдвинули индексы? Доверять HEX-значениям 0x21 и 0x22 из этой справки нельзя — они полностью неверны.
2. Ловушка Истины или почему 0 в Lua — это true? Это главная концептуальная ловушка для программистов, переходящих на Lua с языков Си, C++ или Python. В отличие от Си/Python, где 0 — это false, любое другое число — это true. В Lua (всех версий), логическим ложным значением (false) признаются исключительно два ключевых слова: false и nil. Всё остальное, включая число 0, пустую строку "" и пустую таблицу {}, интерпретатором Lua всегда признается истиной (true)!
Так как в терминал QUIK v11+ при работе на чистом Lua 5.4.1, встроенная библиотека bit (которая была внешней .dll в старых версиях) является устаревшей. Появилась возможность использовать родные поразрядные Си-операторы Lua 5.4.1, которые работают на уровне процессора и не тратят время на вызовы функций. Собствено на этом можно и закончить. Хотя про это много уже писалось повторюсь. Вот золотой стандарт проверки флагов, который гарантирует отсутствие ложных срабатываний (как памятка):
Вариант 1. Проверка через родной оператор Lua 5.4.1 (&) — Рекомендуемый HFT-выбор. Оператор & (побитовое И) возвращает значение маски (например, 4) или 0. Проверяем строго через ~= 0: -- Проверяем Бит №2 заявки/сделки (маска 2^2 = 4, то есть 0x4) -- На Мосбирже: flags & 0x4 ~= 0 означает "Сделка на ПРОДАЖУ" local is_sell = (flags & 0x4) ~= 0 if is_sell then -- Блок выполнится строго если бит присутствует (результат операции равен 4) end
Вариант 2. Проверка через встроенную функцию bit.test в старых скриптах. Если используете функцию bit.test, она сама под капотом делает сравнение и возвращает чистый булев тип (true или false). Здесь оператор ~= 0 не нужен: -- В функцию передается не маска, а чистый НОМЕР БИТА (начиная с 0) local is_sell = bit.test(flags, 2) -- Возвращает true или false if is_sell then -- Код безопасен, так как is_sell — это честный boolean end
поясню почему в луа все значения true кроме nil, Это связано с тем что все данные в луа содержат в неявном виде свой тип Поэтому если значение типа не равно нулю то это true а если равно нулю то это false У nil значение типа равно нулю. -------------------------------------- Утверждение : "Появилась возможность использовать родные поразрядные Си-операторы Lua 5.4.1, которые работают на уровне процессора и не тратят время на вызовы функций." ошибочно. Так как значения переменных это не значения СИ а структуры, то для применения бинарных операций вызываются функции в соответствии с сохраненным типом переменных. Поэтому бинарные логические и сдвиговые операции на символьном уровне записываются как в СИ но на уровне исполнения это вызов функций. ----------------------------------
Блок перерасчёта данных индикатора, Актуально для арбитражных индикаторов и аналогичных, использующих несколько инструментов в своём расчёте.
Пользователь
Сообщений: Регистрация: 30.01.2015
17.10.2026 07:10:27
Для наглядности покажите на графиках без и с пересчетом иначе непонятно зачем это городить.
QUIK и жор памяти, Проблема с памятью скриптов Qlua
написал: for iord=lastact,N do local tab=getItem('orders',iord); -- получаем заявку i if tab~=nil then if tab.account==acc then if bit.band(tab.flags,0x1)==0x1 then ... end; end; end; end;
Если сначала найти индексы всех интересующих заявок, и в цикле извлекать только их, то памяти может потребоваться меньше.
Код
local function Fnd (f,a)
return f & 1 = = 1 and a = = acc
end
local aOrd = SearchItems ( "orders" , lastact, N, Fnd, "flags, account" ) or {}
for _, iord in ipairs(aOrd) do
local tab = getItem ( "orders" ,iord)
--...
end
в начале активные заявки ищутся один раз что не критично для дальнейших расчетов Но если потом выставляются новые заявки то вопрос именно в том как они находятся Если их искать по таблице заявок QUIK то все будет ровно так как написал автор темы ------------------------ А чтобы так не было надо делать свою таблицу активных заявок Сначала ее заполняем по таблице заявок QUIK а потом работаем с ней по колбеку заявок
QUIK и жор памяти, Проблема с памятью скриптов Qlua
for iord=lastact,N do local tab=getItem('orders',iord); -- получаем заявку i if tab~=nil then if tab.account==acc then if bit.band(tab.flags,0x1)==0x1 then ... end; end; end; end;
Перебирал большое число заявок (все) и засорял память, хоть и срабатывал сравнительно редко. До сих пор не понимаю как в qlua сделать локальную переменную массива (таблицы), чтобы при её обработке в цикле не возникало жора памяти?!
в версии 5.3 и 5.4 есть логические операции вместо этого: if bit.band(tab.flags,0x1)==0x1 можно писать это: if tab.flags&1==1 --------------------------------------- измените алгоритм программы. Создайте массив активных заявок. И не надо будет много перебирать
QUIK и жор памяти, Проблема с памятью скриптов Qlua
Пользователь
Сообщений: Регистрация: 30.01.2015
08.10.2026 13:00:13
Предположу ,что проблема в разном объеме в VMLUA свободной памяти. Поэтому сборщик мусора работает по-разному.
QUIK и жор памяти, Проблема с памятью скриптов Qlua
Посмотрите сколько памяти занимает каждый вариант QUIK
Тот который не перегружает занимает 1200 мБ, другой, который перегружает 1870 мБ.
Пока что создаётся впечатление, что это работа OnTrnsReply(reply), так как перегрузка памяти идёт именно в моменты активной торговли другими системами.
Соответственно встаёт вопрос - как с этим бороться? Может быть стоит прописать reply= { } чтобы чистить память сразу из Коллбэка? Потому что никакой сложной обработки у меня нет, фактически все завершается первой строчкой : if reply.account~=Account then return; end; Да и в остальном коде только поиски по тексту ошибки. Мегабайтам там уходить некуда!
посмотрите на что Вы подписаны и сделайте число инструментов в подписке одинаковым Сделайте одинаковое число открытых графиков
QUIK и жор памяти, Проблема с памятью скриптов Qlua
Пользователь
Сообщений: Регистрация: 30.01.2015
07.10.2026 18:31:12
Цитата
Кот написал: Случилось у меня такое интересное наблюдение :
Торговый робот на одной копии QUIK у одного брокера работает нормально, создаёт таблицу данных (43 мБ) и в течении всего времени работы поддерживает выделение памяти на этом уровне. Тот же самый работ на другой копии QUIK (той же версии 8.13.1.6), но у другого брокера испытывает скачки памяти (в таблицах Qlua) с интервалом приблизительно в 3-5 секунд : память растёт от 43мБ до 86 мБ, после чего опять возвращается к уровню 43мБ.
Никакой разницы в роботах или версиях QUIK нет. Все тяжелые вычисления проводятся с намного большей периодичностью (меньшей частотой), приблизительно раз в 30-60 секунд и в обязательном порядке сопровождаются вызовом сборщика мусора. В промежутках между вычислениями сборщик мусора не вызывается, а вся нагрузка это не частые запросы типа Poll (опрос) к котировкам и таблицам заявок. Среди колбэков только легковесные OnOrder(), OnTrnsReply() и всё. При этом на обоих экземплярах QUIK ведётся торговля другими торговыми алгоритмами приблизительно с одинаковой интенсивностью, то есть все обработчики вызываются одинаково регулярно и их выполнение точно не занимает в памяти 40 мБ.
Подскажите, в чём может быть проблема?!
Посмотрите сколько памяти занимает каждый вариант QUIK
написал: Но колбек вызывается перед записью в таблицу обезличенных сделок. Если читать из таблицы то будет вызов колбека, запись в таблицу, и потом чтение из нее.
Здесь есть сомнения, т.к. колбек на таблицу - это событие на изменение данных, которые приходят в пакетах. Что произойдет первым - это вопрос, т.к. я не раз ловил в логах ситуацию когда запись в таблице появлялась ранее чем колбек. Но даже если это такт, то не очень понятно, что это изменяет. Я бы сказал, наоборот, наличие такого частого колбека приведет к падению производительности. Организовать процедуру чтения порций с опросом числа записей в таблице - довольно банальная задача. Сотни тысяч записей записываются в файл за пару секунд. А далее, по мере поступления уже новых, просто их обрабатываем. Зачем для этого колбек в потоке терминала - не ясно. Сама идея событийной модели - это абстракция, за которой все равно будет код, проверяющий что событие наступило. Поэтому я предпочитаю сам это делать, с необходимой мне частотой.
Когда только сделали этот механизм тоже спорил с автором сей разработки об алгоритме решения Но автор так написал роман, а мы лишь читатели.
Использование мессенджера MAX для обмена данными в QUIK, Использование мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK
Пользователь
Сообщений: Регистрация: 30.01.2015
20.09.2026 07:27:51
Еще один вариант. Особо не отлаживал. Выкладываю как есть:
Код
-- max_bridge.lua
-- Двусторонний мост QUIK <-> MAX Messenger
-- Lua 5.3/5.4: native bitwise, //, math.tointeger, <const>
-- Очереди: T={{},0,0} — массив + jw/jr, сброс в push
local MAX = {}
--========== КОНФИГУРАЦИЯ ==========--
MAX.TOKEN = "ВАШ_ТОКЕН"
MAX.API_URL = "https://platform-api2.max.ru"
MAX.CHAT_ID = nil
MAX.LAST_MARKER = 0
MAX.LAST_SEND = 0.0
MAX.LAST_POLL = 0.0
MAX.ERR_COUNT = 0
MAX.HTTP = nil
local luacom_ok, luacom = pcall(require, "luacom")
local MSG_GAP <const> = 2.0
local POLL_GAP <const> = 2.0
local ONIDLE_RET <const> = 200
local F_ACTIVE <const> = 1
local F_SELL <const> = 4
--========== ОЧЕРЕДИ ==========--
-- T = { buf, jr, jw }
-- T[1] — массив данных
-- T[2] — указатель чтения (jr)
-- T[3] — указатель записи (jw)
-- При jr == jw (очередь пуста) — сброс в 0, следующая запись в buf[1]
local function setQ(T, X)
local jw = T[3]
if T[2] == jw then
jw = 0
T[2] = 0
end
jw = jw + 1
T[1][jw] = X
T[3] = jw
end
local function getQ(T)
local jr = T[2]
if T[3] > jr then
jr = jr + 1
T[2] = jr
return T[1][jr]
end
end
local function qsize(T)
return T[3] - T[2]
end
MAX.INCOMING = {{}, 0, 0}
MAX.OUTGOING = {{}, 0, 0}
--========== ТАБЛИЦЫ КОДИРОВАНИЯ/ДЕКОДИРОВАНИЯ ==========--
local escape_map <const> = {
[92] = '\\\\', -- \ > \\
[34] = '\\"', -- " > \"
[10] = '\\n', -- \n > \n
[13] = '\\r', -- \r > \r
[9] = '\\t', -- \t > \t
}
local unescape_map <const> = {
[110] = '\n', -- n > \n
[114] = '\r', -- r > \r
[116] = '\t', -- t > \t
[34] = '"', -- " > "
[92] = '\\', -- \ > \
[47] = '/', -- / > /
}
--========== КОДИРОВАНИЕ (escape) ==========--
local function json_escape(s)
local res, j = {}, 0
for i = 1, #s do
local b = s:byte(i)
local rep = escape_map[b]
if rep then
j = j + 1
res[j] = rep
else
j = j + 1
res[j] = s:sub(i, i)
end
end
return table.concat(res)
end
--========== ДЕКОДИРОВАНИЕ (JSON-парсер) ==========--
local J = { s = "", p = 1 }
local j_skip, j_val
j_skip = function()
while J.p <= #J.s do
local c = J.s:byte(J.p)
if c == 32 or c == 9 or c == 10 or c == 13 then J.p = J.p + 1
else break end
end
end
j_val = function()
j_skip()
local c = J.s:byte(J.p)
if c == 34 then
J.p = J.p + 1
local buf, i = {}, 0
while J.p <= #J.s do
local ch = J.s:byte(J.p)
if ch == 92 then
local n = J.s:byte(J.p + 1)
local rep = unescape_map[n]
if rep then
buf[i + 1] = rep
else
buf[i + 1] = J.s:sub(J.p + 1, J.p + 1)
end
i = i + 1
J.p = J.p + 2
elseif ch == 34 then
J.p = J.p + 1
return table.concat(buf)
else
buf[i + 1] = J.s:sub(J.p, J.p)
i = i + 1
J.p = J.p + 1
end
end
return table.concat(buf)
elseif c == 123 then
J.p = J.p + 1; j_skip()
local obj = {}
if J.s:byte(J.p) == 125 then J.p = J.p + 1 return obj end
while true do
j_skip()
local key = j_val()
j_skip()
if J.s:byte(J.p) == 58 then J.p = J.p + 1 end
obj[key] = j_val()
j_skip()
local sep = J.s:byte(J.p)
if sep == 44 then J.p = J.p + 1
elseif sep == 125 then J.p = J.p + 1 break
else break end
end
return obj
elseif c == 91 then
J.p = J.p + 1; j_skip()
local arr = {}
if J.s:byte(J.p) == 93 then J.p = J.p + 1 return arr end
while true do
arr[#arr + 1] = j_val()
j_skip()
local sep = J.s:byte(J.p)
if sep == 44 then J.p = J.p + 1
elseif sep == 93 then J.p = J.p + 1 break
else break end
end
return arr
else
local start = J.p
while J.p <= #J.s do
local b = J.s:byte(J.p)
if b == 32 or b == 9 or b == 10 or b == 13
or b == 44 or b == 125 or b == 93 then break end
J.p = J.p + 1
end
local v = J.s:sub(start, J.p - 1)
if v == "true" then return true
elseif v == "false" then return false
elseif v == "null" then return nil
else return tonumber(v) or v end
end
end
local function json_parse(str)
J.s = str; J.p = 1
return j_val()
end
--========== HTTP ==========--
local function http(method, url, body)
if not MAX.HTTP then return nil, 0 end
MAX.HTTP:Open(method, url, false)
MAX.HTTP:SetRequestHeader("Authorization", MAX.TOKEN)
MAX.HTTP:SetRequestHeader("Accept", "application/json")
if body then
MAX.HTTP:SetRequestHeader("Content-Type", "application/json")
MAX.HTTP:Send(body)
else
MAX.HTTP:Send()
end
return MAX.HTTP.ResponseText, MAX.HTTP.Status
end
local function raw_send(msg, chat_id, nFormat)
chat_id = chat_id or MAX.CHAT_ID
if not chat_id then return false end
chat_id = math.tointeger(chat_id) or chat_id
local fmt = ""
if nFormat == 1 then fmt = ',"format":"html"'
elseif nFormat == 2 then fmt = ',"format":"markdown"' end
local body = '{"text":"' .. json_escape(msg) .. '"' .. fmt .. '}'
local url = MAX.API_URL .. "/messages?chat_id=" .. tostring(chat_id)
local resp, status = http("POST", url, body)
if status == 200 then
MAX.ERR_COUNT = 0
return true
end
MAX.ERR_COUNT = MAX.ERR_COUNT + 1
if MAX.ERR_COUNT <= 3 then
message("MAX: " .. tostring(status) .. " " .. tostring(resp):sub(1, 150), 3)
end
return false
end
--========== ПУБЛИЧНЫЙ API ==========--
function SendToMAX(msg, chat_id, nFormat)
setQ(MAX.OUTGOING, { m = msg, c = chat_id, f = nFormat or 0 })
end
--========== POLLING ==========--
local function poll()
local url = MAX.API_URL .. "/updates?marker=" .. tostring(MAX.LAST_MARKER)
.. "&timeout=0"
local resp, status = http("GET", url, nil)
if status ~= 200 or not resp then
MAX.ERR_COUNT = MAX.ERR_COUNT + 1
return
end
MAX.ERR_COUNT = 0
local data = json_parse(resp)
if not data then return end
if data.marker then MAX.LAST_MARKER = data.marker end
if not data.updates then return end
for _, upd in ipairs(data.updates) do
local utype = upd.update_type
if utype == "bot_started" then
if upd.chat and upd.chat.chat_id then
MAX.CHAT_ID = math.tointeger(upd.chat.chat_id) or upd.chat.chat_id
end
message("MAX: chat_id = " .. tostring(MAX.CHAT_ID))
SendToMAX("? Связь установлена. /help — список команд", nil, 2)
elseif utype == "message_created" then
local msg = upd.message
if not msg then goto next_upd end
if msg.recipient and msg.recipient.chat_id then
MAX.CHAT_ID = math.tointeger(msg.recipient.chat_id) or msg.recipient.chat_id
end
local text = msg.body and msg.body.text or ""
setQ(MAX.INCOMING, text)
message("MAX < " .. text)
end
::next_upd::
end
end
--========== ДИСПЕТЧЕР ==========--
local function dispatch()
local now = os.clock()
if now - MAX.LAST_SEND < MSG_GAP then return end
-- Приоритет: исходящие
if qsize(MAX.OUTGOING) > 0 then
local item = getQ(MAX.OUTGOING)
if raw_send(item.m, item.c, item.f) then
MAX.LAST_SEND = os.clock()
end
return
end
-- Затем: подтверждение входящего
if qsize(MAX.INCOMING) > 0 then
local text = getQ(MAX.INCOMING)
local reply = MAX.build_reply(text)
if raw_send(reply, nil, 2) then
MAX.LAST_SEND = os.clock()
end
return
end
end
--========== ОБРАБОТКА КОМАНД ==========--
function MAX.build_reply(text)
if not text then return "/help — список команд" end
local cmd = text:lower():gsub("^%s+", ""):gsub("%s+$", "")
if cmd == "/help" or cmd == "помощь" then
return "Команды:\n/status — состояние\n/positions — позиции\n/orders — заявки\n/trades — последние сделки\n/help — список"
elseif cmd == "/status" or cmd == "статус" then
return "QUIK работает. " .. os.date("%Y-%m-%d %H:%M:%S")
elseif cmd == "/positions" or cmd == "позиции" then
local lines, n = {}, 0
for i = 0, getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do
local p = getItem("FUTURES_CLIENT_HOLDING", i)
if p and p.openqty ~= 0 then
n = n + 1
local qty = math.abs(math.tointeger(p.openqty) or tonumber(p.openqty) or 0)
local vm = tonumber(p.varmargin) or 0
lines[n] = string.format("%s **%s** %d шт, вм %.2f",
p.openqty > 0 and "Лонг" or "Шорт",
tostring(p.sec_code), qty, vm)
end
end
return n == 0 and "Нет позиций." or table.concat(lines, "\n")
elseif cmd == "/orders" or cmd == "заявки" then
local lines, n = {}, 0
for i = 0, getNumberOf("ORDERS") - 1 do
local o = getItem("ORDERS", i)
if o and (o.flags & F_ACTIVE) ~= 0 then
n = n + 1
local qty = math.tointeger(o.qty) or tonumber(o.qty) or 0
local price = tonumber(o.price) or 0
lines[n] = string.format("%s **%s** %d @ %.2f",
(o.flags & F_SELL) ~= 0 and "Прод" or "Покуп",
tostring(o.sec_code), qty, price)
end
end
return n == 0 and "Нет заявок." or table.concat(lines, "\n")
elseif cmd == "/trades" or cmd == "сделки" then
local lines = {}
local total = getNumberOf("TRADES")
local start = total > 5 and total - 5 or 0
for i = start, total - 1 do
local t = getItem("TRADES", i)
if t then
local qty = math.tointeger(t.qty) or tonumber(t.qty) or 0
local price = tonumber(t.price) or 0
lines[#lines + 1] = string.format("%s **%s** %d @ %.2f",
(t.flags & F_SELL) ~= 0 and "Прод" or "Покуп",
tostring(t.sec_code), qty, price)
end
end
return #lines == 0 and "Сделок нет."
or "Последние:\n" .. table.concat(lines, "\n")
else
return "Получено: " .. text .. "\n/help — список команд"
end
end
--========== CALLBACKS QUIK ==========--
function OnInit()
if not luacom_ok then
message("MAX Bridge: luacom не найден!", 3)
return
end
MAX.HTTP = luacom.CreateObject("WinHttp.WinHttpRequest.5.1")
if MAX.HTTP then
MAX.HTTP:SetTimeouts(3000, 3000, 5000, 5000)
message("MAX Bridge: запущен. Lua " .. _VERSION .. ". Ожидание /start...")
else
message("MAX Bridge: WinHttpRequest не создан!", 3)
end
end
function OnIdle()
if not MAX.HTTP then return 1000 end
local now = os.clock()
local interval = POLL_GAP
if MAX.ERR_COUNT > 3 then
interval = POLL_GAP * (MAX.ERR_COUNT < 10 and MAX.ERR_COUNT or 10)
end
if now - MAX.LAST_POLL >= interval then
MAX.LAST_POLL = now
poll()
end
dispatch()
return ONIDLE_RET
end
function OnStop()
local out_n = qsize(MAX.OUTGOING)
local inc_n = qsize(MAX.INCOMING)
if MAX.CHAT_ID then
if out_n + inc_n > 0 then
raw_send(string.format(
"?? MAX Bridge остановлен. В очередях: %d исх, %d вх.",
out_n, inc_n), nil, 0)
else
raw_send("?? MAX Bridge остановлен.", nil, 0)
end
end
MAX.HTTP = nil
return 1000
end
function OnTrade(trade)
local is_sell = (trade.flags & F_SELL) ~= 0
local qty = math.tointeger(trade.qty) or tonumber(trade.qty) or 0
local price = tonumber(trade.price) or 0
SendToMAX(string.format("?? %s **%s** %d @ %.2f",
is_sell and "Прод" or "Покуп",
tostring(trade.sec_code), qty, price), nil, 2)
end
--[[
Инструкция: мост QUIK - MAX
Шаг 1. Создание бота в MAX
Откройте MAX на смартфоне, найдите бота Masterbot (или через бизнес-кабинет , если есть юрлицо/ИП).
Создайте нового бота, получите токен — длинная строка вида f9LHodD0cOIq...0BhMw0gm_6f1-DBY.
Напишите боту команду /start — это нужно, чтобы бот «увидел» вас и скрипт позже сможет подхватить ваш chat_id.
Шаг 2. Установка скрипта в QUIK
Откройте скрипт в любом текстовом редакторе (Блокнот, Notepad++).
Найдите строку MAX.TOKEN = "ВАШ_ТОКЕН" и вставьте свой токен.
Сохраните файл, например, max_bridge.lua.
В QUIK: меню Сервис > Lua-скрипты (или Ctrl+I).
Нажмите Добавить, выберите max_bridge.lua.
Нажмите Запустить.
В окне сообщений QUIK должно появиться: MAX Bridge: запущен. Lua 5.x. Ожидание /start...
Шаг 3. Подключение смартфона
Откройте MAX на телефоне, найдите своего бота.
Отправьте ему команду /start.
Скрипт перехватит событие bot_started, запомнит ваш chat_id и пришлёт ответ: ? Связь установлена. /help — список команд.
Всё — двусторонняя связь работает.
Шаг 4. Команды с телефона
Отправляйте боту в MAX:
Команда Что делает
/help Список всех команд
/status Состояние QUIK, дата/время
/positions Открытые фьючерсные позиции
/orders Активные заявки
/trades Последние 5 сделок
Шаг 5. Отправка сообщений из QUIK
Скрипт регистрирует глобальную функцию SendToMAX().
Любой другой Lua-скрипт в QUIK может вызывать её для отправки уведомлений на телефон:
lua
-- Простой текст (без разметки)
SendToMAX("Сигнал: RTS пробил 100000")
-- Текст с разметкой Markdown (формат 2)
SendToMAX("**Внимание!** Цена `GAZP` упала ниже 200", nil, 2)
-- Текст с разметкой HTML (формат 1)
SendToMAX("<b>Внимание!</b> Цена GAZP упала ниже 200", nil, 1)
-- Отправка в конкретный чат (если chat_id известен)
SendToMAX("Личное сообщение", 117000000474, 0)
Форматы:
0 — без разметки (по умолчанию)
1 — HTML (<b>жирный</b>, <i>курсив</i>)
2 — Markdown (**жирный**, _курсив_, `моноширинный`)
Все сообщения попадают в очередь и отправляются не чаще одного в 2 секунды — лимит MAX не нарушается.
Шаг 6. Автоматические уведомления
Скрипт уже содержит обработчик OnTrade — при каждой сделке в QUIK на телефон автоматически уходит уведомление:
text
?? Прод **RIZ5** 5 @ 105250.00
?? Покуп **GAZP** 100 @ 198.50
Чтобы добавить свои триггеры, допишите в скрипт или в отдельный файл:
lua
-- Пример: уведомление при изменении цены
function OnQuote(class_code, sec_code)
if sec_code == "RIZ5" then
local ql = getQuoteLevel2(class_code, sec_code)
if ql and #ql.bid > 0 then
local bid_price = tonumber(ql.bid[#ql.bid].price)
if bid_price and bid_price > 105000 then
SendToMAX("RIZ5 выше 105000! Текущая bid: " .. bid_price, nil, 2)
end
end
end
end
Шаг 7. Остановка
В окне Lua-скрипты нажмите Остановить.
Скрипт отправит в MAX сообщение: ?? MAX Bridge остановлен. (или с количеством неотправленных сообщений в очередях).
COM-объект освобождается, связь закрывается.
Типичные проблемы
Скрипт запущен, но /start не приходит:
Проверьте, что токен вставлен правильно, без пробелов.
Проверьте интернет-соединение на ПК.
В окне сообщений QUIK посмотрите ошибки — если WinHttpRequest не создан, возможно, COM заблокирован антивитором.
Сообщения приходят с задержкой:
Это нормально — rate limit 2 секунды. Если в очереди 5 сообщений, последнее уйдёт через 10 секунд.
Если задержка больше минуты — проверьте, не вырос ли ERR_COUNT (ошибки сети). При ошибках polling замедляется.
luacom не найден:
В некоторых сборках QUIK библиотека luacom не установлена по умолчанию.
Скачайте luacom.dll и положите в папку QUIK рядом с остальными .dll.
Кириллица в сообщениях ломается:
Скрипт отправляет в кодировке UTF-8.
Если QUIK отдаёт строки в Windows-1251 (что типично), кириллица может прийти кривой.
В этом случае нужно конвертировать текст перед отправкой — скажите, добавлю функцию перекодировки.
Если торгуете акциями, а не фьючерсами — замените FUTURES_CLIENT_HOLDING на нужную таблицу в build_reply для команды /positions.
--]]
Квик перестал запускаться, Диалоговое окно "Прекращена работа программы "Рабочее место информационно-торговой системы QUIK""
Просим выполнить следующие рекомендации и сообщить результат:
Удалите временные файлы *.dat и *.log, кроме файлов: scripts.dat, portfolio.dat, alert.dat, qbclists.dat. Проверьте работу программы.
Исключите загрузку текущего файла настроек окон *.wnd. Проверьте работу программы.
Обновите используемые скрипты и внешние модули от сторонних разработчиков если это возможно или отключите их, удалив файл scripts.dat перед запуском программы. Проверьте работу программы.
все было нормально, а сегодня опять ошибка, но уже после авторизации, приложение попросило заменить несколько инструментов, я их заменил, произошла замена и та же ошибка - "Прекращена работа программы..."; запустил второй раз, авторизацию прошел, опять просит замену инструментов - "Истек срок использования 9 инструментов, заменить их?" - отвечаю Нет, а оно еще раз показывает это окно повторно - опять отвечаю Нет, дальше будем смотреть, пока приложение работает нормально, скрин ошибки:
Подозреваю, что проблема в железе. Давно комп от пыли чистили? Проверьте температуру CPU и работу вентиляторов
Использование мессенджера MAX для обмена данными в QUIK, Использование мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK
Пользователь
Сообщений: Регистрация: 30.01.2015
18.09.2026 09:31:48
Цитата
Евгений написал: Поскольку , эта тема вроде нигде не поднималась , опишу свой опыт , может быть будет кому то полезно. Для информирования и контроля за работой торгового привода у меня был поднят небольшой саит на локальном компе с QUIK ,и меня все устраивало, Сейчас эта схема практически утратила смысл из за почти постоянного отключения мобильного интернета. Я решил посмотреть , что можно использовать взамен. Нормально работали только саиты из белого списка и MAX. Поскольку других вариантов не было , выбор пал на MAX ,
Код
Странно, если мобильный интернет не работает то и МАХ не должен работать. скорее всего не работал DNS cервер, поэтому не могли найти IP адрес ---------------------------- из моего опыта . Кратко. можно не делать сайт , а создать сервер на локальном компьютере там же где квик Потом сообщить на смартфон IP адрес своего локального компа , у которого есть выход в интернет. Будете работать напрямую со своим сервером. ------------------------------ Еще варианты прокси или VPN можно бесплатные
Вопросы про OnParam
Пользователь
Сообщений: Регистрация: 30.01.2015
09.09.2026 18:02:59
Возможно это связано со сменой сервера, т к OnCleanUp вызывается терминалом при смене сервера QUIK внутри торговой сессии.
Что происходит при экспирации опциона с точки зрения скрипта?
Пользователь
Сообщений: Регистрация: 30.01.2015
29.08.2026 09:09:24
Цитата
Nikolay написал: OnFuturesClientHolding - срабатывает на любые изменения в таблице, как и любой другой колбек в контексте Квика. Уж так сделано...
Сделки не должно быть, второго контрагента же нет.
А Вы не ошибаетесь? На каждый CALL есть свой PUT. Т е если кто-то купил ,то должен быть тот, кто продал
Квик перестал запускаться, Диалоговое окно "Прекращена работа программы "Рабочее место информационно-торговой системы QUIK""
Пользователь
Сообщений: Регистрация: 30.01.2015
27.08.2026 20:34:34
Попробуйте сделать так Если будет ошибка посмотрите объем занятой памяти. Потом закройте все приложения и снова запустите QUIK Посмотрите объем занятой памяти. Напишите что получилось
Коннектор на Lua 5.1 переписать под Lua 5.4 &, Lua 5.1 -Lua 5.4
Пользователь
Сообщений: Регистрация: 30.01.2015
23.08.2026 05:45:18
Для декомпиляции не нужна отладочная информация в скрипте Декомпилируется байт-код.
Коннектор на Lua 5.1 переписать под Lua 5.4 &, Lua 5.1 -Lua 5.4
возможно, но успех зависит от сложности скрипта. Иногда проще написать заново
Закрывается DataSource при остановке скрипта?
Пользователь
Сообщений: Регистрация: 30.01.2015
16.08.2026 12:56:37
Закрывается DataSource при остановке скрипта?
Пользователь
Сообщений: Регистрация: 30.01.2015
16.08.2026 12:54:21
Код
class="QJSIM"
sec="SBER"
local run = true
function OnStop()
run = nil
local x=ds:Close()
message(tostring(ds)..","..tostring(x),1)
end
function main()
ds = assert(CreateDataSource(class, sec, INTERVAL_M5))
while run do sleep(500) end
end
Демо Quik - даёт истрические данные текущего дня?, Получение исторических ланных в Демо версии?
Пользователь
Сообщений: Регистрация: 30.01.2015
14.08.2026 13:42:04
Цитата
Виктор Волков написал: используется связка Скрипт на Python (библиотека обёртка QuikPy) , коннектор на Lua (QuikSharp) , Демо Квик...
может это пригодится:
Робот, торгующий опционами
Пользователь
Сообщений: Регистрация: 30.01.2015
08.08.2026 13:30:26
и еще... мое мнение: ------------------------- Суть в том что когда торгуем фьючерсом то при покупке и продаже возникает обязанность. когда же продаем опцион, то как во фьючерсах возникает обязанность , но когда покупаем опцион , то возникает лишь право. ---------------------- Таким образом , продажа опциона как и торговля фьючерсом создает обязанность(обязательство). Но в случае с опционом величина риска ничем не ограничена. ----------------------- Что же касается фьючерсов, то в них риск больше по сравнению с акциями только потому, что во фьючерсах всегда есть плечо и срок жизни фьючерса ограничен, если он не вечный. ----------------------- Поэтому риск во фьючерсах больше, чем в акциях.
Робот, торгующий опционами
Пользователь
Сообщений: Регистрация: 30.01.2015
08.08.2026 12:07:52
Вот мнение ИИ вполне компетентное и обоснованное: Прямой и короткий ответ: Нет, классических биржевых опционов, базовым активом которых выступает именно бессрочный (вечный) фьючерс, практически не существует.
Однако есть очень важные нюансы и альтернативы, которые работают точно так же или даже лучше.
Вот почему так и какие есть варианты:
1. Техническая причина: Дата экспирации
Это главное противоречие. Опцион всегда имеет дату истечения (экспирации). Его стоимость зависит от времени, оставшегося до этой даты (тета-распад).
Бессрочный фьючерс (Perpetual Swap) создан так, чтобы никогда не истекать. Он привязан к спотовой цене через механизм ставки финансирования.
Привязать срочный контракт (опцион) к бессрочному инструменту так, чтобы получился ликвидный биржевой продукт, технически очень сложно. Биржам это не нужно, потому что уже существуют отличные аналоги.
2. Что используют вместо опционов на вечный фьючерс?
Трейдеры, которые хотят торговать волатильностью или хеджировать позиции по "вечникам", используют два инструмента:
А) Опционы на спотовый актив
Это 90% рынка крипто-опционов (Deribit, OKX, Binance Options).
У вас открыт вечный фьючерс на BTC.
Вы покупаете пут-опцион на спотовый BTC.
Результат: Хедж работает идеально, потому что цена вечного фьючерса благодаря финансированию всегда стремится к спотовой цене. Расхождение минимально.
Б) Опционы на срочные (квартальные) фьючерсы
На биржах вроде Deribit или CME торгуются опционы, где базовый актив — не вечный, а классический фьючерс с экспирацией (март, июнь, сентябрь, декабрь).
Вы покупаете опцион, который при экспирации превращается в срочный фьючерс.
Это сложнее, и здесь нужно следить за базисом (разницей между ценой фьючерса и спота), но профессиональные трейдеры активно этим пользуются.
3. Экзотика: "Вечные опционы" (Perpetual Options)
Справедливости ради, существуют экспериментальные проекты, которые пытаются создать именно бессрочные опционы (например, исследование Paradigm о "Perpetual Options" или Everlasting Options).
Суть идеи: У такого опциона нет экспирации. Вместо этого периодически (например, раз в сутки) происходит клиринг, где прибыль начисляется автоматически, а если опцион "вне денег" — у держателя списывается аналог "ставки финансирования" (тета-сбор).
Реальность: На данный момент (2024-2025) это больше теоретические модели De-Fi протоколов. Как массовый ликвидный биржевой инструмент на CEX (централизованных биржах) "вечные опционы" пока не прижились.
Итог
Если вы торгуете вечные фьючерсы и хотите купить опцион для страховки позиции, вам не нужен специальный опцион именно на вечный фьючерс.
Открывайте терминал опционов (например, Deribit).
Выбирайте базовый актив — спот (BTC/USD) или срочный фьючерс.
Покупайте пут или колл.
Разница в цене между вечным фьючерсом и этим базовым активом будет ничтожной (обычно в пределах ставки финансирования за пару часов), поэтому защита работает на 100%.
написал: Написал письмо Мосбирже. Жду официального ответа
Из письма следует что опционов на вечный фьючер на московской бирже нет. а голое мнение, что такие опционы бывают ничем не подкреплено и вполне может быть ошибочным
написал: Это самый рискованный инструмент для торговли.
Опцион - это самый доходный инструмент из имеющихся, но не самый рискованный. Самый рискованный - это как раз фьючерс. Если не продавать, а только покупать опционы, то твой маскимальный убыток - это деньги, которые ты заплатил за опционы. Во фьючерсах же максимальный убыток не ограничен, и можно просто обнулиться (если не следить за позицией), сколько бы у тебя денег ни было на счету.
Все верно Вы лишь подтвердили то что я сказал. если не будете продавать опционы Т е вы кастрируете саму торговлю опционами то опционы станут менее рискованными/ Но тогда уж если вообще не будете торговать на бирже то совсем риска не будет ------------------------- Поэтому без кастрации опционы самый рискованный , если кастрировали - то фьючерс . ================================ Итоговый вердикт от ИИ:
По уровню риска для новичка: Фьючерс опаснее опциона (в роли покупателя).
Самый опасный инструмент в мире: Продажа непокрытых (голых) опционов. Там можно потерять сумму, значительно превышающую весь ваш капитал.
Поэтому: если хотите ограничить потери известной суммой, работайте с покупкой опционов. Если готовы к быстрым и линейным прибылям/убыткам — фьючерсы. Никогда не продавайте опционы, если до конца не понимаете «греков» и маржинальные требования.
глобалки колбэки и многопоточность
Пользователь
Сообщений: Регистрация: 30.01.2015
04.08.2026 15:52:07
Цитата
andrey2185 написал: на сколько безопасно изменения глобалки из колбэка и чтение из main? есть ли вероятность , что мы упадём нахер?
ISRUN = false
LAST_ALLTRADE_NUM = 0
function OnAllTrade(alltrade) LAST_ALLTRADE_NUM = alltrade.trade_num end
function main() x = 0 while ISRUN do if LAST_ALLTRADE_NUM > x then x = LAST_ALLTRADE_NUM -- ... else sleep(1) end end end
колбеки в том же стейте что и глобалки Т е они никогда не упадут проблемы в многопоточности не с чтением данных а с записью новых в момент чтения. Поэтому с чтением в main глобалок тоже нет проблем Полагаю что там задействованы еще и критические секции. ---------------------------- Но в любом случае туда , куда указали,точно не упадет.
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
03.08.2026 08:30:21
Цитата
Nikolay написал: Альтернатива - чтение таблицы обезличенных сделок (тики) и это будет самое точное (читать не через колбеки точно), но проблема что её не все брокеры выдают, поэтому это решение нельзя использовать как базовое.
Но колбек вызывается перед записью в таблицу обезличенных сделок. Если читать из таблицы то будет вызов колбека, запись в таблицу, и потом чтение из нее.
limit_kind в таблице depo_limit
Пользователь
Сообщений: Регистрация: 30.01.2015
01.08.2026 11:50:25
для фьючерсов ставлю NUMBER type=0
limit_kind в таблице depo_limit
Пользователь
Сообщений: Регистрация: 30.01.2015
01.08.2026 11:49:02
limit_kind — это число, кодирующее режим расчётов:
0 — T+0;
1 — T+1;
2 — T+2;
365 — Tx (плановая позиция с максимальной датой расчётов).
limit_kind в таблице depo_limit
Пользователь
Сообщений: Регистрация: 30.01.2015
01.08.2026 11:46:10
ставьте 0 или 1 или 2 или 3 limit_kind режим расчётов по сделке:
Очень информативно! (нет!) Если не можете дать чёткий ответ, лучше не писать.
Я ответил вам про параметр NUMBER limit_kind что непонятно?
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
31.07.2026 11:49:51
Цитата
TGB написал: 4. Коды скрипта разделяются между потоками, использующими его. В выбранном варианте трансляции исходников Lua активирована синхронизация, обеспечивающая использование кода LUa только одним потоком, но на разных стеках. Сишные функции (не использующие управление память Lua) при их вызовах выполняются в потоке их вызова, и при этом разрешается выполнение потока на другом стеке. После звершения сишной функции, его поток блокируется до тех пор пока в потоке, исполняемом код Lua не будет вызвана сишная функция.
Тут у Вас ошибка в понимании. Коды не надо разделять или синхронизировать Они могут исполнятся потоками одновременно . Разделяется обращение к памяти данных Это еще называется синхронизация потоков. Т е синхронизация потоков это не про коды а про данные.
Nikolay написал: Тест был направлен не на измерение скорости работы скрипта, а на влияние работы скрипта на работу терминала, его интерфейса в первую очередь. Какой смысл показать, да ещё на демо, что main работает быстро. У меня на демо тоже всё прекрасно. Переключаешься на реальный и во время открытия рынка - терминал вкладки переключает по 30 секунд. Была бы возможность инструментально измерить работу самого терминала - так и вопросов не было бы.
Вы не поняли мой тест. Тест проверяет быстродействие выполнения колбеков, включая обработку очереди .
Проблема возврата предыдущей версии, Вопрос к разработчикам.
Пользователь
Сообщений: Регистрация: 30.01.2015
28.07.2026 05:34:12
Добрый день, Так как есть подозрения , что тормоза терминала связаны с версией , то решил проверить это установив старую версию 8.7 Но установить ее по сохраненной версии в backup не удается -------------------------- копирую все файлы из архива Удаляю все log Запускаю info.exe Появляется окно терминала Исчезает окно терминала Что не так?
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
28.07.2026 05:11:28
Цитата
Nikolay написал: Оставил скрипты тестовые с колбеками запущенными. В итоге:
задержка данных при обмене с сервером = 11.109 средняя задержка данных = 26.384. Максимальная задержка данных = 175.063
Как только остановил скрипты - побежал счётчик полученных пакетов, отставших записей в информационном окне. И пока данные бегут, то терминал и без скриптов не особо спешит.
Вывод -тормозят Ваши скрипты. Измерьте время их исполнения. ------------------ Кроме того, тормозит сервер брокера . И это не зависит от скриптов. Последнее время у Сбера видны задержки в выставлении заявок Т е уходит заявка из терминала а в стакане она появляется с заметной задержкой визуально. Так как задержка реакция нашего глаза не менее 0.2 сек то можно говорить что заявка выставляется с задержкой сотни миллисекунд. ------------------------ Объяснить это можно лишь задержкой на стороне сервера. Два варианта 1) Умышленная задержка на стороне сервера. 2) Большие очереди заявок. ------------------------------------- Но так как эта задержка существует и при спокойном рынке, то скорее всего это 1 вариант
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
27.07.2026 11:42:37
Цитата
Nikolay написал: Вот прямо сейчас смотрю на один из терминалов - банально время сервера в строке состояния изменяется скачками, замирая на длительный период. И так каждый раз при старте, что, в теории, нормально, т.к. приходят пакеты. Но не 15 минут же. На терминалах других брокеров это же занимает минуту, 5-ять иногда. И в это время отчетливо видно как с трудом совершаются любые операции с интерфейсом.
Аналогично и в периоды высокой ликвидности. В это время транзакции могут исполнятся минуты - это ожидаемо, но почему опять интерфейс также "умирает".
Я готов это списать на влияние работы скриптов. Но тогда хотелось бы понять, что именно и какие методы оказывают максимальное влияние. Иначе делаешь банальный скрипт, а эффект как будто модель на 100b считаешь.
О скачках времени сервера читайте здесь:
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
27.07.2026 07:25:42
сделал свой тест на демо сервере --------------- Так как скрипт рабочий и большой, то расскажу основные моменты, чтобы было понятно , что и как -------------------- У меня все колбеки сделаны одинаков таким образом:
Код
OnOr der=function(t) setQ(4,t); end
Функция setQ помещает таблицу параметров колбека t и ключ колбека в очередь. В этой функции я добавил в параметры значение точного счетчика Windows Этот счетчик считает с квантом 0.1 мкс -------------------------------- В функции main я в цикле обрабатываю элементы очереди В данном тесте я из значения точного счетчика вычитаю сохраненное его значения при записи в очередь Результат пишу в лог файл ------------------------------------------- Таким образом в лог файле я получаю время задержки от вызова любого колбека до начала обработки параметров этого колбека в main Т е фактически это время задержки от момента записи в очередь до момента начала обработки элемента из очереди
возможно Вы правы пока не проверял. Но тогда это прикольно. По крайней мере для меня. ------------------------------- Полагаю ,что правильный скрипт запускается при любой погоде. ------------------------- А эти тупо молчат нет никаких сообщений об ошибках или о нелетной погоде .
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
26.07.2026 05:37:17
Цитата
Nikolay написал: Ок. Чтобы показать влияние на работу интерфейса терминала еще сделал такой тест.
Терминал свежий, установлен не более двух недель назад. Брокер ВТБ. Остановил все скрипты, даже автологин.
В тестируемом скрипте добавил запоминание последних значений, чтобы выводились в окно только измененные данные. Лог через PrintDbgStr. В колбеках вывода в лог нет, только в main.
Запускаем три экземпляра скрипта и смотрим на реакцию терминала.
Один скрипт - почти нет влияния. Два - уже ТТТ "подвисла" и данные выводятся не так быстро. Три - всё встало, данные появляются только если "пнуть" таблицу
В архиве скрипты, лог с таймингом работы main, запись видео работы терминала.
Код тестового скрипта - по факту, он ничего не делает, кроме обработки колбеков, запроса данных через методы QLUA, и вывода данных в таблицу. Никаких расчётов, даже файловые операции убраны.
Код
Взял скрипты На демо версии тесты не запускаются что не так?
Периодические паузы в получении данных
Пользователь
Сообщений: Регистрация: 30.01.2015
24.07.2026 13:00:51
лекарство только одно - стучать брокеру по ...
Периодические паузы в получении данных
Пользователь
Сообщений: Регистрация: 30.01.2015
24.07.2026 13:00:14
Я про это писал и выкладывал скрипт, который это обнаруживает и пишет в лог файлы
У нас есть колбеки - настоятельно рекомендуемые к использованию. Есть окно скрипта - единственный способ вывести данные. Банальная задача - вывести данные, полученные через getParamEx. Также, для какой-то нагрузки - читаем 7 стаканов, при этом даже не разбирая их, а банально беря верхние значения, т.е. просто запрос данных.
И выводим это в таблицу. Всё. Ни транзакций, ни расчетов, ни запросов данных графиков и потока данных - только, по факту, запрос данных ТТТ из терминала.
Проверяем как это терминал переваривает, если таких скриптов несколько. Такое на 7-ой версии терминала даже не вызывало вопросов.
Да стаканы читать тяжело. Но выводить все в таблицы если это робот то это избыточно. --------------------- Относительно индикатора регрессии считаю в скользящем окне. Этот индикатор лучше чем мувинги.
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
24.07.2026 12:10:04
что-то тест уж больно большой. Трудно проверить что же он все таки проверяет
Влияние колбэков на производительность
Пользователь
Сообщений: Регистрация: 30.01.2015
23.07.2026 17:19:47
У вас все таки колбеки не пустые
Код
if alltrade.class_code ~= class or alltrade.sec_code ~= sec then return end
либо поставьте измерение времени этого оператора и вычитайте либо действительно поставьте пустой колбек Иначе эксперимент не чистый
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
23.07.2026 17:15:05
Для себя сделал вывод. Разработчики еще 25 лет назад честно написали QUIK - это для подачи заявок брокеру вместо телефона. Они честно сказали и честно это соблюдают. ------------------------------- QUIK - не для написания роботв а для подачи заявок и получения информации с биржи ------------------------------- Роботов надо писать в отдельных приложениях или хотя бы в отдельных потоках с одноразовым вызовом колбеков и по возможности без графиков
написал: можете сделать вывод времени входа и выхода для колбеков и для main c помощью точного счетчик Windows?
Если без излишеств, просто через os.clock, то сами колбеки работаю микросекунды. main уже зависит о того, что делает, но там тоже не что-то существенное.
Я пока наблюдаю странное - подключаешь несколько библиотек на 1000 функций - и привет. Собственно это в тесте и сделано, чтобы проверить влияние этого. Я, конечно, понимаю, что Lua - не тот язык в котором обычно пишутся модули на тысячи строк, но как-то я не встречал упоминаний о влиянии этого на производительность. Хотя если вспомнить World of Warcraft, то ему не мешает.
Пришлось разбираться, т.к. в последних версиях терминала стало всё очень медленно если запущены "большие" скрипты, банально вкладки переключаются со скрипом. Пальцем в небо - что-то сделали с GC. У меня функции использую локальные переменные, а функций много. В итоге GC надо работать. Как он работает в Квике не знаю, но надеюсь, что независимо от основного потока.
Впрочем, приведённый нагрузочный тест не делает ничего такого, чтобы сильно потреблять память, а падение производительности есть.
Наблюдал такой прикол ставишь индикатора регрессии на большой истории и привет ждешь старта квик очень долго. На демо все быстро потому что там история маленькая.
Задать время снятия заявки программно при выставлении sendtransaction, Задать время снятия заявки программно при выставлении sendtransaction
Пользователь
Сообщений: Регистрация: 30.01.2015
21.07.2026 05:28:04
Цитата
Игорь_С написал: Попробовал, к сожалению не работает. Заявка выставляется без указанных параметров. Может быть поддержка подскажет?
проверьте формат параметров. Все параметры транзакции должны быть строками. Часто вместо строк ставят числа
‘Вы уже работаете в системе’ + ‘Соединение установить не удалось’, Проблема с соединением
Пользователь
Сообщений: Регистрация: 30.01.2015
21.07.2026 05:25:34
Цитата
Игорь С написал: Когда выдаются сообщения ‘Вы уже работаете в системе’ + ‘Соединение установить не удалось’, команда TELNET с адресом сервера и номером порта выполняется без ошибок (как описано в инструкции). История продолжается. Вероятно, придется смириться и терпеть. Всем спасибо!
если включено автоматическое восстановление связи то просто ждите и все восстановится минуты через 3-5
Работа колбеков
Пользователь
Сообщений: Регистрация: 30.01.2015
21.07.2026 05:21:52
можете сделать вывод времени входа и выхода для колбеков и для main c помощью точного счетчик Windows?