Документация · v1.0.0

Market Oracle API

Рыночные данные для торговых ботов и AI-агентов: закрытые бары, индикаторы, стакан, макро и режим рынка. Ниже — всё по порядку: от первого запроса до готового кода на Python и Node.js.

Полный контракт для Ai-агента
https://market-oracle.pro/ru/docs/agents.md

Основы

Market Oracle — только источник рыночных данных. Он не открывает сделки и не управляет позициями. Между рынком и вашей стратегией — единый подготовленный слой: закрытые бары, индикаторы, факты стакана, макро-контекст и режим рынка.

Главное правило: торговые решения — только по закрытому бару (closed: true). Каждый сигнал обрабатывается один раз, дедупликация по ключу symbol:ts.

Быстрый старт

Пять минут до первого осмысленного ответа API:

1. Health

Сервис доступен, данные свежие.

GET /health

2. Тариф

Ваши лимиты: запросы в день, RPM, число WS.

GET /v1/me

3. Символы

Брать только пары с ready=true.

GET /v1/symbols

4. Stream

Подписаться на закрытые бары.

WS /v1/stream

5. Context

Снимок для решения: раз в 60–90 с и перед входом.

GET /v1/context/{symbol}

6. Сигнал

Один разбор на один закрытый бар.

dedupe symbol:ts
# Текущий узел. Ключ — из письма после регистрации на сайте curl.exe -s https://api.market-oracle.pro/health curl.exe -s https://api.market-oracle.pro/v1/me -H "Authorization: Bearer mo_…" curl.exe -s "https://api.market-oracle.pro/v1/context/BTCUSDT" -H "Authorization: Bearer mo_…"

Подключение

Два канала, две роли. REST — запрос данных (снимки, история, календарь). WebSocket — уведомления о том, что закрылся очередной бар. Торговый цикл всегда один: WS будит → REST забирает данные → решение → пауза. Вебхуки (POST на ваш endpoint) Oracle не шлёт.

Адрес и ключ

# Храните в переменных окружения, не в коде и не в публичном фронтенде ORACLE_BASE_URL=https://api.market-oracle.pro ORACLE_API_KEY=mo_…

