<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>Форум QUIK [тема: Использование мессенджера MAX  для обмена данными в QUIK]</title>
		<link>http://forum.quik.ru</link>
		<description>Новое в теме Использование мессенджера MAX  для обмена данными в QUIK форума  на сайте Форум QUIK [forum.quik.ru]</description>
		<language>ru</language>
		<docs>http://backend.userland.com/rss2</docs>
		<pubDate>Tue, 03 Nov 2026 13:00:46 +0300</pubDate>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83195/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Еще один вариант. <br />Особо не отлаживал. <br />Выкладываю как есть:
====code====
<pre>-- max_bridge.lua
-- Двусторонний мост QUIK &#60;-&#62; MAX Messenger
-- Lua 5.3/5.4: native bitwise, //, math.tointeger, &#60;const&#62;
-- Очереди: T={{},0,0} — массив + jw/jr, сброс в push

local MAX = {}

--========== КОНФИГУРАЦИЯ ==========--
MAX.TOKEN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "ВАШ_ТОКЕН"
MAX.API_URL&nbsp;&nbsp;&nbsp;&nbsp; = "https://platform-api2.max.ru"
MAX.CHAT_ID&nbsp;&nbsp;&nbsp;&nbsp; = nil
MAX.LAST_MARKER = 0

MAX.LAST_SEND&nbsp;&nbsp; = 0.0
MAX.LAST_POLL&nbsp;&nbsp; = 0.0
MAX.ERR_COUNT&nbsp;&nbsp; = 0
MAX.HTTP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= nil

local luacom_ok, luacom = pcall(require, "luacom")

local MSG_GAP&nbsp;&nbsp;&nbsp;&nbsp;&#60;const&#62; = 2.0
local POLL_GAP&nbsp;&nbsp; &#60;const&#62; = 2.0
local ONIDLE_RET &#60;const&#62; = 200

local F_ACTIVE &#60;const&#62; = 1
local F_SELL&nbsp;&nbsp; &#60;const&#62; = 4

--========== ОЧЕРЕДИ ==========--
-- T = { buf, jr, jw }
-- T&#91;1&#93; — массив данных
-- T&#91;2&#93; — указатель чтения (jr)
-- T&#91;3&#93; — указатель записи (jw)
-- При jr == jw (очередь пуста) — сброс в 0, следующая запись в buf&#91;1&#93;

local function setQ(T, X)
&nbsp;&nbsp;&nbsp;&nbsp;local jw = T&#91;3&#93;
&nbsp;&nbsp;&nbsp;&nbsp;if T&#91;2&#93; == jw then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jw = 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T&#91;2&#93; = 0
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;jw = jw + 1
&nbsp;&nbsp;&nbsp;&nbsp;T&#91;1&#93;&#91;jw&#93; = X
&nbsp;&nbsp;&nbsp;&nbsp;T&#91;3&#93; = jw
end

local function getQ(T)
&nbsp;&nbsp;&nbsp;&nbsp;local jr = T&#91;2&#93;
&nbsp;&nbsp;&nbsp;&nbsp;if T&#91;3&#93; &#62; jr then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jr = jr + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T&#91;2&#93; = jr
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return T&#91;1&#93;&#91;jr&#93;
&nbsp;&nbsp;&nbsp;&nbsp;end
end

local function qsize(T)
&nbsp;&nbsp;&nbsp;&nbsp;return T&#91;3&#93; - T&#91;2&#93;
end

MAX.INCOMING = {{}, 0, 0}
MAX.OUTGOING = {{}, 0, 0}

--========== ТАБЛИЦЫ КОДИРОВАНИЯ/ДЕКОДИРОВАНИЯ ==========--

local escape_map &#60;const&#62; = {
&nbsp;&nbsp;&nbsp;&nbsp;&#91;92&#93;&nbsp;&nbsp;= '&#92;&#92;&#92;&#92;',&nbsp;&nbsp;-- &#92;&nbsp;&nbsp;&#62; &#92;&#92;
&nbsp;&nbsp;&nbsp;&nbsp;&#91;34&#93;&nbsp;&nbsp;= '&#92;&#92;"',&nbsp;&nbsp; -- "&nbsp;&nbsp;&#62; &#92;"
&nbsp;&nbsp;&nbsp;&nbsp;&#91;10&#93;&nbsp;&nbsp;= '&#92;&#92;n',&nbsp;&nbsp; -- &#92;n &#62; &#92;n
&nbsp;&nbsp;&nbsp;&nbsp;&#91;13&#93;&nbsp;&nbsp;= '&#92;&#92;r',&nbsp;&nbsp; -- &#92;r &#62; &#92;r
&nbsp;&nbsp;&nbsp;&nbsp;&#91;9&#93;&nbsp;&nbsp; = '&#92;&#92;t',&nbsp;&nbsp; -- &#92;t &#62; &#92;t
}

