Purpose
Market Oracle is a market data source only. It does not open trades or manage positions. Between exchanges and clients sits a single prepared layer: closed bars, indicators, order-book facts, macro, and market regime.
closed: true, bar −1). Signal deduplication: symbol:ts.- Canonical candles: Binance Spot; Bybit — failover + independent BBO; OKX — quote-only for consensus.
- One call to
GET /v1/context/{symbol}returns a decision snapshot. - Live trigger:
WS /v1/stream→bar_closeevent. - Numbers in JSON are decimal strings (no float errors).
Quick start
1. Health
Check status=ok, Redis, and WS provider.
2. Plan
Limits: daily / RPM / WS / expires_at.
3. Symbols
Take only ready=true.
4. Stream
Subscribe to closed bars.
5. Context
Snapshot before a decision (60–90 s).
6. Signal
Once per closed bar.
Authorization
All /v1/* routes require the header:
GET /healthandGET /metrics— public.- WebSocket: the same Bearer or
?token=mo_…in the URL. - Key management (
/v1/keys*) —ORACLE_ADMIN_TOKENonly. - Without
expires_atat creation, a key lives +30 days (not perpetual).
Symbol readiness
| Field | Where | Meaning |
|---|---|---|
bars_1m / bar_count | symbols, status | how many 1m bars in Redis |
ready | symbols, status, context | true at ≥ 200 bars (EMA200 warmup) |
history | same | warming / ready / full_day (≥1440) |
indicators_ready | latest, status, context | base set ema20+rsi14+atr14 present |
data_quality.score | context, status | 0…100; for entry require ≥ 70 |
lag_sec | status, context | age of closed bar; >120 cuts score to ≤69 |
ready ≠ indicators_ready. For EMA200 you need both. Don't trade a "warm" pair with 15 candles as if it were BTC with a full day of history.GET /v1/context/{symbol}
Main endpoint for bots/AI. One response instead of 8–10 calls:
| Block | Purpose |
|---|---|
bar + indicators | signal only on closed 1m |
ticker | 24h volume/change, best bid/ask |
depth | spread, imbalance, walls (live snapshot) |
ready / history / lag_sec | whether the pair is tradeable |
macro_event_soon | pause before FOMC/CPI (high impact <60 min) |
derivatives + liquidations | funding / OI / cascades |
macro_snapshot | F&G, dominance, stables, DXY/10Y |
cross_exchange | venue consensus, divergence |
market_regime | corr to BTC, vol, breadth |
data_quality | score + flags |
Not in context (request separately): long history, event calendar, live WS, /v1/meta, closed minute microstructure history.
context_scope="live_snapshot", historical_safe=false — this is not point-in-time history for backtesting.WebSocket /v1/stream
- After connect the server sends
{"type":"hello",…} - Client:
{"op":"subscribe","symbols":["*"]}or a pair list - For order book:
"microstructure": true→ extramicrostructure_closeevent - Signal event:
{"type":"bar_close","symbol":"BTCUSDT","bar":{…},"interval":"1m"} - Ping:
{"op":"ping"}→pong
Join bar_close and microstructure_close strictly by symbol + ts, not by receive time. WS push does not spend daily quota.
Plans and limits
| Plan | Requests / day | RPM | Min. pause | Max WS |
|---|---|---|---|---|
free | 6 000 | 30 | 2 s (2000 ms) | 1 |
basic | 25 000 | 120 | 500 ms | 2 |
pro | 100 000 | 180 | 350 ms | 3 |
Pause between requests ≈ 60 000 ms ÷ RPM (steady pace under the per-minute limit). Heavy endpoints (context/history = weight 3) spend more of the daily quota; /v1/me, /v1/symbols, /v1/meta/*, /v1/calendar — weight 0 for the day (RPM and pause still apply). WS push does not spend daily quota.
On limit: HTTP 429, headers X-RateLimit-*, Retry-After, X-Quota-*. Check the status/code field in the body.
basic — context every 60–90 s per active pair; on free — less often (6k/day budget). Don't storm with dozens of parallel context calls.All endpoints
Service
| Method | Path | Description |
|---|---|---|
| GET | /health, /v1/health | status, Redis, active_provider, failover |
| GET | /metrics | Prometheus text |
| GET | /v1/me | key plan, usage, weights, expires_at |
Keys (admin)
| Method | Path | Description |
|---|---|---|
| GET / POST | /v1/keys | list / create (name, tier, expires_at) |
| PATCH / DELETE | /v1/keys/{id} | change tier/expiry / revoke |
Symbols and status
| Method | Path | Description |
|---|---|---|
| GET | /v1/symbols | active pairs + bars / ready / history |
| POST | /v1/symbols | add pair → bootstrap + WS reload |
| DELETE | /v1/symbols/{symbol} | remove from registry |
| GET | /v1/status/{symbol} | lag, ready, indicators, quality |
| GET | /v1/meta/{symbol} | tick / step / minNotional |
History and sync
| Method | Path | Description |
|---|---|---|
| GET | /v1/history/{symbol} | ?interval=1m|1h|4h|1d|1w, limit, from, to |
| POST | /v1/history/batch | up to 20 pairs; optional include_microstructure |
| POST | /v1/sync/bootstrap | cold dump from Redis for the client |
| GET | /v1/latest?symbols= | last closed bar + ticker |
| GET | /v1/indicators/{symbol} | indicators only over history |
| Interval | Depth | Indicators |
|---|---|---|
1m | 21 days (live WS) | yes |
1h | ~9 mo | no (null) |
4h | 2 years | no |
1d | 3 years | no |
1w | 5 years | no |
Market slice
| Method | Path | Description |
|---|---|---|
| GET | /v1/context/{symbol} | full AI snapshot |
| GET | /v1/depth/{symbol} | live top-20 / recent seconds (execution filter) |
| GET | /v1/derivatives/{symbol} | funding, OI, liquidations |
| GET | /v1/calendar | ?hours=, ?high_only=true |
| GET | /v1/macro | F&G (+history ?fng_days=), dominance, stables, FRED |
| GET | /v1/quotes/{symbol} | BBO consensus Binance/Bybit/OKX |
| GET | /v1/market-regime | corr / vol / breadth from own 1h |
Microstructure
| Method | Path | Description |
|---|---|---|
| GET | /v1/microstructure/{symbol} | closed minute order-book history |
| GET | /v1/microstructure/{symbol}/latest | last closed minute |
Top-20 aggregation @ 1 Hz into a UTC minute. Live depth in context and closed microstructure are different entities. Historical depth from the exchange is not reconstructed after the fact.
Indicators on the 1m bar
Incremental computation, batch-reference tests. Fields are decimal strings; may be null during warmup.
ema20,ema50,ema200rsi14,atr14,adx14(Wilder seed)vwap,obv,mfi14cvd_delta— bar delta (taker buy − sell); cumulative CVD — prefix sum on the client
Errors and statuses
| status / code | HTTP | When |
|---|---|---|
ok | 200 | success |
key_missing / key_invalid / key_expired / key_revoked | 401 | key problems |
unauthorized | 401 | wrong admin token |
rate_limited / quota_exceeded / too_fast / ws_limit | 429 | plan limits |
unavailable | 503 | auth/DB temporarily unavailable |
Client: check status (or code) first; don't parse the error text. After 429 — sleep for retry_after_ms / Retry-After.
Checklist for an AI agent / bot
GET /health→status == "ok", Redis ok, WS connected.GET /v1/me→ account for tier, daily, RPM,min_interval_ms,expires_at.GET /v1/symbols→ filterready == true(preferfull_day).- WS subscribe; for order book —
microstructure: true. - On
bar_close— analyze once (dedupesymbol:ts). - Before entry / on schedule —
GET /v1/context/{symbol}; gate:data_quality.score ≥ 70,ready,indicators_ready. - Optionally 1–2 s after signal:
GET /v1/depth/{symbol}?seconds=3as an execution filter (does not change the historical bar signal). - After reconnect: pause ≥ min_interval →
/v1/history(+ microstructure) → exact join. - Don't store the admin token in the client. Don't publish
mo_…in a repository.
docs/DOC.md, docs/AUTH.md, docs/agents.md. This page is a public digest of the same specification.