{"openapi":"3.1.0","info":{"title":"KlineSync Engine","description":"Multi-exchange market-data + indicator API, including Binance equity perpetuals.\n\n**For AI agents**: read [`/agents.md`](/agents.md) before generating requests. It documents canonical symbol forms, decision trees, and common pitfalls that prevent guessing.\n\n**For schemas**: this OpenAPI document is the normative contract for field types, defaults, and constraints.","version":"2.0"},"paths":{"/api/markets":{"get":{"tags":["markets"],"summary":"List all venues with WS status snapshot","description":"List every venue we sync with full metadata for agent self-discovery.\n\nPer-venue fields:\n  - asset_class:  \"crypto\" / \"stock\" / \"forex\"\n  - region:       \"CN\"/\"HK\"/\"US\" for stock, null otherwise\n  - intervals:    list of supported intervals (per-venue, may differ)\n  - max_klines:   {interval: cap}, the cap on `limit` for klines/chart\n  - session:      null = 24x7 (crypto); else {calendar, is_open, next_open_ms}\n  - status:       see /api/health for semantics; \"ok\"/\"degraded\"/\"dead\"/\"starting\"","operationId":"list_markets_api_markets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/markets/{exchange}/{market}/symbols":{"get":{"tags":["markets"],"summary":"List symbols subscribed on a specific venue","description":"Return the canonical symbol list for one venue. Hyperliquid:perp is\nUSDC-only; okx:perp is USDT-only — the lists reflect actual coverage.\n\nBinance:perp includes subscribed equity perpetuals. include_meta=true adds\nsymbol_meta (instrument_type, underlying_symbol, quote_asset, status) and\nmetadata_status=ready|stale|unavailable plus metadata_updated_at_ms. It does\nnot list unsubscribed contracts or change Kline columns. Metadata age does\nnot indicate candle freshness. This option is currently Binance:perp only.","operationId":"list_symbols_api_markets__exchange___market__symbols_get","parameters":[{"name":"exchange","in":"path","required":true,"schema":{"enum":["binance","bybit","okx","hyperliquid","stock","forex","commodity"],"type":"string","title":"Exchange"}},{"name":"market","in":"path","required":true,"schema":{"enum":["spot","perp","cn","hk","us","futures"],"type":"string","title":"Market"}},{"name":"include_meta","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Meta"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/intervals":{"get":{"tags":["markets"],"summary":"Supported intervals + per-interval cache caps","description":"Return every interval we sync, with the cache cap (max bars stored per\nsymbol) and the staleness budget (seconds before watchdog flags as stale).\n\nPass exchange and market together for venue-specific limits. Omitting both\npreserves the legacy crypto profile response.","operationId":"list_intervals_api_intervals_get","parameters":[{"name":"exchange","in":"query","required":false,"schema":{"anyOf":[{"enum":["binance","bybit","okx","hyperliquid","stock","forex","commodity"],"type":"string"},{"type":"null"}],"title":"Exchange"}},{"name":"market","in":"query","required":false,"schema":{"anyOf":[{"enum":["spot","perp","cn","hk","us","futures"],"type":"string"},{"type":"null"}],"title":"Market"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/klines":{"get":{"tags":["klines"],"summary":"Get OHLCV bars, automatically retrieving history for explicit time windows","description":"Each row: `[open_time_ms, open, high, low, close, volume, quote_volume]`.\n\nOn subscribed crypto exchange feeds, explicit `startTime` or `endTime`\nautomatically retrieves available history, bounded by limit. No flag is\nrequired; the legacy extend_history flag remains accepted. Unavailable\nhistorical windows return 404, preparing/unavailable sources return 503\nwith Retry-After and X-Kline-Error-Code. Latest queries are unchanged.","operationId":"get_klines_api_klines_get","parameters":[{"name":"exchange","in":"query","required":true,"schema":{"enum":["binance","bybit","okx","hyperliquid","stock","forex","commodity"],"type":"string","title":"Exchange"}},{"name":"market","in":"query","required":true,"schema":{"enum":["spot","perp","cn","hk","us","futures"],"type":"string","title":"Market"}},{"name":"symbol","in":"query","required":true,"schema":{"type":"string","description":"Canonical {BASE}{QUOTE} (e.g. BTCUSDT)","examples":["BTCUSDT"],"title":"Symbol"},"description":"Canonical {BASE}{QUOTE} (e.g. BTCUSDT)"},{"name":"interval","in":"query","required":true,"schema":{"enum":["1m","5m","15m","30m","1h","4h","1d"],"type":"string","description":"Lowercase interval","examples":["1h"],"title":"Interval"},"description":"Lowercase interval"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Bars to return","examples":[100],"default":500,"title":"Limit"},"description":"Bars to return"},{"name":"startTime","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Window start, ms epoch","title":"Starttime"},"description":"Window start, ms epoch"},{"name":"endTime","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Window end, ms epoch","title":"Endtime"},"description":"Window end, ms epoch"},{"name":"extend_history","in":"query","required":false,"schema":{"type":"boolean","description":"Legacy option. Explicit startTime/endTime already retrieves available crypto exchange history; no flag is needed. Gold cache restrictions still apply.","default":false,"title":"Extend History"},"description":"Legacy option. Explicit startTime/endTime already retrieves available crypto exchange history; no flag is needed. Gold cache restrictions still apply."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Symbol not subscribed, no cached data, or no available candles in the requested historical window","headers":{"X-Kline-Error-Code":{"schema":{"type":"string","enum":["symbol_not_subscribed","history_not_available"]},"description":"Present for classified symbol/history errors"}}},"503":{"description":"Market data is preparing or temporarily unavailable; retry the same request after Retry-After","headers":{"Retry-After":{"schema":{"type":"string"}},"X-Kline-Error-Code":{"schema":{"type":"string","enum":["history_preparing","history_busy","history_upstream_unavailable"]},"description":"Present for historical retrieval errors"}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/indicators":{"post":{"tags":["indicators"],"summary":"Compute indicator values; return klines + raw values keyed by indicator","description":"Strategy-oriented: return raw indicator column values aligned with klines.\n\nThe `indicators` key is generated from each calc spec's `id`, or falls\nback to `\"name:k1=v1,k2=v2\"` (params alphabetized). When two calc entries\nwould collide on the auto-key, the request is rejected with 400 — set\n`id` on at least one of them.\n\nResponse always contains `klines` (the same window the indicators are\ncomputed on, post-warmup-trim).\n\nWith `explain=true` (default), each indicator entry carries an `explain`\nfield with `name / category / standard / desc / summary_focus` (and\n`outputs / signals / caveats` when standard=false). The Skill / LLM should\nuse `summary_focus` as the analysis checklist when interpreting raw values.","operationId":"post_indicators_api_indicators_post","parameters":[{"name":"explain","in":"query","required":false,"schema":{"type":"boolean","description":"Embed knowledge-base explanation per indicator (default true). Set false for programmatic-only calls (backtest/alert) to shrink response.","default":true,"title":"Explain"},"description":"Embed knowledge-base explanation per indicator (default true). Set false for programmatic-only calls (backtest/alert) to shrink response."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndicatorCalcRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad request: unknown indicator, calc params don't match signature, duplicate calc keys without id, limit > 1000, empty calc"},"404":{"description":"Symbol not subscribed, no cached data, or no available candles in the requested historical window","headers":{"X-Kline-Error-Code":{"schema":{"type":"string","enum":["symbol_not_subscribed","history_not_available"]},"description":"Present for classified symbol/history errors"}}},"503":{"description":"Market data is preparing or temporarily unavailable; retry the same request after Retry-After","headers":{"Retry-After":{"schema":{"type":"string"}},"X-Kline-Error-Code":{"schema":{"type":"string","enum":["history_preparing","history_busy","history_upstream_unavailable"]},"description":"Present for historical retrieval errors"}}},"422":{"description":"Pydantic validation error: missing required field, wrong type, extra unknown field"}}},"get":{"tags":["indicators"],"summary":"Discover available indicators with category + description (knowledge-base index layer)","description":"Index layer of the indicator knowledge base. Returns a flat list of\nindicators with category, short description, and a `standard` flag.\n\nUse this to discover what indicators exist before constructing a\n`POST /api/indicators` request. The full per-indicator analysis framework\n(signals / summary_focus / caveats) is delivered embedded in the POST\nresponse under `indicators[*].explain`, not here — this endpoint is\nintentionally lightweight for catalog browsing.\n\nThe response carries `X-Knowledge-Version` header. Skill clients can\ncache the index and re-fetch only when the version changes (default\nCache-Control: max-age=3600).","operationId":"list_indicators_api_indicators_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by category. Use one of the values returned in the response 'categories' field. Returns empty list if category not found.","title":"Category"},"description":"Filter by category. Use one of the values returned in the response 'categories' field. Returns empty list if category not found."},{"name":"keyword","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring match (case-insensitive) against keywords + desc. Combined with category as AND.","title":"Keyword"},"description":"Substring match (case-insensitive) against keywords + desc. Combined with category as AND."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/indicators/compute":{"post":{"tags":["indicators"],"summary":"Compute indicators against user-supplied klines (no in-memory store lookup)","description":"Bring-your-own klines:run indicators on user-uploaded OHLCV instead of\nthe engine's cached data.\n\nUseful for backtest, custom feeds, replaying historical scenarios, or\nintegrating data the engine doesn't subscribe to. Same response shape as\nPOST /api/indicators (minus venue/symbol/current_price fields).\n\n**No warmup is added** — include enough leading bars yourself for warmup-\nsensitive indicators (ATR/EMA(200) ≈ 200+ bars, SMC swing ≥ 50, FVG ≥ 3).\n\nAuth + rate limits identical to other compute endpoints (`Bearer` token\nvia Authorization header recommended for higher quota).","operationId":"post_indicators_compute_api_indicators_compute_post","parameters":[{"name":"explain","in":"query","required":false,"schema":{"type":"boolean","description":"Embed knowledge-base explanation per indicator (default true). Set false to shrink response.","default":true,"title":"Explain"},"description":"Embed knowledge-base explanation per indicator (default true). Set false to shrink response."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComputeRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad request: empty klines, non-monotonic open_time, NaN/inf, unknown indicator, calc failure"},"413":{"description":"klines count exceeds 2000 for a non-HMM-only request (HMM-only cap: 5000)"},"422":{"description":"Pydantic validation: missing field, wrong type, extra unknown field"}}}},"/api/indicators/catalog":{"get":{"tags":["indicators"],"summary":"Chart-able indicators with drawing-spec parameter signatures","description":"Subset of indicators that have a `spec_<name>` function (i.e. can be\nrendered via POST /api/chart). For the full set of computable indicators,\nuse GET /api/indicators/registry instead.","operationId":"indicator_catalog_api_indicators_catalog_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/indicators/registry":{"get":{"tags":["indicators"],"summary":"Self-describing list of every indicator (params + output columns)","description":"Discovery endpoint: enumerate every indicator with its parameter\nsignature (name, type, default), the column names it adds with default\nparameters, and whether it has a chart spec. With include_signals=true,\nalso returns has_signals and native feature definitions (without calculating\nany bars). Live features support Binance, Bybit, OKX and Hyperliquid feeds,\nincluding Binance equity perpetuals; BYO requires fixed-duration bars and an\nexplicit interval. Definition availability is not data readiness.\n\nAI agents should call this **before** generating /api/indicators or\n/api/chart requests so they don't guess parameter names. The\n`default_output_columns` field tells you which columns will appear in\nthe response; parametric indicators (e.g. `ema_<period>`) report the\ncolumn produced with default `period`.","operationId":"indicator_registry_api_indicators_registry_get","parameters":[{"name":"include_signals","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Signals"}},{"name":"include_schema","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Schema"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/indicators/registry/resolve":{"post":{"tags":["indicators"],"summary":"Resolve indicator parameters and output definitions without calculating candles","operationId":"resolve_indicator_definitions_api_indicators_registry_resolve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefinitionResolveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/indicators/signals":{"get":{"tags":["indicators"],"summary":"Query native feature definitions grouped by indicator","description":"Read-only definitions for agents, chart clients and other API consumers.\n\nNo candles or feature values are returned. Names and IDs are case-sensitive;\nfilters combine with AND. Without kind/id, groups with no features are retained\nwith signals=[] and a reason. With kind/id, groups without matching definitions\nare omitted; a valid query with no matches returns count=0, signal_count=0,\nindicators={}. The usual optional API token and rate limits apply.\n\nGet parameters from /api/indicators/registry. Get observed values by setting\nsignals=true on /api/indicators, /api/indicators/compute or /api/chart. Features\nconfirm on closed bars by default: true=occurred/holds, false=valid but not met,\nnull=unknown (forming bar, insufficient history, invalid inputs or a gap).\nDefinition availability is not data readiness. Live features support Binance,\nBybit, OKX and Hyperliquid feeds, including Binance equity perpetuals. BYO\nrequires an explicit interval and continuous fixed-duration bars.\nFollow each indicator's market/interval constraints. Feature open_time and\nconfirmed_at_ms are milliseconds; chart marker time is seconds. With\ninclude_forming=true, supported features evaluate the final OHLCV as complete\nand append bar_status; forming observations never have a confirmation time.","operationId":"indicator_signal_directory_api_indicators_signals_get","parameters":[{"name":"indicator","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Exact indicator name, e.g. macd. Omit for all indicators.","title":"Indicator"},"description":"Exact indicator name, e.g. macd. Omit for all indicators."},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"enum":["event","state"],"type":"string"},{"type":"null"}],"description":"Filter feature type; omit for both.","title":"Kind"},"description":"Filter feature type; omit for both."},{"name":"id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"null"}],"description":"Exact feature ID, e.g. macd.cross_up. Must belong to indicator if both are supplied.","title":"Id"},"description":"Exact feature ID, e.g. macd.cross_up. Must belong to indicator if both are supplied."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureDirectoryResponse"}}}},"400":{"description":"Unknown indicator or feature ID, or indicator/ID ownership mismatch."},"401":{"description":"Invalid supplied API token."},"429":{"description":"API rate limit exceeded; respect Retry-After."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chart":{"post":{"tags":["chart"],"summary":"Build a chart payload: klines + panels with drawing protocol","description":"Chart-frontend-oriented: return klines plus a declarative drawing\nprotocol (`panels` + `items` + `style.role`).\n\nEvery entry in `calc[]` must have a `spec_<name>` registered (see\nGET /api/indicators/catalog or `has_chart_spec: true` in\nGET /api/indicators/registry).\n\nNote: the `time` field inside chart payloads is **seconds**, not\nmilliseconds, matching lightweight-charts conventions.\n\nSet `signals: true` for `indicator_signals` plus main-panel event markers.\nMarkers are on confirmation candles, not historical pivots; states are not\nplotted repeatedly. Without this option, the original response is preserved.","operationId":"post_chart_api_chart_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalcRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad request: unknown indicator, indicator has no chart spec, duplicate calc keys, empty calc"},"404":{"description":"Symbol not subscribed, no cached data, or no available candles in the requested historical window","headers":{"X-Kline-Error-Code":{"description":"Present for classified symbol/history errors","schema":{"type":"string","enum":["symbol_not_subscribed","history_not_available"]}}}},"503":{"description":"Market data is preparing or temporarily unavailable; retry the same request after Retry-After","headers":{"Retry-After":{"schema":{"type":"string"}},"X-Kline-Error-Code":{"description":"Present for historical retrieval errors","schema":{"type":"string","enum":["history_preparing","history_busy","history_upstream_unavailable"]}}}},"422":{"description":"Pydantic validation error"}}}},"/api/symbols/builtin":{"get":{"tags":["markets"],"summary":"Built-in common symbols (curated natural-name → canonical mapping)","description":"Return a curated list mapping common natural names (中文/英文/简称) to\ncanonical (exchange, market, symbol) tuples. Use this as the first stop\nwhen resolving a user-provided asset name; fall back to\n`/api/symbols/search?q=` for fuzzy lookup, or\n`/api/markets/{exchange}/{market}/symbols` for the exhaustive subscribed\nlist per venue.\n\nResponse carries `X-Symbols-Version` header for cache invalidation —\nre-fetch only when version changes.","operationId":"get_symbols_builtin_api_symbols_builtin_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/symbols/search":{"get":{"tags":["markets"],"summary":"Search symbols (built-in + smartbox fallback)","description":"Look up a natural-language asset name. Built-in symbols (curated,\nwith aliases) are searched first and ranked by match quality. If fewer\nthan 3 results, a live smartbox query discovers additional stocks across\nA-shares, HK, and US markets.","operationId":"get_symbols_search_api_symbols_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Query string. Searches the curated built-in table first; if fewer than 3 matches, falls back to Tencent smartbox for broader stock/forex discovery. Each match has a `source` field ('builtin' or 'smartbox') indicating its origin.","examples":["茅台","tesla","BTC","招商银行"],"title":"Q"},"description":"Query string. Searches the curated built-in table first; if fewer than 3 matches, falls back to Tencent smartbox for broader stock/forex discovery. Each match has a `source` field ('builtin' or 'smartbox') indicating its origin."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/derivatives/funding-rates":{"get":{"tags":["derivatives"],"summary":"Funding rate history for perpetual contracts","description":"Historical funding rates from the exchange's native API.","operationId":"get_funding_rates_api_derivatives_funding_rates_get","parameters":[{"name":"exchange","in":"query","required":true,"schema":{"enum":["binance","bybit","okx"],"type":"string","description":"Exchange name","title":"Exchange"},"description":"Exchange name"},{"name":"symbol","in":"query","required":true,"schema":{"type":"string","description":"Canonical perp symbol, e.g. BTCUSDT","examples":["BTCUSDT"],"title":"Symbol"},"description":"Canonical perp symbol, e.g. BTCUSDT"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/derivatives/open-interest":{"get":{"tags":["derivatives"],"summary":"Historical open interest (K-line style, Binance)","operationId":"get_open_interest_api_derivatives_open_interest_get","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string","description":"Canonical perp symbol","examples":["BTCUSDT"],"title":"Symbol"},"description":"Canonical perp symbol"},{"name":"period","in":"query","required":false,"schema":{"type":"string","description":"Aggregation period (5m/15m/30m/1h/2h/4h/6h/12h/1d)","default":"1h","title":"Period"},"description":"Aggregation period (5m/15m/30m/1h/2h/4h/6h/12h/1d)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/derivatives/long-short-ratio":{"get":{"tags":["derivatives"],"summary":"Top trader long/short position ratio (Binance)","operationId":"get_long_short_ratio_api_derivatives_long_short_ratio_get","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string","examples":["BTCUSDT"],"title":"Symbol"}},{"name":"period","in":"query","required":false,"schema":{"type":"string","default":"1h","title":"Period"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/derivatives/taker-ratio":{"get":{"tags":["derivatives"],"summary":"Taker buy/sell volume ratio (Binance)","operationId":"get_taker_ratio_api_derivatives_taker_ratio_get","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string","examples":["BTCUSDT"],"title":"Symbol"}},{"name":"period","in":"query","required":false,"schema":{"type":"string","default":"1h","title":"Period"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sentiment/fear-greed":{"get":{"tags":["sentiment"],"summary":"Crypto Fear & Greed Index (daily, alternative.me)","description":"0 = Extreme Fear, 100 = Extreme Greed. Updated daily.","operationId":"get_fear_greed_api_sentiment_fear_greed_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"Days of history","default":30,"title":"Limit"},"description":"Days of history"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/playbooks":{"get":{"tags":["indicators"],"summary":"List available strategy playbooks (analysis recipes)","description":"Catalog of analysis playbooks. Each playbook bundles indicators +\nper-asset-class default intervals + synthesis prompt + output template +\nconstraints — i.e. how to interpret a set of indicators in a given\nscenario.\n\nUse `POST /api/analyze` with a `playbook` name to execute one in a single\ncall: the engine fetches data, computes indicators, and returns the\nplaybook context plus values ready for an LLM to synthesize a verdict.","operationId":"get_playbooks_list_api_playbooks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/playbooks/{name}":{"get":{"tags":["indicators"],"summary":"Get a single playbook's full recipe","description":"Full playbook detail: indicators / intervals_per_asset_class /\nsynthesis prompt / output_template / constraints / applicable_to.","operationId":"get_playbook_api_playbooks__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Playbook name not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analyze":{"post":{"tags":["indicators"],"summary":"Execute a playbook against a symbol — returns indicator data per interval (recipe hidden by default)","description":"One call returns:\n\n* `playbook` — playbook NAME (string), not the full recipe\n* `data`     — per-interval `current_price` + `klines` + `indicators`,\n               each indicator carrying its `explain` (knowledge-base\n               summary_focus etc.)\n* `recipe`   — *only when `verbose=true`* — full recipe\n               (synthesis / output_template / constraints). Production\n               callers omit `verbose` so the recipe never reaches the\n               end-user terminal; the Skill embeds the format rules\n               in its own SKILL.md instead.\n\nThe Skill applies the format rules it already knows; this endpoint's\njob is purely data delivery.","operationId":"post_analyze_api_analyze_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyzeRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad request: unsupported interval for this venue, calc params don't match signature, limit > INDICATOR_CALC_LIMIT, or playbook lacks defaults for this asset_class"},"404":{"description":"Playbook name unknown, or symbol not subscribed on this venue"},"422":{"description":"Pydantic validation error"},"500":{"description":"Indicator runtime failure or playbook misconfigured"}}}},"/api/health":{"get":{"tags":["system"],"summary":"Per-venue health, with overall status","description":"Per-venue WS-batch + freshness status, plus an overall rollup.\n\nPer-venue `status`:\n  - `starting`  no batch registered yet (init in progress)\n  - `ok`        all batches running and no streams stale\n  - `degraded`  some streams stale or some batches failed\n  - `dead`      all batches failed\n\nTop-level `status` is the worst venue status. Use this endpoint to\ndecide whether to retry on a 404 from data endpoints — `starting`\nmeans wait, anything else means the data path should be available.","operationId":"health_api_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/agents.md":{"get":{"tags":["system"],"summary":"Operating manual for AI agents (markdown)","description":"Return AGENTS.md as raw markdown. Read this **before** generating\nrequests against the API; it documents canonical conventions, decision\ntrees between similar endpoints, and common pitfalls.","operationId":"agents_md_agents_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}},"text/markdown":{}}}}}}},"components":{"schemas":{"AnalyzeRequest":{"properties":{"playbook":{"type":"string","title":"Playbook","description":"Playbook name. List available via GET /api/playbooks.","examples":["market-pulse"]},"exchange":{"type":"string","enum":["binance","bybit","okx","hyperliquid","stock","forex","commodity"],"title":"Exchange","examples":["binance"]},"market":{"type":"string","enum":["spot","perp","cn","hk","us","futures"],"title":"Market","examples":["perp"]},"symbol":{"type":"string","title":"Symbol","description":"Canonical {BASE}{QUOTE} all-uppercase, no separators (e.g. 'BTCUSDT', 'SOLUSDC', '600519').","examples":["SOLUSDT"]},"intervals":{"anyOf":[{"items":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d"]},"type":"array"},{"type":"null"}],"title":"Intervals","description":"Override the playbook's default intervals (chosen per asset_class). Pass a list when the user asks for specific timeframes; omit to use defaults from the playbook's `intervals_per_asset_class`.","examples":[null,["1h","4h"]]},"limit":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Limit","description":"Override `playbook.limit` (default 200). Counts the bars returned per interval."},"verbose":{"type":"boolean","title":"Verbose","description":"If true, response includes the full `recipe` block (synthesis / output_template / constraints) for debugging or admin verification. Default false — production callers (Skill, web client) keep recipe out of the wire to avoid leaking format instructions to end users; the recipe is still applied server-side via the playbook the engine looked up.","default":false}},"additionalProperties":false,"type":"object","required":["playbook","exchange","market","symbol"],"title":"AnalyzeRequest","description":"Body for POST /api/analyze.\n\nThe playbook supplies indicators + default intervals + synthesis prompt;\nthe engine fetches data, runs the indicators, and returns everything an\nLLM needs to synthesize a verdict per the playbook's `synthesis` +\n`output_template` + `constraints`."},"CalcRequest":{"properties":{"include_forming":{"type":"boolean","title":"Include Forming","description":"With signals=true, evaluate the final forming candle as a complete OHLCV sample. Values, features and objects use the same calculation. Signals append bar_status (closed/forming); forming results may disappear and have no confirmation time. Omit or set false to preserve the original closed-bar behavior.","default":false},"include":{"items":{"type":"string","enum":["signal_reasons","signal_details","calculation","definition"]},"type":"array","maxItems":4,"title":"Include","description":"Optional single-calculation metadata. Signal reasons/details require signals=true. Omit for the original response."},"exchange":{"type":"string","enum":["binance","bybit","okx","hyperliquid","stock","forex","commodity"],"title":"Exchange","description":"Lowercase exchange id. Use GET /api/markets to list venues.","examples":["binance"]},"market":{"type":"string","enum":["spot","perp","cn","hk","us","futures"],"title":"Market","description":"Lowercase market kind. Crypto futures use 'perp'; commodity supports 'futures' and gold 'spot'.","examples":["perp"]},"symbol":{"type":"string","title":"Symbol","description":"Canonical {BASE}{QUOTE} all-uppercase, no separators. We translate to exchange-native internally; native forms (e.g. 'BTC-USDT-SWAP', 'BTCPERP', 'BTC') return 404.","examples":["BTCUSDT","ETHUSDC","1000PEPEUSDT"]},"interval":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d"],"title":"Interval","description":"Candle interval; case-sensitive lowercase. Check /api/markets for each venue's subset.","examples":["1h"]},"limit":{"type":"integer","minimum":1.0,"title":"Limit","description":"Number of bars to return. Cap differs by endpoint: /api/indicators caps at INDICATOR_CALC_LIMIT (1000); /api/chart caps at MAX_KLINES_BY_INTERVAL[interval] silently.","default":500,"examples":[100,500]},"startTime":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Starttime","description":"Window start in **milliseconds** since Unix epoch. Optional. Indicator warmup is added in front of this automatically. Explicit time windows on subscribed crypto exchange feeds (including Binance equity perpetuals) automatically retrieve available history; no extra option is required.","examples":[1735689600000]},"endTime":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Endtime","description":"Inclusive candle open-time bound in milliseconds. An explicit bound automatically retrieves available exchange history. Optional."},"calc":{"items":{"$ref":"#/components/schemas/IndicatorSpec"},"type":"array","title":"Calc","description":"List of indicators to compute. Cannot be empty (returns 400). Order is preserved in the response, but lookup by key, not index.","examples":[[{"name":"ema","params":{"period":20}},{"name":"rsi","params":{"period":14}}]]},"signals":{"type":"boolean","title":"Signals","description":"Include native closed-bar features; chart also adds confirmed-event markers. Crypto only; default response is unchanged.","default":false}},"additionalProperties":false,"type":"object","required":["exchange","market","symbol","interval","calc"],"title":"CalcRequest","description":"Common numeric/chart fields; optional metadata never changes defaults."},"ComputeRequest":{"properties":{"include_forming":{"type":"boolean","title":"Include Forming","description":"With signals=true, evaluate the final forming candle as a complete OHLCV sample. Values, features and objects use the same calculation. Signals append bar_status (closed/forming); forming results may disappear and have no confirmation time. Omit or set false to preserve the original closed-bar behavior.","default":false},"include":{"items":{"type":"string","enum":["signal_reasons","signal_details","calculation","definition"]},"type":"array","maxItems":4,"title":"Include","description":"Optional single-calculation metadata. Signal reasons/details require signals=true. Omit for the original response."},"klines":{"items":{},"type":"array","maxItems":5000,"minItems":1,"title":"Klines","description":"OHLCV bars. Accepts two formats (auto-detected per row):\n  - Nested list: [open_time_ms, open, high, low, close, volume, quote_volume?]  (quote_volume optional, defaults to 0)\n  - Object: {open_time, open, high, low, close, volume, quote_volume?}\nConstraints: open_time monotonically increasing in ms; OHLCV finite floats; count ≤ 2000, or 5000 for HMM-only requests."},"interval":{"anyOf":[{"type":"string","enum":["1m","5m","15m","30m","1h","4h","12h","1d"]},{"type":"null"}],"title":"Interval","description":"Optional bar duration, also used for CVD confirmation close times. When omitted, CVD confirmed_at_ms is null; no duration is inferred from gaps. Required when signals=true, and for hmm_regime (5m/15m/1h/4h/12h/1d). 12h is BYO-only.","examples":["1h"]},"calc":{"items":{"$ref":"#/components/schemas/IndicatorSpec"},"type":"array","minItems":1,"title":"Calc","description":"List of indicators to compute. Same shape as POST /api/indicators (see IndicatorSpec). Cannot be empty.","examples":[[{"name":"rsi","params":{"period":14}}]]},"last_bar_closed":{"type":"boolean","title":"Last Bar Closed","description":"Caller asserts supplied bars are closed by default. Set false when the last bar is still forming; CVD/HMM and native features will not confirm using that bar. All earlier supplied bars must be closed.","default":true},"echo_klines":{"type":"boolean","title":"Echo Klines","description":"Echo the input klines back in the response (under `klines`). Set false to shrink the response when you already have the data.","default":true},"signals":{"type":"boolean","title":"Signals","description":"Include native closed-bar feature series. Requires interval; input must use fixed-duration bars. Honors last_bar_closed. Default response is unchanged.","default":false}},"additionalProperties":false,"type":"object","required":["klines","calc"],"title":"ComputeRequest","description":"Body for POST /api/indicators/compute (bring-your-own klines).\n\nProvides indicator computation against user-supplied OHLCV instead of the\nengine's in-memory store. Use when you have your own data source (backtest,\ncustom feed, offline analysis). No warmup is added — caller must include\nenough history for the indicator to stabilize (ATR/EMA = 200+ bars, etc.)."},"DefinitionResolveRequest":{"properties":{"calc":{"items":{"$ref":"#/components/schemas/IndicatorSpec"},"type":"array","maxItems":100,"minItems":1,"title":"Calc"},"interval":{"anyOf":[{"type":"string","enum":["1m","5m","15m","30m","1h","4h","12h","1d"]},{"type":"null"}],"title":"Interval"}},"additionalProperties":false,"type":"object","required":["calc"],"title":"DefinitionResolveRequest"},"FeatureDefinitionResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Stable feature ID; matches calculation columns and chart signal_ids."},"label":{"type":"string","title":"Label","description":"Human-readable feature name (Chinese)."},"kind":{"type":"string","enum":["event","state"],"title":"Kind","description":"event: occurrence on one bar; state: condition evaluated on each bar. Neither is a trade instruction."},"description":{"type":"string","title":"Description","description":"Judgment rule (Chinese), evaluated with the calculation request's parameters."},"meaning":{"type":"string","title":"Meaning","description":"Interpretation of the feature (Chinese)."},"required_history":{"type":"string","title":"Required History","description":"History and validity requirements; may refer to calculation parameters, not a numeric bar count."},"version":{"type":"integer","minimum":1.0,"title":"Version","description":"Version of this feature definition."},"details":{"items":{"type":"string"},"type":"array","title":"Details","description":"Additional boundaries and confirmation conditions (Chinese); empty when none."},"supports_forming":{"type":"boolean","title":"Supports Forming","description":"Supports include_forming=true final-sample trials; does not imply input readiness or actual close confirmation."}},"type":"object","required":["id","label","kind","description","meaning","required_history","version","details","supports_forming"],"title":"FeatureDefinitionResponse","description":"A feature definition, not an observation or a drawing instruction."},"FeatureDirectoryResponse":{"properties":{"count":{"type":"integer","minimum":0.0,"title":"Count","description":"Number of indicator groups returned after filtering."},"signal_count":{"type":"integer","minimum":0.0,"title":"Signal Count","description":"Number of feature definitions returned after filtering."},"indicators":{"additionalProperties":{"$ref":"#/components/schemas/IndicatorFeatureDefinitionsResponse"},"type":"object","title":"Indicators","description":"Groups keyed by the indicator name used in calc[].name."}},"type":"object","required":["count","signal_count","indicators"],"title":"FeatureDirectoryResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IndicatorCalcRequest":{"properties":{"include_forming":{"type":"boolean","title":"Include Forming","description":"With signals=true, evaluate the final forming candle as a complete OHLCV sample. Values, features and objects use the same calculation. Signals append bar_status (closed/forming); forming results may disappear and have no confirmation time. Omit or set false to preserve the original closed-bar behavior.","default":false},"include":{"items":{"type":"string","enum":["signal_reasons","signal_details","calculation","definition"]},"type":"array","maxItems":4,"title":"Include","description":"Optional single-calculation metadata. Signal reasons/details require signals=true. Omit for the original response."},"exchange":{"type":"string","enum":["binance","bybit","okx","hyperliquid","stock","forex","commodity"],"title":"Exchange","description":"Lowercase exchange id. Use GET /api/markets to list venues.","examples":["binance"]},"market":{"type":"string","enum":["spot","perp","cn","hk","us","futures"],"title":"Market","description":"Lowercase market kind. Crypto futures use 'perp'; commodity supports 'futures' and gold 'spot'.","examples":["perp"]},"symbol":{"type":"string","title":"Symbol","description":"Canonical {BASE}{QUOTE} all-uppercase, no separators. We translate to exchange-native internally; native forms (e.g. 'BTC-USDT-SWAP', 'BTCPERP', 'BTC') return 404.","examples":["BTCUSDT","ETHUSDC","1000PEPEUSDT"]},"interval":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d"],"title":"Interval","description":"Candle interval; case-sensitive lowercase. Check /api/markets for each venue's subset.","examples":["1h"]},"limit":{"type":"integer","minimum":1.0,"title":"Limit","description":"Number of bars to return. Cap differs by endpoint: /api/indicators caps at INDICATOR_CALC_LIMIT (1000); /api/chart caps at MAX_KLINES_BY_INTERVAL[interval] silently.","default":500,"examples":[100,500]},"startTime":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Starttime","description":"Window start in **milliseconds** since Unix epoch. Optional. Indicator warmup is added in front of this automatically. Explicit time windows on subscribed crypto exchange feeds (including Binance equity perpetuals) automatically retrieve available history; no extra option is required.","examples":[1735689600000]},"endTime":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Endtime","description":"Inclusive candle open-time bound in milliseconds. An explicit bound automatically retrieves available exchange history. Optional."},"calc":{"items":{"$ref":"#/components/schemas/IndicatorSpec"},"type":"array","title":"Calc","description":"List of indicators to compute. Cannot be empty (returns 400). Order is preserved in the response, but lookup by key, not index.","examples":[[{"name":"ema","params":{"period":20}},{"name":"rsi","params":{"period":14}}]]},"signals":{"type":"boolean","title":"Signals","description":"Include native closed-bar features; chart also adds confirmed-event markers. Crypto only; default response is unchanged.","default":false}},"additionalProperties":false,"type":"object","required":["exchange","market","symbol","interval","calc"],"title":"IndicatorCalcRequest"},"IndicatorFeatureDefinitionsResponse":{"properties":{"has_signals":{"type":"boolean","title":"Has Signals","description":"Whether this indicator provides native feature output, independent of data readiness."},"signal_status":{"type":"string","enum":["supported","none","unreviewed"],"title":"Signal Status","description":"supported: features available; none: no independent features; unreviewed: no feature decision yet."},"signal_reason":{"type":"string","title":"Signal Reason","description":"Reason for no feature output (Chinese); empty for supported indicators."},"signals":{"items":{"$ref":"#/components/schemas/FeatureDefinitionResponse"},"type":"array","title":"Signals","description":"Definitions matching the query, not calculated values."}},"type":"object","required":["has_signals","signal_status","signal_reason","signals"],"title":"IndicatorFeatureDefinitionsResponse"},"IndicatorSpec":{"properties":{"name":{"type":"string","title":"Name","description":"Indicator name without prefix. Look up valid names + parameter signatures via GET /api/indicators/registry.","examples":["ema","rsi","macd","bollinger","supertrend"]},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"Named keyword arguments passed to calc_<name>. Each indicator has its own parameter set; e.g. ema takes {period}, macd takes {fast, slow, signal}, bollinger takes {period, std_dev}.","examples":[{"period":20},{"fast":12,"signal":9,"slow":26}]},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Optional response-key override. By default the response key is auto-generated as 'name:k1=v1,k2=v2' (params alphabetized). Required only when two `calc` entries would collide on that auto-key (same name + same params).","examples":["ema_short","ema_long"]}},"additionalProperties":false,"type":"object","required":["name"],"title":"IndicatorSpec","description":"One indicator computation request.\n\nDiscover valid `name` values and parameter signatures from\n`GET /api/indicators/registry`. Do not guess parameter names — they must\nmatch the underlying `calc_<name>(df, **params)` signature exactly."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"tags":[{"name":"markets","description":"Discover venues, symbols, intervals."},{"name":"klines","description":"Raw OHLCV data."},{"name":"indicators","description":"Compute indicator values for strategy code."},{"name":"chart","description":"Build chart drawing payloads."},{"name":"system","description":"Health, AGENTS.md, and self-description."}]}