local unescape_map &#60;const&#62; = {
&nbsp;&nbsp;&nbsp;&nbsp;&#91;110&#93; = '&#92;n',&nbsp;&nbsp;&nbsp;&nbsp;-- n&nbsp;&nbsp;&#62; &#92;n
&nbsp;&nbsp;&nbsp;&nbsp;&#91;114&#93; = '&#92;r',&nbsp;&nbsp;&nbsp;&nbsp;-- r&nbsp;&nbsp;&#62; &#92;r
&nbsp;&nbsp;&nbsp;&nbsp;&#91;116&#93; = '&#92;t',&nbsp;&nbsp;&nbsp;&nbsp;-- t&nbsp;&nbsp;&#62; &#92;t
&nbsp;&nbsp;&nbsp;&nbsp;&#91;34&#93;&nbsp;&nbsp;= '"',&nbsp;&nbsp;&nbsp;&nbsp; -- "&nbsp;&nbsp;&#62; "
&nbsp;&nbsp;&nbsp;&nbsp;&#91;92&#93;&nbsp;&nbsp;= '&#92;&#92;',&nbsp;&nbsp;&nbsp;&nbsp;-- &#92;&nbsp;&nbsp;&#62; &#92;
&nbsp;&nbsp;&nbsp;&nbsp;&#91;47&#93;&nbsp;&nbsp;= '/',&nbsp;&nbsp;&nbsp;&nbsp; -- /&nbsp;&nbsp;&#62; /
}

--========== КОДИРОВАНИЕ (escape) ==========--

local function json_escape(s)
&nbsp;&nbsp;&nbsp;&nbsp;local res, j = {}, 0
&nbsp;&nbsp;&nbsp;&nbsp;for i = 1, #s do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local b = s:byte(i)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local rep = escape_map&#91;b&#93;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if rep then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res&#91;j&#93; = rep
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res&#91;j&#93; = s:sub(i, i)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;return table.concat(res)
end

--========== ДЕКОДИРОВАНИЕ (JSON-парсер) ==========--

local J = { s = "", p = 1 }

local j_skip, j_val
j_skip = function()
&nbsp;&nbsp;&nbsp;&nbsp;while J.p &#60;= #J.s do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local c = J.s:byte(J.p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if c == 32 or c == 9 or c == 10 or c == 13 then J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else break end
&nbsp;&nbsp;&nbsp;&nbsp;end
end