Каждый запрос к /v1/* (кроме публичных /health и /v1/health) несёт заголовок:

Authorization: Bearer mo_…

Что откуда приходит

НужноКаналОткуда
Момент «бар закрылся»WebSocketbar_close (бар + индикаторы 1m)
Всё для решения одним ответомRESTGET /v1/context/{symbol}
Себестоимость сделки и «дорого / нормально»RESTполя trade_cost / cost_risk в context (в WS их нет)
Старший таймфрейм liveRESTполе htf в context (m15/h1/h4/d1; в WS его нет)
История свечей и индикаторовRESTGET /v1/history / POST /v1/history/batch
Свежий стакан для проверки входаRESTGET /v1/depth/{symbol}?seconds=3
Минутная история стаканаREST или WSGET /v1/microstructure или событие microstructure_close
Календарь событий, макро, режим рынкаREST/v1/calendar, /v1/macro, /v1/market-regime

Диалог с WebSocket

# 1. После connect сервер присылает hello (version, failover). Без подписки событий нет. {"type": "hello", "version": "1.0.0", "failover": false} # 2. Подписка: конкретные пары, все сразу или со стаканом {"op": "subscribe", "symbols": ["BTCUSDT", "ETHUSDT"]} {"op": "subscribe", "symbols": ["*"]} {"op": "subscribe", "symbols": ["BTCUSDT"], "microstructure": true} # сразу служебное subscribed — не бар {"type": "subscribed", "symbols": […], "all": false, "microstructure": true} # 3. Сигнал и стаканное событие (join строго по symbol + ts) {"type": "bar_close", "symbol": "BTCUSDT", "interval": "1m", "failover": false, "bar": {…}} {"type": "microstructure_close", "symbol": "BTCUSDT", "microstructure": {…}} # 4. Служебное {"op": "unsubscribe", "symbols": ["ETHUSDT"]} {"op": "ping"} → {"type": "pong"}
Reconnect — обязательно с backoff: старт 1 с → ×2 → максимум 60 с, jitter ±25%. Не ставьте задержку в миллисекундах — при массовом рестарте это бьёт по серверу. После переподключения сначала догрузите пропуски через /v1/history, и только потом продолжайте live.

Готовность пары

Не каждая пара из списка пригодна для анализа. Проверяйте связку флагов — это три секунды, которые спасают от торговли по «тёплой» истории:

ПолеГдеСмысл
readysymbols, status, contexttrue при ≥ 200 баров (прогрев EMA200)
historyтам жеwarming / ready / full_day (≥1440 баров)
indicators_readylatest, status, contextесть базовый набор ema20+rsi14+atr14
data_quality.scorecontext, status0…100; для входа требуйте ≥ 70
lag_secstatus, contextвозраст закрытого бара; >120 режет score до ≤69
last_closed_tssymbols, statusвремя последнего закрытого бара (мс UTC)
Важно: readyindicators_ready. Для стратегий на EMA200 нужны оба. Не торгуйте пару с 15 свечами так же, как BTC с сутками истории.

GET /v1/context/{symbol}

Главный endpoint для бота и агента: один ответ вместо 8–10 вызовов. Берите его раз в 60–90 с на активную пару и обязательно перед входом.

БлокЧто это простыми словами
bar + indicatorsпоследний закрытый 1m-бар — сигнал минутной стратегии. Для 5m/15m/1h берите native history / htf. Поле может быть null
tickerцена сейчас и статистика 24h (для отображения и расчёта размера, не для сигнала)
depthсвежий стакан: спред, перекос bid/ask, крупные уровни
trade_cost / cost_riskво сколько обойдётся сделка и не «съедят» ли комиссии стоп (tradable: false = не входить). Есть только здесь, в WS их нет
htfстаршие бары live: m15/h1/h4/d1 с индикаторами. Полей m5/m30/w1 нет — их только через history
data_quality + freshnessможно ли доверять снимку: score 0…100 и свежесть каждого компонента
macro_event_soontrue = через <60 мин важное событие (FOMC/CPI) — лучше пауза
derivatives + liquidationsfunding, open interest, каскады ликвидаций — фильтр, а не сигнал
macro_snapshotFear&Greed, доминация BTC, стейблы, индекс доллара, доходность 10Y
cross_exchangeсверка mid; divergence_warning = не входить без проверки
market_regime / volatility_regimeфон рынка: связь с BTC, волатильность, breadth
Ограничение: context_scope="live_snapshot", historical_safe=false — это текущий снимок, а не исторические данные для бэктеста. В бэктест его подмешивать нельзя.
# Минимум перед входом (псевдокод — рабочие примеры ниже) bar != null and bar.closed == true ready == true and indicators_ready == true data_quality.score >= 70 and lag_sec <= 120 cost_risk != null and cost_risk.tradable == true macro_event_soon == false and divergence_warning == false

Свои комиссии можно передать query-параметрами — тогда tradable посчитается под вашу модель издержек: ?fee_buy=0.001&fee_sell=0.001&slippage=0.0002&k_sl=2&rr=2&tradable_c_r_max=0.45. Бэктест и live должны использовать одни и те же комиссии, иначе оценка «дорого / нормально» разъедется.

Как читать trade_cost / cost_risk: комиссии + половина спреда + проскальзывание = c_spot (доля от сделки, 0.0025 = 0.25% туда-обратно). Это делится на стоп (k_sl × ATR) → c_r. Значение 0.45 значит, что издержки съедят почти полстопа; p_be — доля прибыльных сделок, чтобы выйти в ноль при заданном RR. tradable: false — пара сейчас слишком дорогая для вашего стопа: шире стоп или пропуск.

Пример ответа (сокращённый, структура 1-в-1)

Полный JSON на ~80 полей с разбором каждого блока — в agents.md §7. Ниже — скелет, который придёт на GET /v1/context/BTCUSDT:

# GET /v1/context/BTCUSDT → 200, live_snapshot (усечено для чтения) { "symbol": "BTCUSDT", "interval": "1m", "ts": 1784179235000, # now сервера, не bar.ts "lag_sec": 75, "bar": { "ts": 1784179200000, "close": "65040.00", "closed": true, "indicators": { "ema20": "64910.12", "rsi14": "54.20", "atr14": "180.50", "adx14": "22.10", "vwap": "64980.00" } }, "data_quality": { "score": 92, "flags": [] }, "freshness": { "depth": { "fresh": true, "max_age_sec": 10 } }, "trade_cost": { "c_spot": "0.0025", "spread_from_depth": true }, "cost_risk": { "c_r": "0.446429", "p_be": "0.482143", "tradable": true }, "htf": { "m15": {…}, "h1": {…}, "h4": {…}, "d1": {…} }, "macro_event_soon": false, "volatility_regime": "low_vol_range" }
Как читать: score ≥ 70 + tradable: true + macro_event_soon: false = снимку можно доверять. Сигнал 1m — из bar (closed: true); старший ТФ — htf / history. depth для cost свеж только при freshness.depth.fresh (смотри max_age_sec в ответе).

История и таймфреймы

Oracle сам ведёт нативные свечи старших таймфреймов — склеивать 5m/15m из минуток на клиенте не нужно (иначе потеряете ADX, VWAP, CVD, OBV, MFI).

IntervalГлубинаИндикаторы
1m~60 днейда
5m60 днейда
15m90 днейда
30m120 днейда
1h~9 месяцевда
4h2 годада
1d3 годада
1w5 летда
# История одной пары и пакет для нескольких GET /v1/history/BTCUSDT?interval=15m&limit=300 POST /v1/history/batch {"symbols":["BTCUSDT"], "interval":"15m", "limit":200}

Стакан: live и история

Две разные сущности — не путайте:

GET /v1/depth (live)Microstructure (история)
Чтотекущий top-20, окно до 10 секундзакрытая UTC-минута: spread, imbalance, стены, pressure
Зачемпроверка входа через 1–2 с после сигналабэктест и стаканные фильтры на истории
Гдетолько текущее окно, без историиистория + WS-событие microstructure_close
Вызов/v1/depth/BTCUSDT?seconds=3/v1/microstructure/BTCUSDT / /latest
Гейт для стаканного входа: sample_count ≥ 40, coverage_pct ≥ 66.7, quality.score ≥ 70, microstructure.ts == bar.ts, closed == true. Live-depth — это фильтр исполнения, он не меняет исторический сигнал закрытого бара.
Стакан и CVD — не всегда доступны. При failover: true свечи могут оставаться валидными, но минутная microstructure может не писаться, а cvd.status стать down. Стаканным и CVD-стратегиям мало общего верхнего status (он бывает ok или degraded): проверяйте bars.status (свечи) и cvd.status (поток) в GET /health.

Индикаторы

Один и тот же набор на 1m и на всех старших ТФ после прогрева. Во время прогрева отдельные поля — null (не подставляйте 0). Каждый индикатор ниже — это готовый вход для бота, сигнализатора или скринера: тренд, сила, импульс, волатильность, объём, якорь цены, качество свечи, уровни.

ГруппаКлючиЧто показывает и как применять
Трендema20 / ema50 / ema200, ema50_slope_pctНаправление и скорость. Цена выше EMA200 — бычий фон; кросс ema20/ema50 — импульс; |slope| ≤ 0.1 — флет для сетки
Сила и направлениеadx14, plus_di14 / minus_di14 / di_sideADX — только сила (флет ≤25, тренд ≥30), DI — сторона (строки "1"/"-1"/"0"). Фильтр: трендовый бот только при ADX ≥ 25
Импульсrsi14, mfi14Перегрев 0–100 (>70 перекуплен, <30 перепродан). MFI — второй голос с объёмом. Не контртренд по одному RSI в тренде
Волатильностьatr14 / atr_pct, atr50 / atr_ratio_14_50, bb_mid / bb_upper / bb_lower / bb_widthСтоп = k×ATR; ratio <0.8 — squeeze (копится энергия), >1.2 — разгон; BB-width — squeeze-метр для пробоя
Объём и потокvol_sma20, volume_usd / volume_rate, obv, cvd_deltaВход подтверждать объёмом ≥1.5–2× нормы ($/мин сравним между ТФ). Накопительный CVD — сумма cvd_delta на клиенте; валиден только при cvd.status == ok
Якорь ценыvwapДневной VWAP (сброс 00:00 UTC): выше — день за покупателями. На 1w это не недельный VWAP
Форма свечиbody, wick_balance, close_pos, candle_q, range_ratioКачество бара одним числом candle_q; close_pos > 0.7 — сильный лонг-бар; range_ratio << 1 — шум, пропускать
Уровниswing_high / swing_low, last_swing_*Фракталы strength=2 с лагом 2 бара: стопы за экстремум, цели, пробойные входы. swing_* — только на баре подтверждения

Готовность ядра: indicators_ready = есть ema20+rsi14+atr14. Остальное подтягивается позже: ADX/DI примерно после 27 баров, EMA200 — после 200 баров этого интервала, Bollinger — после 20. Полный разбор каждого ключа (формула, пороги, применение в боте, ловушки) — в agents.md. Чего в Oracle нет и не будет: MACD, Stochastic, Supertrend, Ichimoku — это логика вашей стратегии.

Как комбинировать поля

Данные Oracle — входы, не готовый «покупай/продавай». Три рабочих связки для бота, сигнализатора и скринера:

Тренд + HTF

На bar_close 1m смотрите context.htf.h1: цена выше ema50, adx14 ≥ 25 и di_side == "1" — на младшем ТФ только лонги. Ниже EMA200 H1 — лонги только с пробойным подтверждением. Убирает входы против старшего тренда.

Mean-reversion

На своём ТФ: rsi14 вышел из зоны (>70 вниз или <30 вверх), цена вернулась к bb_mid / vwap, volume_rate не ниже нормы, tradable, до новостей >60 мин. Без quality-гейта такой сигнал пропускают.

Скринер + стакан

Раз в 5 мин сортируйте пары по volume_rate и atr_ratio_14_50 (squeeze + объём). На сигнале через 1–2 с — GET /v1/depth?seconds=3: спред в норме, imbalance в сторону входа, гейт microstructure. Нет — пропуск, да — лимит у стены.

Стартовый ТФ: 15m нативный + фильтр H1. 1m без опыта — пила и комиссии. Накопительный CVD считайте на клиенте суммой cvd_delta по закрытым барам; бэктест — только history as-of, не live-context.

Тарифы

Три клиентских тарифа: free, basic, pro. Цены — на сайте продажи ключей, здесь — лимиты, чтобы выбрать тариф под своего бота. Точные цифры вашего ключа всегда в GET /v1/me: если расходятся с таблицей — верьте /v1/me.

ТарифЗапросов в деньRPMМин. паузаРек. паузаMax WSКому
free2 000302000 мс2000 мс1знакомство с API, один бот
basic5 00060200 мс1000 мс2live 24/7: 1–2 бота на ключ
pro8 00090150 мс667 мс3live 24/7: до 3 ботов на одном ключе
Практика: на basiccontext раз в 60–90 с на активную пару + обязательно перед входом; на free — ориентир раз в ~30 мин. latest для тикера — раз в 10–15 с, историю — с кэшем от 5 мин. Бот без WS, долбящий latest каждые 10 с, съедает ~8640 запросов в сутки — не влезет ни в один тариф: сначала переходите на WebSocket.

Пример заголовков после платного GET /v1/context/BTCUSDT (имена без учёта регистра, в CORS проброшены):

X-Quota-Used: 150 X-Quota-Limit: 2000 X-Quota-Remaining: 1850 X-Quota-Cost: 1 X-Quota-Weight: 3 X-Quota-Reset: 1784217600

GET /v1/me те же заголовки отдаёт, но дневную квоту не тратит. На 429 смотрите Retry-After и JSON retry_after_ms; на обычном 200 заголовка Retry-After нет. Полная таблица полей — в agents.md, раздел «Заголовки лимитов».


Все endpoint'ы

Служебные

МетодПутьОписание
GET/healthстатус сервиса и свежесть баров (публичный)
GET/v1/meтариф ключа, остатки лимита, expires_at

Символы и статус

МетодПутьОписание
GET/v1/symbolsактивные пары + бары / ready / history
GET/v1/status/{symbol}lag, ready, индикаторы, quality одной пары
GET/v1/meta/{symbol}tick / step / minNotional для округления приказов

История и синхронизация

МетодПутьОписание
GET/v1/history/{symbol}?interval=1m|5m|15m|30m|1h|4h|1d|1w, limit (до 10080), from/to в мс
POST/v1/history/batchдо 20 пар за один запрос, тот же набор interval
POST/v1/sync/bootstrapхолодный дамп только 1m (до 10080 баров на пару)
GET/v1/latest?symbols=последний закрытый бар + ticker (до 50 пар; ответ всегда через .symbols[ПАРА])
GET/v1/indicators/{symbol}только индикаторы, только 1m (для старших ТФ — history)

Срез рынка

МетодПутьОписание
GET/v1/context/{symbol}полный снимок для решения
GET/v1/depth/{symbol}live top-20 (?seconds=0..10), фильтр исполнения
GET/v1/derivatives/{symbol}funding, OI, ликвидации
GET/v1/calendarмакро-события: ?hours=, ?high_only=true, для бэктеста ?as_of=bar.ts&window_min=60
GET/v1/macroFear&Greed (+история ?fng_days=), доминация, стейблы, DXY/10Y
GET/v1/quotes/{symbol}сверка BBO
GET/v1/market-regimeкорреляции с BTC, волатильность, breadth рынка

Microstructure

МетодПутьОписание
GET/v1/microstructure/{symbol}закрытая минутная история стакана (interval=1m, до 10080)
GET/v1/microstructure/{symbol}/latestпоследняя закрытая минута

Примеры кода

Два стартовых клиента — Python и Node.js. Адрес узла уже подставлен; остаётся ваш ключ mo_…. Язык переключается вкладками.

REST: первый запрос и гейт перед входом

# Только стандартная библиотека import json, urllib.request BASE = "https://api.market-oracle.pro" KEY = "mo_…" def api(path: str): req = urllib.request.Request(BASE + path, headers={"Authorization": f"Bearer {KEY}"}) with urllib.request.urlopen(req, timeout=15) as r: return json.load(r) health = api("/health") assert health["status"] == "ok" and health["bars"]["status"] == "ok" me = api("/v1/me") print(me["tier"], "остаток:", me["daily_remaining"]) ctx = api("/v1/context/BTCUSDT") bar = ctx["bar"] ok = (bar["closed"] and ctx["ready"] and ctx["indicators_ready"] and ctx["data_quality"]["score"] >= 70 and ctx["lag_sec"] <= 120 and ctx["cost_risk"]["tradable"] and not ctx["macro_event_soon"]) print("можно анализировать:", ok, bar["close"])

WebSocket: слушать закрытые бары

# pip install websockets import asyncio, json import websockets async def main(): async with websockets.connect( "wss://api.market-oracle.pro/v1/stream", extra_headers={"Authorization": "Bearer mo_…"}, ) as ws: print(await ws.recv()) # hello await ws.send(json.dumps({"op": "subscribe", "symbols": ["BTCUSDT"]})) seen = set() async for msg in ws: ev = json.loads(msg) if ev.get("type") != "bar_close": continue key = f"{ev['symbol']}:{ev['bar']['ts']}" if key in seen: continue seen.add(key) print("закрылся бар:", key, ev["bar"]["close"]) asyncio.run(main())

Ошибки

Сначала смотрите HTTP-код ответа, затем машинное поле code (на ошибках равно status) в теле. Текст error не парсите.

code / statusHTTPКогда и что делать
ok200успех
key_missing / key_invalid / key_expired / key_revoked401проблема с ключом: остановить торговлю, запросить продление у оператора
too_fast / rate_limited429слишком частые запросы: пауза retry_after_ms + jitter, дальше реже
quota_exceeded429дневной лимит исчерпан: data-REST не ретраить до UTC midnight; WS и служебные endpoint'ы продолжают работать
ws_limit429*слишком много WS на ключ: смотреть поле code (поля status может не быть)
unavailable503Oracle временно недоступен: backoff и повторить

Полезные заголовки: дневной остаток — X-Quota-* (не X-RateLimit-*); на 429Retry-After и retry_after_ms в JSON. Неизвестный символ / кривой диапазон — 400, внутренняя ошибка — 5xx с ограниченным exponential backoff.

Чеклист для AI-агента / бота

  1. GET /healthstatus == "ok" и bars.status == "ok"; для CVD-стратегий ещё cvd.status == "ok".
  2. GET /v1/me → учесть тариф, остатки дня, rpm, min_interval_ms, expires_at.
  3. GET /v1/symbols → только ready == true, лучше full_day.
  4. WS subscribe (для стакана — microstructure: true); дедуп обоих событий по symbol:ts.
  5. На bar_close — разбор один раз. Сигнал 5m/15m/1h — только по закрытому нативному бару своего ТФ.
  6. GET /v1/context/{symbol} по расписанию и перед входом; гейты: score ≥ 70, lag ≤ 120, cost_risk.tradable, без macro_event_soon и divergence_warning.
  7. Через 1–2 с после сигнала — опционально GET /v1/depth?seconds=3 как фильтр исполнения.
  8. После reconnect: пауза ≥ min_interval → /v1/history (+ microstructure) → exact join по ts.
  9. Не считать EMA/RSI/ADX на клиенте, если Oracle уже отдал их в bar.indicators. Не публикуйте ключ mo_… в открытых репозиториях и фронтенде.