{"openapi":"3.1.0","info":{"title":"Quantustik Public API","description":"S&P 500 market data API: filings, insider and congressional disclosures, earnings, fear and greed. Free, open access.","version":"1.0.0"},"paths":{"/api/v1/health":{"get":{"tags":["public-v1"],"summary":"Health","operationId":"health_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/market/fear-greed":{"get":{"tags":["public-v1"],"summary":"Get Fear Greed","description":"Fear & Greed index (latest cached value).","operationId":"get_fear_greed_api_v1_market_fear_greed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FearGreedResponse"}}}}}}},"/api/v1/earnings/{ticker}":{"get":{"tags":["public-v1"],"summary":"Get Earnings V1","description":"Earnings calendar for one ticker: the next and last reporting dates, and how many days away the next one is.\n\nA risk gate, not a convenience: swing BUYs are suppressed within 5 days\nof earnings. Absence of data returns ``available: false`` with\nHTTP 200 (a normal cold-cache state), never a 404. ``as_of`` anchors\ndata freshness so callers can reason about staleness.","operationId":"get_earnings_v1_api_v1_earnings__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarningsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/market/correlations":{"get":{"tags":["public-v1"],"summary":"Get Correlations","description":"Which S&P 500 stocks have moved together: trailing daily-return correlation.\n\nMeasured data only: the Pearson correlation of each pair's recent actual daily\nreturns. Tickers with no usable price history are reported in ``missing``,\nnever imputed.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_correlations_api_v1_market_correlations_get","parameters":[{"name":"horizon","in":"query","required":false,"schema":{"type":"string","description":"Window label echoed back: 1mo, 3mo, 6mo, or 1y.","default":"3mo","title":"Horizon"},"description":"Window label echoed back: 1mo, 3mo, 6mo, or 1y."},{"name":"top_n","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":2,"description":"Universe size: the first N tickers alphabetically (2-100).","default":50,"title":"Top N"},"description":"Universe size: the first N tickers alphabetically (2-100)."},{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When set, return only this ticker's correlation row, not the full matrix.","title":"Ticker"},"description":"When set, return only this ticker's correlation row, not the full matrix."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorrelationMatrixResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/insider/screener":{"get":{"tags":["public-v1"],"summary":"Get Insider Screener Route","description":"S&P 500 screener: which top-100 tickers have notable insider activity now.\n\n\"Notable\" = a cluster buy (3+ distinct insiders buying within 10 days) or a\nsingle buy that is >=2x that insider's own historical median buy size, in\nthe last 30 days. Empty `results` is a valid, honest answer — most weeks\nhave no qualifying activity. Cached ~2h; a periodic\n``tasks.insider_pulse.refresh_insider_screener`` Procrastinate task keeps\nthat cache warm — this endpoint is cache-read-only and NEVER\ntriggers a live ~100-CIK EDGAR fan-out on a cold miss.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\nNote: registered ABOVE `/insider/{ticker}` — FastAPI matches path\noperations in registration order, and \"screener\" would otherwise be\ncaptured as a literal ticker symbol by the dynamic route below.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_insider_screener_route_api_v1_insider_screener_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/insider/feed":{"get":{"tags":["public-v1"],"summary":"Get Insider Feed Route","description":"Paginated, dated feed of persisted SEC Form 4 insider transactions\nacross the full S&P 500.\n\nUnlike `/insider/screener` (a rolling TOP-100 \"notable this month\"\nsnapshot with no history), this reads the durable ``insider_events``\nPostgres store so callers can page back through real dated\nhistory. Ordering is pure newest-filed-first — cluster-buy and\nunusually-large flags are informational only and do not affect sort.\n\nQuery params:\n- `page` (default 1), `per_page` (default 25, max 100).\n- `window`: lookback in days from today (default 90, max 400 — the\n  store's retention horizon).\n- `type`: optional `\"buy\"` or `\"sell\"` filter on the SEC transaction\n  code; omitted/other values return both.\n- `ticker`: optional single-symbol filter, applied server-side over the\n  whole stored history (so `total` and the page count stay correct under\n  the filter, rather than the caller having to page through everything and\n  filter client-side).\n\nAn empty `items` list with `total: 0` is a valid, honest answer (e.g.\nbefore the first ingestion run, or a quiet window) — never an error.\n\nRead-only surfacing — this is information, not a buy/sell\nrecommendation, and does not feed the model's conviction/signal logic.\n\nNote: registered ABOVE `/insider/{ticker}` — FastAPI matches path\noperations in registration order, and \"feed\" would otherwise be\ncaptured as a literal ticker symbol by the dynamic route below.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_insider_feed_route_api_v1_insider_feed_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Per Page"}},{"name":"window","in":"query","required":false,"schema":{"type":"integer","maximum":400,"minimum":1,"default":90,"title":"Window"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(buy|sell)$"},{"type":"null"}],"title":"Type"}},{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9.\\-]{0,9}$"},{"type":"null"}],"title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/filings/digest":{"get":{"tags":["public-v1"],"summary":"Get Filings Digest Feed Route","description":"Site-wide feed: most recent 8-K filings across the S&P 500 (TOP-100) universe.\n\nEach entry carries a grounded event type (derived from the filing's own\nSEC Item number(s) — never LLM-guessed), a one-line AI summary grounded\nin the actual filing text, and a link to the source accession. Empty\n`filings` is a valid, honest answer for a quiet news day. Cached ~2h; a\nperiodic ``tasks.filings_digest.refresh_8k_feed_digest`` Procrastinate\ntask keeps that cache warm — this endpoint is cache-read-only\nand NEVER triggers a live ~100-CIK EDGAR fan-out on a cold miss.\n\nEach filing also carries `facts` (a list of short statements the company\nmade in the filing, AI-extracted and checked against the filing text) and\n`facts_generated_at`; `facts` is `[]` until the background job has read the\nfiling, so always treat the list as optional.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\nNote: registered ABOVE `/filings/digest/{ticker}` — FastAPI matches path\noperations in registration order, and \"digest\" alone has no ticker\nsegment so this is unambiguous, but kept consistent with the\n`/insider/screener` vs `/insider/{ticker}` ordering convention above.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_filings_digest_feed_route_api_v1_filings_digest_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/filings/digest/10-k":{"get":{"tags":["public-v1"],"summary":"Get Filings 10K Digest Feed Route","description":"Site-wide feed: most recent 10-K annual reports across the S&P 500 (TOP-100) universe.\n\nCompanion to `/filings/digest` (surfaces top 10-Ks alongside the\n8-K card). Unlike the 8-K feed, entries are metadata-only — ticker,\nfiled date, and a link to the source accession, no AI summary — since a\n10-K is far too long to cheaply excerpt/ground a one-liner in. Empty\n`filings` is a valid, honest answer. Cached ~6h; a periodic\n``tasks.filings_digest.refresh_10k_feed_digest`` Procrastinate task keeps\nthat cache warm — this endpoint is cache-read-only and NEVER\ntriggers a live ~100-CIK EDGAR fan-out on a cold miss.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\nNote: registered ABOVE `/filings/digest/{ticker}` for the same reason as\n`/filings/digest` above — \"10-k\" would otherwise be captured as a\nliteral ticker symbol by the dynamic route below.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_filings_10k_digest_feed_route_api_v1_filings_digest_10_k_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/filings/digest/{ticker}":{"get":{"tags":["public-v1"],"summary":"Get Filings Digest Ticker Route","description":"8-K Event Digest — recent 8-K filings for one ticker, AI-summarized.\n\nFor each filing: event type derived from the filing's own SEC Item\nnumber(s) (ground truth, e.g. Item 5.02 = exec departure/appointment,\nItem 2.02 = earnings results, Item 2.01 = M&A completion — never\nLLM-guessed), a one-line AI summary grounded in the actual filed\ndocument text, and a link to the source accession via `accession_url`.\n\nEach filing also carries `facts` (a list of short statements the company\nmade in the filing, AI-extracted and checked against the filing text) and\n`facts_generated_at`; `facts` is `[]` until the background job has read the\nfiling, so always treat the list as optional.\n\nCache-read on the request path: a cold miss (this ticker's\nlatest 8-K hasn't been summarized yet) returns an instant item-label\nentry (`summary_source: \"pending\"`) instead of blocking on an EDGAR\ndoc fetch + LLM call — generation is deferred to a background\nProcrastinate task so the next request serves the real grounded\nsummary. Same precompute/prewarm convention as\n`/api/insights/{ticker}/sector`.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_filings_digest_ticker_route_api_v1_filings_digest__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/filings/feed":{"get":{"tags":["public-v1"],"summary":"Get Filings Feed Route","description":"One dated, page-through history covering every SEC filing form we store.\n\nThe companion `/filings/8-k/feed` below is the same store narrowed to 8-Ks;\nthis endpoint is the whole thing, so a caller can show annual reports and\nmaterial events side by side without stitching two feeds together.\n\nQuery params:\n- `form`: optional SEC form filter — currently `8-K` (material events) or\n  `10-K` (annual reports). Omitted returns every form. A form we do not\n  store is a 400, never a silently-empty page: \"we don't carry that form\"\n  and \"that form had no filings\" are different answers and the caller\n  deserves to be able to tell them apart.\n- `ticker`: optional single-symbol filter.\n- `event_type`: optional narrowing to one broad 8-K category derived from\n  the SEC's own item numbers (e.g. \"earnings\", \"exec_change\").\n- `page` / `per_page`: pagination. The response always carries `total`, so\n  the caller never has to fetch everything to learn how much there is.\n\nBoth filters are applied **server-side**, over the entire stored history —\nnot over the current page — so `total` and the page count remain truthful\nwhile a filter is on.\n\nAn empty result is a valid, honest answer (a quiet news day, or a ticker we\nhave no filings for). This endpoint reads only our own store and never\ncalls SEC EDGAR, so it cannot be made slow — or get us rate-limited — by\ntraffic.\n\nRead-only surfacing of official public-record data — this is information,\nnot a buy/sell recommendation, and does not feed the model's\nconviction/signal logic.","operationId":"get_filings_feed_route_api_v1_filings_feed_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Per Page"}},{"name":"form","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Form"}},{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9.\\-]{0,9}$"},{"type":"null"}],"title":"Ticker"}},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/filings/8-k/feed":{"get":{"tags":["public-v1"],"summary":"Get Filings 8K Feed Route","description":"A dated, page-through history of 8-K filings (the reports a company must file when something material happens).\n\nDifferent from the `/filings/digest` endpoint above, which only ever shows\na rolling snapshot of the current feed and cannot be paged back through.\nThis one is backed by a durable, append-only history, so you can walk back\nas far as it goes. Newest filing first. `event_type` optionally narrows the\nresults to one broad category derived from the SEC's own filing items (for\nexample \"earnings\" or \"exec_change\").\n\nAn empty result is a valid, honest answer — most often a quiet news day.\nThis endpoint never fails because the history store is unavailable; it\ndegrades to an empty page.\n\nEach filing also carries `facts` (a list of short statements the company\nmade in the filing, AI-extracted and checked against the filing text) and\n`facts_generated_at`; `facts` is `[]` until the background job has read the\nfiling, so always treat the list as optional.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_filings_8k_feed_route_api_v1_filings_8_k_feed_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Per Page"}},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"}},{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9.\\-]{0,9}$"},{"type":"null"}],"title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/filings/language-diff/{ticker}":{"get":{"tags":["public-v1"],"summary":"Get Filing Language Diff Route","description":"What changed in the language of one company's latest SEC filing, versus the comparable filing a year (or a quarter) earlier.\n\nCovers the two sections where companies describe what could go wrong and\nhow management reads the business: Risk Factors and Management's\nDiscussion & Analysis.\n\nCites a known academic finding (Cohen, Malloy & Nguyen 2020, \"Lazy\nPrices\", Journal of Finance): YoY changes in 10-K Risk Factors/MD&A\nlanguage are historically return-predictive. The similarity score is a\nreal TF-IDF cosine similarity computed between the two actual filing\nsections; `added_sentences`/`removed_sentences` are a real sentence-level\ndiff. Every entry links to BOTH source filings via `filings[].accession_url`.\n\nAn empty `sections` dict is a valid, honest answer when fewer than 2\nfilings of the requested form are on file, or a section couldn't be\nreliably extracted from both filings (see module docstring in\n`quantum_model/filing_language_diff.py` for known extraction-format\ngaps) — never fabricated.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\nCache-read-only (precompute+cache convention): the expensive diff (two\nmulti-MB filing downloads + sentence-level TF-IDF diff + up to two LLM\ncalls) NEVER runs on this request path. On a cold cache key the response is\n``status=\"pending\"`` (with both source-filing links already populated) and\na background worker computes+caches the diff; a follow-up request serves it.\n\nArgs:\n    form: \"10-K\" (year-over-year, default) or \"10-Q\" (quarter-over-quarter).\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_filing_language_diff_route_api_v1_filings_language_diff__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"form","in":"query","required":false,"schema":{"type":"string","pattern":"^(10-K|10-Q)$","default":"10-K","title":"Form"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/institutional/feed":{"get":{"tags":["public-v1"],"summary":"Get Institutional Feed Route","description":"A dated, page-through feed of institutional 13F holdings — who owns what, and how much.\n\nEach row is one institutional holder × one security × one reported\nquarter: the filer, the security (with its ticker where we can map the\nCUSIP to one we cover), share count, reported dollar value, the quarter it\ncovers, the date it was filed, and a link to the source 13F accession.\nNewest filing first; within a day the larger dollar positions lead.\n\nUnlike `/institutional/{ticker}` (a per-ticker quarter-over-quarter whale\nsummary), this reads the durable ``institutional_holdings`` Postgres store\nso callers can page back through real dated history.\n\nCoverage is deliberately narrow — roughly 50 large institutional filers\nover the last few quarters, NOT all 13F filings. `ticker` optionally\nnarrows to one symbol (server-side, so the `total` stays truthful under the\nfilter); a ticker we don't cover, or a holding whose CUSIP never mapped to\na symbol, yields an honest empty page.\n\nAn empty `items` list with `total: 0` is a valid, honest answer (e.g.\nbefore the first ingestion run) — never an error. This endpoint never hits\nEDGAR; it is a Postgres read only, and degrades to an empty page when the\nstore is unavailable.\n\nNote: registered ABOVE `/institutional/{ticker}` — FastAPI matches path\noperations in registration order, and \"feed\" would otherwise be captured as\na literal ticker symbol by the dynamic route below.\n\nRead-only surfacing of first-source public records — this is information,\nnot a buy/sell recommendation, and does not feed the model's\nconviction/signal logic.","operationId":"get_institutional_feed_route_api_v1_institutional_feed_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Per Page"}},{"name":"window","in":"query","required":false,"schema":{"type":"integer","maximum":400,"minimum":1,"default":400,"title":"Window"}},{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/institutional/{ticker}":{"get":{"tags":["public-v1"],"summary":"Get Institutional Activity Route","description":"What the big institutional investors and activist shareholders are doing in one ticker.\n\n``whale_summary``: QoQ (quarter-over-quarter) change in institutional\nownership across a curated ~50-filer 13F universe — new positions\nopened, positions closed, and the largest increases/decreases by dollar\nvalue between the two most recent 13F quarters on file. Pure computed\ndeltas, no LLM. Institutional filer names come from SEC's own\nsubmissions data (ground truth), and every filer row links to its\nsource 13F accession via `accession_url`.\n\n``activist_alerts``: recent Schedule 13D (activist/control intent) and\n13G (passive >5% stake) filings. 13D entries include a one-line AI\nsummary grounded strictly in the filing's own Item 4 (\"Purpose of\nTransaction\") text when confidently extractable (`summary_source:\n\"llm\"`); otherwise a factual fallback sentence (`summary_source:\n\"item_label\"`) — never invented intent. 13G entries get a structured,\nnon-AI note (`summary_source: \"structured\"`). Every alert links to its\nsource filing via `accession_url`.\n\nAn empty/near-empty result (empty `activist_alerts`, or a `whale_summary`\nwith a `narration` explaining why there's nothing to compute) is a\nvalid, honest answer — never fabricated.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\nCache-read-only: this endpoint NEVER triggers the 13F universe rebuild\n(an EDGAR fan-out over every tracked whale filer) — the periodic\n``tasks.institutional_activity.refresh_institutional_activity``\nProcrastinate task owns generation. On a cold/lapsed cache the payload is\nserved stale-but-labelled (`stale`, `cache_age_hours`, `cache_status`) or\nas an honest \"no data cached yet\" state, rather than blocking the request\non a rebuild.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_institutional_activity_route_api_v1_institutional__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/insider/{ticker}":{"get":{"tags":["public-v1"],"summary":"Get Insider Pulse Route","description":"Insider Pulse — recent SEC Form 4 insider transactions for one ticker.\n\nSurfaces already-ingested Form 4 filings (the same Form 4 data feeding the\nmarket model's `form4` stage) with analytical context per transaction:\nbuyer role (officer/director/10% owner), transaction size vs that\ninsider's own historical buy pattern (`size_vs_own_median`,\n`is_unusually_large`), and cluster-buy detection (`is_cluster` — 3+\ndistinct insiders buying within a 10-day window). Every transaction links\nto its source SEC filing via `accession_url`.\n\nRead-only surfacing — this is information, not a buy/sell recommendation,\nand does not feed the model's conviction/signal logic.\n\nCache-read-only (precompute+cache convention): the fast persisted-store read\nis served directly for covered tickers. For an uncovered long-tail ticker\n(store miss) the expensive live per-symbol FMP fetch NEVER runs on this\nrequest path — the response is ``status=\"pending\"`` and a background worker\nruns+caches the fetch; a follow-up request serves it cache-only.\n\n*Disclaimer: informational only; not investment advice.*","operationId":"get_insider_pulse_route_api_v1_insider__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"CorrelationMatrixResponse":{"properties":{"generated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated At"},"scan_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scan Date"},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method"},"horizon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Horizon"},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode"},"basis":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basis"},"stale":{"type":"boolean","title":"Stale","default":false},"disclaimer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disclaimer"}},"additionalProperties":true,"type":"object","title":"CorrelationMatrixResponse","description":"Cross-ticker entanglement matrix (full or single-ticker shape).\n\n``extra=allow`` so the full-matrix shape (matrix/top_pairs/missing) and the\nsingle-ticker shape (correlations/most_entangled/most_divergent/note) share\none model — the route returns whichever the request selected."},"EarningsLast":{"properties":{"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"eps":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eps"},"eps_estimated":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eps Estimated"},"revenue":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Revenue"},"revenue_estimated":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Revenue Estimated"}},"additionalProperties":true,"type":"object","title":"EarningsLast","description":"Last-reported earnings event (actuals vs. estimates)."},"EarningsNext":{"properties":{"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"eps_estimated":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eps Estimated"},"revenue_estimated":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Revenue Estimated"},"time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time","description":"Session timing: \"amc\" (after close), \"bmo\" (before open), or null."}},"additionalProperties":true,"type":"object","title":"EarningsNext","description":"Next-upcoming earnings event (estimates only — not yet reported)."},"EarningsResponse":{"properties":{"ticker":{"type":"string","title":"Ticker"},"available":{"type":"boolean","title":"Available","default":false},"next":{"anyOf":[{"$ref":"#/components/schemas/EarningsNext"},{"type":"null"}]},"last":{"anyOf":[{"$ref":"#/components/schemas/EarningsLast"},{"type":"null"}]},"days_until_next":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Until Next","description":"How many calendar days from the `as_of` date until the company next reports earnings. Null when we do not know the date."},"as_of":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"As Of","description":"Date the calendar was computed (data-freshness anchor)."}},"additionalProperties":true,"type":"object","required":["ticker"],"title":"EarningsResponse","description":"Per-ticker earnings calendar.\n\nA first-class risk gate: swing BUYs are suppressed within 5 days of\nearnings, so an agent must be able to see the earnings clock to\nreason about overnight gap risk. ``available: false`` (with HTTP 200)\nsignals \"no earnings data\" — a normal cold-cache state, not an error."},"FearGreedResponse":{"properties":{"value":{"anyOf":[{},{"type":"null"}],"title":"Value","description":"Index score, 0 (Extreme Fear) to 100 (Extreme Greed)."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Rating for the score, e.g. \"fear\", \"greed\"."},"timestamp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timestamp","description":"When the index was last updated (ISO 8601)."}},"additionalProperties":true,"type":"object","title":"FearGreedResponse","description":"Fear & Greed index snapshot.\n\n``value`` / ``label`` / ``timestamp`` are the flat, documented contract.\nThe upstream payload nests the same data under ``current``\n({score, rating, updated_at}), which left all three declared fields null on\nthe wire; the route lifts them so the declared shape is the shape actually\nreturned. ``current`` / ``history`` / ``sub_indicator_scores`` still ride\nalong via ``extra=\"allow\"`` for the consumers that already read them."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"}},"additionalProperties":true,"type":"object","required":["status"],"title":"HealthResponse"},"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"}}}}