j_val = function()
&nbsp;&nbsp;&nbsp;&nbsp;j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;local c = J.s:byte(J.p)
&nbsp;&nbsp;&nbsp;&nbsp;if c == 34 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local buf, i = {}, 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while J.p &#60;= #J.s do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local ch = J.s:byte(J.p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ch == 92 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local n = J.s:byte(J.p + 1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local rep = unescape_map&#91;n&#93;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if rep then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf&#91;i + 1&#93; = rep
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf&#91;i + 1&#93; = J.s:sub(J.p + 1, J.p + 1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i = i + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 2
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif ch == 34 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return table.concat(buf)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf&#91;i + 1&#93; = J.s:sub(J.p, J.p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i = i + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return table.concat(buf)
&nbsp;&nbsp;&nbsp;&nbsp;elseif c == 123 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 1; j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local obj = {}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if J.s:byte(J.p) == 125 then J.p = J.p + 1 return obj end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while true do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local key = j_val()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if J.s:byte(J.p) == 58 then J.p = J.p + 1 end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj&#91;key&#93; = j_val()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local sep = J.s:byte(J.p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if sep == 44 then J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif sep == 125 then J.p = J.p + 1 break
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else break end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return obj
&nbsp;&nbsp;&nbsp;&nbsp;elseif c == 91 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 1; j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local arr = {}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if J.s:byte(J.p) == 93 then J.p = J.p + 1 return arr end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while true do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr&#91;#arr + 1&#93; = j_val()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j_skip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local sep = J.s:byte(J.p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if sep == 44 then J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif sep == 93 then J.p = J.p + 1 break
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else break end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return arr
&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local start = J.p
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while J.p &#60;= #J.s do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local b = J.s:byte(J.p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if b == 32 or b == 9 or b == 10 or b == 13
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; or b == 44 or b == 125 or b == 93 then break end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;J.p = J.p + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local v = J.s:sub(start, J.p - 1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if v == "true" then return true
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif v == "false" then return false
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif v == "null" then return nil
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else return tonumber(v) or v end
&nbsp;&nbsp;&nbsp;&nbsp;end
end

local function json_parse(str)
&nbsp;&nbsp;&nbsp;&nbsp;J.s = str; J.p = 1
&nbsp;&nbsp;&nbsp;&nbsp;return j_val()
end

--========== HTTP ==========--

local function http(method, url, body)
&nbsp;&nbsp;&nbsp;&nbsp;if not MAX.HTTP then return nil, 0 end
&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:Open(method, url, false)
&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:SetRequestHeader("Authorization", MAX.TOKEN)
&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:SetRequestHeader("Accept", "application/json")
&nbsp;&nbsp;&nbsp;&nbsp;if body then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:SetRequestHeader("Content-Type", "application/json")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:Send(body)
&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:Send()
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;return MAX.HTTP.ResponseText, MAX.HTTP.Status
end

local function raw_send(msg, chat_id, nFormat)
&nbsp;&nbsp;&nbsp;&nbsp;chat_id = chat_id or MAX.CHAT_ID
&nbsp;&nbsp;&nbsp;&nbsp;if not chat_id then return false end
&nbsp;&nbsp;&nbsp;&nbsp;chat_id = math.tointeger(chat_id) or chat_id

&nbsp;&nbsp;&nbsp;&nbsp;local fmt = ""
&nbsp;&nbsp;&nbsp;&nbsp;if nFormat == 1 then fmt = ',"format":"html"'
&nbsp;&nbsp;&nbsp;&nbsp;elseif nFormat == 2 then fmt = ',"format":"markdown"' end
&nbsp;&nbsp;&nbsp;&nbsp;local body = '{"text":"' .. json_escape(msg) .. '"' .. fmt .. '}'
&nbsp;&nbsp;&nbsp;&nbsp;local url&nbsp;&nbsp;= MAX.API_URL .. "/messages?chat_id=" .. tostring(chat_id)
&nbsp;&nbsp;&nbsp;&nbsp;local resp, status = http("POST", url, body)
&nbsp;&nbsp;&nbsp;&nbsp;if status == 200 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.ERR_COUNT = 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;MAX.ERR_COUNT = MAX.ERR_COUNT + 1
&nbsp;&nbsp;&nbsp;&nbsp;if MAX.ERR_COUNT &#60;= 3 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("MAX: " .. tostring(status) .. " " .. tostring(resp):sub(1, 150), 3)
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;return false
end

--========== ПУБЛИЧНЫЙ API ==========--

function SendToMAX(msg, chat_id, nFormat)
&nbsp;&nbsp;&nbsp;&nbsp;setQ(MAX.OUTGOING, { m = msg, c = chat_id, f = nFormat or 0 })
end

--========== POLLING ==========--

local function poll()
&nbsp;&nbsp;&nbsp;&nbsp;local url = MAX.API_URL .. "/updates?marker=" .. tostring(MAX.LAST_MARKER)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .. "&#38;timeout=0"
&nbsp;&nbsp;&nbsp;&nbsp;local resp, status = http("GET", url, nil)
&nbsp;&nbsp;&nbsp;&nbsp;if status ~= 200 or not resp then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.ERR_COUNT = MAX.ERR_COUNT + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;MAX.ERR_COUNT = 0
&nbsp;&nbsp;&nbsp;&nbsp;local data = json_parse(resp)
&nbsp;&nbsp;&nbsp;&nbsp;if not data then return end

&nbsp;&nbsp;&nbsp;&nbsp;if data.marker then MAX.LAST_MARKER = data.marker end
&nbsp;&nbsp;&nbsp;&nbsp;if not data.updates then return end

&nbsp;&nbsp;&nbsp;&nbsp;for _, upd in ipairs(data.updates) do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local utype = upd.update_type

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if utype == "bot_started" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if upd.chat and upd.chat.chat_id then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.CHAT_ID = math.tointeger(upd.chat.chat_id) or upd.chat.chat_id
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("MAX: chat_id = " .. tostring(MAX.CHAT_ID))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendToMAX("? Связь установлена. /help — список команд", nil, 2)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif utype == "message_created" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local msg = upd.message
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if not msg then goto next_upd end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if msg.recipient and msg.recipient.chat_id then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.CHAT_ID = math.tointeger(msg.recipient.chat_id) or msg.recipient.chat_id
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local text = msg.body and msg.body.text or ""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setQ(MAX.INCOMING, text)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("MAX &#60; " .. text)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::next_upd::
&nbsp;&nbsp;&nbsp;&nbsp;end
end

--========== ДИСПЕТЧЕР ==========--

local function dispatch()
&nbsp;&nbsp;&nbsp;&nbsp;local now = os.clock()
&nbsp;&nbsp;&nbsp;&nbsp;if now - MAX.LAST_SEND &#60; MSG_GAP then return end

&nbsp;&nbsp;&nbsp;&nbsp;-- Приоритет: исходящие
&nbsp;&nbsp;&nbsp;&nbsp;if qsize(MAX.OUTGOING) &#62; 0 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local item = getQ(MAX.OUTGOING)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if raw_send(item.m, item.c, item.f) then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.LAST_SEND = os.clock()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;-- Затем: подтверждение входящего
&nbsp;&nbsp;&nbsp;&nbsp;if qsize(MAX.INCOMING) &#62; 0 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local text = getQ(MAX.INCOMING)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local reply = MAX.build_reply(text)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if raw_send(reply, nil, 2) then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.LAST_SEND = os.clock()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;end
end

--========== ОБРАБОТКА КОМАНД ==========--

function MAX.build_reply(text)
&nbsp;&nbsp;&nbsp;&nbsp;if not text then return "/help — список команд" end
&nbsp;&nbsp;&nbsp;&nbsp;local cmd = text:lower():gsub("^%s+", ""):gsub("%s+$", "")

&nbsp;&nbsp;&nbsp;&nbsp;if cmd == "/help" or cmd == "помощь" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return "Команды:&#92;n/status — состояние&#92;n/positions — позиции&#92;n/orders — заявки&#92;n/trades — последние сделки&#92;n/help — список"

&nbsp;&nbsp;&nbsp;&nbsp;elseif cmd == "/status" or cmd == "статус" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return "QUIK работает. " .. os.date("%Y-%m-%d %H:%M:%S")

&nbsp;&nbsp;&nbsp;&nbsp;elseif cmd == "/positions" or cmd == "позиции" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local lines, n = {}, 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for i = 0, getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local p = getItem("FUTURES_CLIENT_HOLDING", i)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if p and p.openqty ~= 0 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n = n + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local qty = math.abs(math.tointeger(p.openqty) or tonumber(p.openqty) or 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local vm&nbsp;&nbsp;= tonumber(p.varmargin) or 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lines&#91;n&#93; = string.format("%s **%s** %d шт, вм %.2f",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.openqty &#62; 0 and "Лонг" or "Шорт",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tostring(p.sec_code), qty, vm)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return n == 0 and "Нет позиций." or table.concat(lines, "&#92;n")

&nbsp;&nbsp;&nbsp;&nbsp;elseif cmd == "/orders" or cmd == "заявки" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local lines, n = {}, 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for i = 0, getNumberOf("ORDERS") - 1 do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local o = getItem("ORDERS", i)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if o and (o.flags &#38; F_ACTIVE) ~= 0 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n = n + 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local qty = math.tointeger(o.qty) or tonumber(o.qty) or 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local price = tonumber(o.price) or 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lines&#91;n&#93; = string.format("%s **%s** %d @ %.2f",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(o.flags &#38; F_SELL) ~= 0 and "Прод" or "Покуп",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tostring(o.sec_code), qty, price)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return n == 0 and "Нет заявок." or table.concat(lines, "&#92;n")

&nbsp;&nbsp;&nbsp;&nbsp;elseif cmd == "/trades" or cmd == "сделки" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local lines = {}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local total = getNumberOf("TRADES")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local start = total &#62; 5 and total - 5 or 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for i = start, total - 1 do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local t = getItem("TRADES", i)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if t then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local qty = math.tointeger(t.qty) or tonumber(t.qty) or 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local price = tonumber(t.price) or 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lines&#91;#lines + 1&#93; = string.format("%s **%s** %d @ %.2f",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(t.flags &#38; F_SELL) ~= 0 and "Прод" or "Покуп",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tostring(t.sec_code), qty, price)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return #lines == 0 and "Сделок нет."
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; or "Последние:&#92;n" .. table.concat(lines, "&#92;n")

&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return "Получено: " .. text .. "&#92;n/help — список команд"
&nbsp;&nbsp;&nbsp;&nbsp;end
end

--========== CALLBACKS QUIK ==========--

function OnInit()
&nbsp;&nbsp;&nbsp;&nbsp;if not luacom_ok then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("MAX Bridge: luacom не найден!", 3)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP = luacom.CreateObject("WinHttp.WinHttpRequest.5.1")
&nbsp;&nbsp;&nbsp;&nbsp;if MAX.HTTP then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP:SetTimeouts(3000, 3000, 5000, 5000)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("MAX Bridge: запущен. Lua " .. _VERSION .. ". Ожидание /start...")
&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("MAX Bridge: WinHttpRequest не создан!", 3)
&nbsp;&nbsp;&nbsp;&nbsp;end
end

function OnIdle()
&nbsp;&nbsp;&nbsp;&nbsp;if not MAX.HTTP then return 1000 end

&nbsp;&nbsp;&nbsp;&nbsp;local now = os.clock()

&nbsp;&nbsp;&nbsp;&nbsp;local interval = POLL_GAP
&nbsp;&nbsp;&nbsp;&nbsp;if MAX.ERR_COUNT &#62; 3 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;interval = POLL_GAP * (MAX.ERR_COUNT &#60; 10 and MAX.ERR_COUNT or 10)
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;if now - MAX.LAST_POLL &#62;= interval then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAX.LAST_POLL = now
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll()
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;dispatch()

&nbsp;&nbsp;&nbsp;&nbsp;return ONIDLE_RET
end

function OnStop()
&nbsp;&nbsp;&nbsp;&nbsp;local out_n = qsize(MAX.OUTGOING)
&nbsp;&nbsp;&nbsp;&nbsp;local inc_n = qsize(MAX.INCOMING)
&nbsp;&nbsp;&nbsp;&nbsp;if MAX.CHAT_ID then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if out_n + inc_n &#62; 0 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raw_send(string.format(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"?? MAX Bridge остановлен. В очередях: %d исх, %d вх.",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out_n, inc_n), nil, 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raw_send("?? MAX Bridge остановлен.", nil, 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;MAX.HTTP = nil
&nbsp;&nbsp;&nbsp;&nbsp;return 1000
end

function OnTrade(trade)
&nbsp;&nbsp;&nbsp;&nbsp;local is_sell = (trade.flags &#38; F_SELL) ~= 0
&nbsp;&nbsp;&nbsp;&nbsp;local qty&nbsp;&nbsp; = math.tointeger(trade.qty) or tonumber(trade.qty) or 0
&nbsp;&nbsp;&nbsp;&nbsp;local price = tonumber(trade.price) or 0
&nbsp;&nbsp;&nbsp;&nbsp;SendToMAX(string.format("?? %s **%s** %d @ %.2f",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is_sell and "Прод" or "Покуп",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tostring(trade.sec_code), qty, price), nil, 2)
end
--&#91;&#91;
Инструкция: мост QUIK - MAX
Шаг 1. Создание бота в MAX
Откройте MAX на смартфоне, найдите бота Masterbot (или через бизнес-кабинет , если есть юрлицо/ИП).
Создайте нового бота, получите токен — длинная строка вида f9LHodD0cOIq...0BhMw0gm_6f1-DBY.
Напишите боту команду /start — это нужно, чтобы бот «увидел» вас и скрипт позже сможет подхватить ваш chat_id.

Шаг 2. Установка скрипта в QUIK
Откройте скрипт в любом текстовом редакторе (Блокнот, Notepad++).
Найдите строку MAX.TOKEN = "ВАШ_ТОКЕН" и вставьте свой токен.
Сохраните файл, например, max_bridge.lua.
В QUIK: меню Сервис &#62; Lua-скрипты (или Ctrl+I).
Нажмите Добавить, выберите max_bridge.lua.
Нажмите Запустить.
В окне сообщений QUIK должно появиться: MAX Bridge: запущен. Lua 5.x. Ожидание /start...

Шаг 3. Подключение смартфона
Откройте MAX на телефоне, найдите своего бота.
Отправьте ему команду /start.
Скрипт перехватит событие bot_started, запомнит ваш chat_id и пришлёт ответ: ? Связь установлена. /help — список команд.
Всё — двусторонняя связь работает.

Шаг 4. Команды с телефона
Отправляйте боту в MAX:

Команда&nbsp;&nbsp;&nbsp;Что делает
/help&nbsp;&nbsp;&nbsp;Список всех команд
/status&nbsp;&nbsp;&nbsp;Состояние QUIK, дата/время
/positions&nbsp;&nbsp;&nbsp;Открытые фьючерсные позиции
/orders&nbsp;&nbsp;&nbsp;Активные заявки
/trades&nbsp;&nbsp;&nbsp;Последние 5 сделок
Шаг 5. Отправка сообщений из QUIK
Скрипт регистрирует глобальную функцию SendToMAX().
Любой другой Lua-скрипт в QUIK может вызывать её для отправки уведомлений на телефон:

lua
-- Простой текст (без разметки)
SendToMAX("Сигнал: RTS пробил 100000")

-- Текст с разметкой Markdown (формат 2)
SendToMAX("**Внимание!** Цена `GAZP` упала ниже 200", nil, 2)

-- Текст с разметкой HTML (формат 1)
SendToMAX("&#60;b&#62;Внимание!&#60;/b&#62; Цена GAZP упала ниже 200", nil, 1)

-- Отправка в конкретный чат (если chat_id известен)
SendToMAX("Личное сообщение", 117000000474, 0)
Форматы:

0 — без разметки (по умолчанию)
1 — HTML (&#60;b&#62;жирный&#60;/b&#62;, &#60;i&#62;курсив&#60;/i&#62;)
2 — Markdown (**жирный**, _курсив_, `моноширинный`)
Все сообщения попадают в очередь и отправляются не чаще одного в 2 секунды — лимит MAX не нарушается.

Шаг 6. Автоматические уведомления
Скрипт уже содержит обработчик OnTrade — при каждой сделке в QUIK на телефон автоматически уходит уведомление:

text
?? Прод **RIZ5** 5 @ 105250.00
?? Покуп **GAZP** 100 @ 198.50
Чтобы добавить свои триггеры, допишите в скрипт или в отдельный файл:

lua
-- Пример: уведомление при изменении цены
function OnQuote(class_code, sec_code)
&nbsp;&nbsp;&nbsp;&nbsp;if sec_code == "RIZ5" then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local ql = getQuoteLevel2(class_code, sec_code)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ql and #ql.bid &#62; 0 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local bid_price = tonumber(ql.bid&#91;#ql.bid&#93;.price)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if bid_price and bid_price &#62; 105000 then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendToMAX("RIZ5 выше 105000! Текущая bid: " .. bid_price, nil, 2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;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.
--&#93;&#93;

</pre>
============= <br />
			<i>20.09.2026 07:27:51, nikolz.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83195/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83195/topic9637/</guid>
			<pubDate>Sun, 20 Sep 2026 07:27:51 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83193/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_71bRISlS" href="/user/62/" bx-tooltip-user-id="62">nikolz</a> написал:<br /> <br />====quote====<br /><noindex><a href="/user/13937/" target="_blank" rel="nofollow">Евгений</a></noindex> написал:<br />Поскольку , эта тема вроде нигде не поднималась , опишу свой опыт , может быть будет кому то полезно.<br />Для информирования и &nbsp;контроля за работой торгового привода у меня был поднят небольшой &nbsp; саит на локальном компе с QUIK ,и меня все &nbsp;устраивало,<br />Сейчас эта схема практически утратила смысл из за почти постоянного отключения мобильного интернета. Я решил &nbsp;посмотреть &nbsp;, что можно использовать взамен. &nbsp;Нормально работали только саиты из белого списка и MAX. &nbsp;Поскольку других вариантов &nbsp;не было , выбор пал на MAX ,<br /> 
====code====
<pre>&nbsp;&nbsp;&nbsp;&nbsp;</pre>
=============
 &nbsp;<br />=============<br /> Странно, если мобильный интернет не работает то и МАХ не должен работать. <br />скорее всего не работал DNS cервер, поэтому не могли найти IP адрес<br />----------------------------<br />из моего опыта . <br />Кратко.<br />можно не делать сайт ,<br />а создать сервер на локальном компьютере там же где квик &nbsp; <br />Потом сообщить на смартфон IP адрес своего локального компа ,<br />у которого есть выход в интернет. <br />Будете работать напрямую со своим сервером. <br />------------------------------<br />Еще варианты прокси или VPN &nbsp;можно бесплатные<br />=============<br />Мобильный интернет то работает , только &nbsp;ничего &nbsp;кроме max , &nbsp;приложений некоторых банков и мир pay не открывается. &nbsp;Когда объявлена беспилотная опасность , то все кроме белого списка блокируется наглухо. А у нас в краснодарском крае эта опасность объявлена почти &nbsp;постоянно .Может на счет сайта я &nbsp;не совсем точно выразился . У меня &nbsp;работает локально на компе с квиком web сервис +корпоративный open vpn &nbsp;, так как выделено ip у меня нет &nbsp;. &nbsp; <br />
			<i>18.09.2026 11:21:15, Евгений.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83193/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83193/topic9637/</guid>
			<pubDate>Fri, 18 Sep 2026 11:21:15 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83191/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_ySp9Feey" href="/user/13937/" bx-tooltip-user-id="13937">Евгений</a> написал:<br />Поскольку , эта тема вроде нигде не поднималась , опишу свой опыт , может быть будет кому то полезно.<br />Для информирования и &nbsp;контроля за работой торгового привода у меня был поднят небольшой &nbsp; саит на локальном компе с QUIK ,и меня все &nbsp;устраивало,<br />Сейчас эта схема практически утратила смысл из за почти постоянного отключения мобильного интернета. Я решил &nbsp;посмотреть &nbsp;, что можно использовать взамен. &nbsp;Нормально работали только саиты из белого списка и MAX. &nbsp;Поскольку других вариантов &nbsp;не было , выбор пал на MAX ,<br />
====code====
<pre>
</pre>
=============
 <br />=============<br />Странно, если мобильный интернет не работает то и МАХ не должен работать. <br />скорее всего не работал DNS cервер, поэтому не могли найти IP адрес<br />----------------------------<br />из моего опыта . <br />Кратко.<br />можно не делать сайт ,<br />а создать сервер на локальном компьютере там же где квик &nbsp; <br />Потом сообщить на смартфон IP адрес своего локального компа ,<br />у которого есть выход в интернет. <br />Будете работать напрямую со своим сервером. <br />------------------------------<br />Еще варианты прокси или VPN &nbsp;можно бесплатные <br />
			<i>18.09.2026 09:31:48, nikolz.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83191/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83191/topic9637/</guid>
			<pubDate>Fri, 18 Sep 2026 09:31:48 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83188/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Еще раз благодарю Вас за пример и просвещение. Меня собственно заинтересовало, возможность получить дополнительный вывод. &nbsp;Для не большого скрипта &nbsp;- стохастический генератор Monte Carlo generator (WinRate + ProfitFactor &nbsp;Lua 5.4). Используемый для проверки гипотезы. &nbsp;Но мне нужен переход от генератора результатов к симулятору позиции. <br />Отличие принципиальное:<br />Mодель генератора: &nbsp;Trade -&gt; Result <br />Новая: &nbsp;State(t) -&gt; Price \ Path -&gt; Position &nbsp;-&gt; Exit &nbsp;-&gt; Capital. То есть сделка становится процессом, а не точкой. Ну и соответственно вывод со сменой входящих параметров. <br />Надеюсь не запутал? Подходит под подобную задачу? <br />
			<i>16.09.2026 18:40:47, VPM.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83188/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83188/topic9637/</guid>
			<pubDate>Wed, 16 Sep 2026 18:40:47 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83187/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_l5OSjZlq" href="/user/16131/" bx-tooltip-user-id="16131">VPM</a> написал:<br />То есть если я правильно понимаю, контроль за роботом (Вашей самопиской) в окне МАХ? А во сколько можно оценить потерю во времени прохождения команды? Ну хотя бы примерно ведь наверно задавались данным вопросом. Если можно продемонстрируйте картинкой.<br />=============<br />У &nbsp;ботов от макс &nbsp;есть 2 варианта обмена &nbsp; основной - через Webhook &nbsp; и Long Polling . &nbsp;Long Polling - это что то типа временной заглушки для тестирования.<br />Я использую &nbsp;Long Polling . В цикле MAIN quik а раз в 5 секунд &nbsp;выполняю опрос бота , разбираю ответ и выполняю принятые команды и отсылаю результат в чат &nbsp;, если требуется. Получается на ответ от 6 до 7 секунд.Через Webhook можно сделать быстрее &nbsp;, но там надо намного больше заморачиваться. Читайте &nbsp; <noindex><a href="https://dev.max.ru/docs-api/methods/GET/updates" target="_blank" rel="nofollow">API max</a></noindex> &nbsp;, если есть желание разобраться подробнее. &nbsp; &nbsp; <br />
			<img src="https://forum.quik.ru/bitrix/components/bitrix/forum.interface/show_file.php?fid=13480&" width="616" height="786" /><br /><i>16.09.2026 18:13:46, Евгений.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83187/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83187/topic9637/</guid>
			<pubDate>Wed, 16 Sep 2026 18:13:46 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83185/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			То есть если я правильно понимаю, контроль за роботом (Вашей самопиской) в окне МАХ? А во сколько можно оценить потерю во времени прохождения команды? Ну хотя бы примерно ведь наверно задавались данным вопросом. Если можно продемонстрируйте картинкой. <br />
			<i>16.09.2026 17:31:47, VPM.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83185/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83185/topic9637/</guid>
			<pubDate>Wed, 16 Sep 2026 17:31:47 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83184/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			<br />====quote====<br /><a class="blog-p-user-name" id="bp_9fX4E6D4" href="/user/16131/" bx-tooltip-user-id="16131">VPM</a> написал:<br />Спасибо,<noindex><a href="/user/13937/" target="_blank" rel="nofollow">Евгений</a></noindex>, для тех кто не в теме и для меня лично, поясните, а зачем все эти премудрости? Что это дает? и А каком приводе идет речь, типа Бондаря для скальпинга?<br />=============<br />Вы же не можете сидеть безвылазно перед компьютером с quik ом .Нужно отлучаться &nbsp;по делам или на &nbsp;работу или на отдых. И хочется контролировать работу робота , иногда &nbsp;поменять стратегию &nbsp;, или вообще остановить в случае форс мажора или поднастроить немного. Посмотреть &nbsp;отчет по сделкам , по состоянию депо и.т.п. &nbsp;Для таких же целей банки делают свои приложения на смартфоны &nbsp;. А привод в данной теме речи не играет. У меня своя самомиска для торговли на спредах &nbsp;на облигациях.<br />====quote====<br /><br /><br />=============<br /> <br />
			<i>16.09.2026 17:24:12, Евгений.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83184/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83184/topic9637/</guid>
			<pubDate>Wed, 16 Sep 2026 17:24:12 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83183/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Спасибо,<a class="blog-p-user-name" id="bp_ZmiVLymQ" href="/user/13937/" bx-tooltip-user-id="13937">Евгений</a>, для тех кто не в теме и для меня лично, поясните, а зачем все эти премудрости? Что это дает? и А каком приводе идет речь, типа Бондаря для скальпинга? <br />
			<i>16.09.2026 16:52:24, VPM.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83183/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83183/topic9637/</guid>
			<pubDate>Wed, 16 Sep 2026 16:52:24 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
		<item>
			<title>Использование мессенджера MAX  для обмена данными в QUIK</title>
			<description><![CDATA[<b><a href="http://forum.quik.ru/messages/forum10/message83179/topic9637/">Использование мессенджера MAX  для обмена данными в QUIK</a></b> <i>Использование  мессенджер для обмена для отправки сообщений и управление торговым приводом в QUIK</i> в форуме <a href="http://forum.quik.ru/forum10/">Программирование на языке Lua</a>. <br />
			Поскольку , эта тема вроде нигде не поднималась , опишу свой опыт , может быть будет кому то полезно.<br />Для информирования и &nbsp;контроля за работой торгового привода у меня был поднят небольшой &nbsp; саит на локальном компе с QUIK ,и меня все &nbsp;устраивало,<br />Сейчас эта схема практически утратила смысл из за почти постоянного отключения мобильного интернета. Я решил &nbsp;посмотреть &nbsp;, что можно использовать взамен. &nbsp;Нормально работали только саиты из белого списка и MAX. &nbsp;Поскольку других вариантов &nbsp;не было , выбор пал на MAX ,<br />И так , что же мог предложить MAX для решения этой задачи ? &nbsp; &nbsp;В MAX можно создавать чат боты , но делать это могут только OOO ,ИП и самозанятые.<br />Я давно имею статус самозанятого , а для тех кто его не имеет , получить его можно онлаин за 5 минут и этот статус ни к чему не обязывает.<br />Для самозанятых MAx ставит ограничение в 2 чат бота. Мне хватило 1 бота, и 1 &nbsp;канала.<br />Я зашел в лк MAX (<noindex><a href="https://business.max.ru/self/services" target="_blank" rel="nofollow">https://business.max.ru/self/services</a></noindex> ) как самозанятый и зарегил бота , создал там же канал. &nbsp;Далее чат бота я сделал администратором канала.<br />В чат чат- бота я направил информационные сообщения от робота а в &nbsp;канале закрепил набор кнопок для &nbsp;отправки управляющих команд для торгового привода. &nbsp;Правда пришлось помучиться &nbsp;с вычислением идентификаторов каналов chat_id. Проще всего это сделать запустив web версию &nbsp;и взять эти id из URL &nbsp; (у чат бота это положительное число в конце URL , &nbsp;а у канала отрицательное).<br /><br />Привожу пример отправки сообщения в чат бот Max. <br />Для отправки HTTP сообщения я использовал c библиотеку &nbsp;luacom.dll +WinHttp.WinHttpRequest.5.1, но есть и много других способов (напимер curl)<br />
====code====
<pre>-----------------------------------&nbsp;&nbsp;
function send_max(msg,chat_id,access_token,nFormat)
&nbsp;&nbsp;&nbsp;-----------------------------------
&nbsp;&nbsp;&nbsp;---грузим luacom
&nbsp;&nbsp;&nbsp;luacom = require("luacom")
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;--для формата markdown
&nbsp;&nbsp;&nbsp;-- # Формат markdown &#92;n **жирный**, _курсив_, ~~зачёркнутый~~, ++подчёркнутый++, `моноширинный`&nbsp;&nbsp;,&nbsp;&nbsp;&nbsp;^^Выделенный^^ , &#91;Документация&#93;(https://dev.max.ru/) 
&nbsp;&nbsp;&nbsp;local url,status,responseText,cUser,body,cFormat,http
&nbsp;&nbsp;&nbsp;--chat_id =117.......474
 &nbsp;&nbsp;&nbsp;--access_token = "f9LHodD0cOIq...................0BhMw0gm_6f1-DBY" 
&nbsp;&nbsp;&nbsp;if not nFormat then 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nFormat=0
&nbsp;&nbsp;&nbsp;end 
&nbsp;&nbsp;&nbsp;---выбор формата разметки 
&nbsp;&nbsp;&nbsp;if nFormat==0 then 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--без формата 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cFormat=''
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif nFormat==1 then 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--HTML
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cFormat=&nbsp;&nbsp;&nbsp;',"format": "html"'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif nFormat==2 then 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--markdown
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cFormat=&nbsp;&nbsp;&nbsp;',"format": "markdown"'
&nbsp;&nbsp;&nbsp;end 
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;-- URL&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;url = "https://platform-api2.max.ru/messages?" .. "chat_id=" .. chat_id
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;--Тело запроса (JSON)
&nbsp;&nbsp;&nbsp;body ='{"text":"' .. msg .. '"'..cFormat..'}'
&nbsp;&nbsp;&nbsp;-- Создаём COM-объект
&nbsp;&nbsp;&nbsp;http = luacom.CreateObject("WinHttp.WinHttpRequest.5.1")
&nbsp;&nbsp;&nbsp;if&nbsp;&nbsp;http then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- Открываем соединение (синхронно)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http:Open("POST", url, false)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- Заголовки
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http:SetRequestHeader("Authorization", access_token)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http:SetRequestHeader("Content-Type", "application/json")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http:SetRequestHeader("Accept","application/json")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--Отправляем
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http:Send(body)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--Получаем ответ
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status = http.Status
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseText = http.ResponseText
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if http.Status==200 then 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;---ok
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message("Status: " ..&nbsp;&nbsp;tostring(status), 3)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message("Response: " ..&nbsp;&nbsp;tostring(responseText), 3)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- Освобождаем объект
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http = nil
&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message("Не удалось создать WinHttp.WinHttpRequest.5.1", 3)
&nbsp;&nbsp;&nbsp;end
end </pre>
============= <br />
			<i>16.09.2026 08:44:38, Евгений.</i>]]></description>
			<link>http://forum.quik.ru/messages/forum10/message83179/topic9637/</link>
			<guid>http://forum.quik.ru/messages/forum10/message83179/topic9637/</guid>
			<pubDate>Wed, 16 Sep 2026 08:44:38 +0300</pubDate>
			<category>Программирование на языке Lua</category>
		</item>
	</channel>
</rss>
