-- "Сколько сейчас Сбер" / "котировка газпром" — query MOEX ISS public API. local phrase = (jarvis.context.phrase or ""):lower() -- Common name → ticker map. local TICKERS = { ["сбер"] = "SBER", ["сбербанк"] = "SBER", ["газпром"] = "GAZP", ["лукойл"] = "LKOH", ["яндекс"] = "YDEX", ["yandex"] = "YDEX", ["вк"] = "VKCO", ["вконтакте"] = "VKCO", ["втб"] = "VTBR", ["магнит"] = "MGNT", ["мтс"] = "MTSS", ["роснефть"] = "ROSN", ["новатэк"] = "NVTK", ["норникель"] = "GMKN", ["норильск"] = "GMKN", ["полюс"] = "PLZL", ["тинькофф"] = "T", ["тбанк"] = "T", ["т банк"] = "T", ["сургутнефтегаз"] = "SNGS", ["мосбиржа"] = "MOEX", ["биржа"] = "MOEX", ["x5"] = "X5", ["икс пять"] = "X5", ["алроса"] = "ALRS", ["русал"] = "RUAL", ["мечел"] = "MTLR", ["фосагро"] = "PHOR", ["сегежа"] = "SGZH", ["белуга"] = "BELU", } -- find ticker local ticker, ticker_name for name, tk in pairs(TICKERS) do if phrase:find(name, 1, true) then ticker = tk ticker_name = name break end end -- Allow direct ticker mention "сколько SBER" etc. if not ticker then local maybe = phrase:upper():match("([A-Z][A-Z][A-Z]+)") if maybe then ticker = maybe; ticker_name = maybe end end if not ticker then jarvis.speak("Не понял какую бумагу. Скажите название.") jarvis.audio.play_error() return { chain = false } end local url = string.format( "https://iss.moex.com/iss/engines/stock/markets/shares/securities/%s.json?iss.meta=off", ticker ) local data = jarvis.http.json(url) if not data then jarvis.speak("Не получилось получить котировки.") jarvis.audio.play_error() return { chain = false } end -- MOEX ISS returns parallel arrays: columns + data rows. We want marketdata.LAST. local md = data.marketdata if not md or not md.columns or not md.data then jarvis.speak("Биржа вернула пустой ответ.") jarvis.audio.play_error() return { chain = false } end local cols = md.columns local rows = md.data -- find indexes local idx_last, idx_change, idx_board for i, c in ipairs(cols) do if c == "LAST" then idx_last = i end if c == "LASTTOPREVPRICE" then idx_change = i end if c == "BOARDID" then idx_board = i end end -- pick the TQBR (main board) row if present, else first non-nil LAST local last, change for _, row in ipairs(rows) do local board = idx_board and row[idx_board] if board == "TQBR" and row[idx_last] then last = row[idx_last] change = idx_change and row[idx_change] break end end if not last then for _, row in ipairs(rows) do if row[idx_last] then last = row[idx_last] change = idx_change and row[idx_change] break end end end if not last then jarvis.speak("По " .. ticker_name .. " сегодня нет торгов.") jarvis.audio.play_not_found() return { chain = false } end local rub = string.format("%.2f", last):gsub("%.", " и ") local line = string.format("%s — %s рубля.", ticker_name, rub) if change and tonumber(change) then local pct = tonumber(change) local sign = pct >= 0 and "плюс" or "минус" line = line .. string.format(" Сегодня %s %.2f процента.", sign, math.abs(pct)) end jarvis.speak(line) jarvis.audio.play_ok() return { chain = false }