{"openapi":"3.1.0","info":{"title":"ZeroGEX API","description":"Real-time options analytics API","version":"1.0.0"},"paths":{"/api/signals/trades-history":{"get":{"tags":["Trade Signals"],"summary":"Get Signal History","description":"Closed-trade log with aggregate win/loss statistics.\n\n**Params:** `limit` (1–5000, default 500).\n\n**Returns:**\n```json\n{\n  \"portfolio_size\": 1000000,\n  \"trades\": [\n    {\n      \"id\": 421, \"underlying\": \"SPY\",\n      \"signal_timestamp\": \"...\", \"opened_at\": \"...\", \"closed_at\": \"...\", \"updated_at\": \"...\",\n      \"status\": \"closed\", \"direction\": \"bullish\",\n      \"score_at_entry\": 72.1, \"score_latest\": 64.8,\n      \"option_symbol\": \"SPY 250425C00680000\", \"option_type\": \"call\",\n      \"expiration\": \"2025-04-25\", \"strike\": 680.0,\n      \"entry_price\": 1.22, \"current_price\": 1.55,\n      \"quantity_initial\": 10, \"quantity_open\": 0,\n      \"realized_pnl\": 330.0, \"unrealized_pnl\": 0.0, \"total_pnl\": 330.0,\n      \"pnl_percent\": 27.05,\n      \"outcome\": \"win\"\n    }\n  ],\n  \"summary\": {\n    \"total_trades\": 120, \"wins\": 72, \"losses\": 44,\n    \"win_rate\": 0.6, \"total_pnl\": 12450.32\n  }\n}\n```\n\n- `portfolio_size` — from `SIGNALS_PORTFOLIO_SIZE` env var.\n- `outcome` — `\"win\"` (pnl > 0), `\"loss\"` (pnl < 0), or `\"flat\"`.\n- `win_rate` — 4-decimal fraction; `null` when no trades exist.\n- `score_at_entry` / `score_latest` — MSI composite values (0–100).\n\n**Page design.** Stats header strip (win rate, total P&L, counts);\nsortable/filterable trades table; equity-curve sparkline from cumulative `total_pnl`.","operationId":"get_signal_history_api_signals_trades_history_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":500,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/trades-live":{"get":{"tags":["Trade Signals"],"summary":"Get Live Signals","description":"Open paper/live positions initiated by the signal engine.\n\n**Params:** None.\n\n**Returns:**\n```json\n{\n  \"trades\": [\n    {\n      \"id\": 421, \"underlying\": \"SPY\",\n      \"signal_timestamp\": \"...\", \"opened_at\": \"...\", \"updated_at\": \"...\",\n      \"status\": \"open\", \"direction\": \"bullish\",\n      \"score_at_entry\": 72.1, \"score_latest\": 64.8,\n      \"option_symbol\": \"SPY 250425C00680000\", \"option_type\": \"call\",\n      \"expiration\": \"2025-04-25\", \"strike\": 680.0,\n      \"entry_price\": 1.22, \"current_price\": 1.55,\n      \"quantity_initial\": 10, \"quantity_open\": 10,\n      \"realized_pnl\": 0.0, \"unrealized_pnl\": 330.0, \"total_pnl\": 330.0,\n      \"pnl_percent\": 27.05\n    }\n  ],\n  \"count\": 1\n}\n```\n\n- `direction` — `\"bullish\"` | `\"bearish\"`.\n- `option_type` — `\"call\"` | `\"put\"`.\n- `score_at_entry` / `score_latest` — MSI composite values (0–100).\n- `pnl_percent` — percentage of premium paid.\n\n**Page design.** Card grid: option symbol, direction chip, big P&L number\n(unrealized), MSI-at-entry vs latest delta with a color arrow.","operationId":"get_live_signals_api_signals_trades_live_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/score":{"get":{"tags":["Trade Signals"],"summary":"Get Latest Score","description":"Composite Market State Index (MSI) — single 0–100 regime gauge.\n\nAggregates 6 option-structure components into one reading of \"what kind\nof market are we in right now?\" Each component returns a raw score in\n[-1, +1], multiplied by its weight (points) to form a signed contribution.\nAll contributions are summed onto a 50-point baseline then clamped to [0, 100].\n\n**Params:** `underlying` (default `SPY`). Returns 404 when no rows exist.\n\n**Components and weights:**\n\n| Component | Max pts | What it measures |\n|---|---|---|\n| `net_gex_sign` | 16 | Sign of dealer net gamma |\n| `gamma_anchor` | 30 | Blended proximity to gamma flip / local gamma density / max-gamma strike |\n| `put_call_ratio` | 12 | OI-weighted P/C tilt |\n| `volatility_regime` | 6 | Realized/VIX regime |\n| `order_flow_imbalance` | 19 | Smart-money premium-weighted call vs put flow |\n| `dealer_delta_pressure` | 17 | Dealer net delta forced-hedge direction |\n\n`gamma_anchor` exposes its three sub-signals nested under `context`:\n`flip_distance_subscore`, `local_gamma_subscore`, `price_vs_max_gamma_subscore`,\nplus the active `blend_weights`. Use those for the per-sub-signal breakdown\nthat previously appeared as standalone components.\n\n**Returns:**\n```json\n{\n  \"composite_score\": 63.42,\n  \"components\": {\n    \"net_gex_sign\":          {\"max_points\": 16, \"contribution\":  9.60, \"score\":  0.6},\n    \"gamma_anchor\":          {\n      \"max_points\": 30,\n      \"contribution\":  -2.10,\n      \"score\": -0.07,\n      \"context\": {\n        \"score\": -0.07,\n        \"flip_distance_subscore\":  0.21,\n        \"local_gamma_subscore\":   -0.42,\n        \"price_vs_max_gamma_subscore\": 0.17,\n        \"blend_weights\": {\"flip_distance\": 0.45, \"local_gamma\": 0.35, \"price_vs_max_gamma\": 0.20}\n      }\n    },\n    \"put_call_ratio\":        {\"max_points\": 12, \"contribution\":  2.40, \"score\":  0.2},\n    \"volatility_regime\":     {\"max_points\":  6, \"contribution\": -0.08, \"score\": -0.013},\n    \"order_flow_imbalance\":  {\"max_points\": 19, \"contribution\":  6.65, \"score\":  0.35},\n    \"dealer_delta_pressure\": {\"max_points\": 17, \"contribution\":  3.40, \"score\":  0.2}\n  }\n}\n```\n\n- `composite_score` — float [0, 100]; `50` is the neutral/fallback value.\n- `components[*].max_points` — the component's weight ceiling.\n- `components[*].contribution` — signed points added to the baseline, rounded to 4 decimals.\n- `components[*].score` — raw component score [-1, +1], 6-decimal precision.\n- `components[*].context` — optional, present when the component emits diagnostic\n  sub-fields (e.g. `gamma_anchor` exposes its three subscores here).\n\n**Regime interpretation:**\n- **≥ 70** — trend/expansion; favor directional trades in the prevailing bias.\n- **40–70** — controlled trend; moderate directional edge, size down.\n- **20–40** — chop/range; fade extremes, avoid trend trades.\n- **< 20** — high-risk reversal; mean-reversion only.\n\n**Page design.** Big radial gauge (0–100). Horizontal bar stack below showing\neach component's signed contribution. Hover for `score` and `max_points`.\nFor `gamma_anchor` specifically, render a smaller secondary breakdown of the\nthree subscores from `context` so operators retain visibility into which\nsub-signal is driving the blended reading.","operationId":"get_latest_score_api_signals_score_get","parameters":[{"name":"underlying","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Underlying"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/score-history":{"get":{"tags":["Trade Signals"],"summary":"Get Score History","description":"Time series of the composite MSI, newest-first.\n\n**Params:** `underlying` (default `SPY`), `limit` (default 90, max 5000).\n\n**Returns.** An array of objects with `timestamp`, `composite_score`, and\n`components` (same shape as `/score`). Rows are ordered by `timestamp DESC`\nso index 0 is the most recent. `timestamp` is ISO-8601 UTC of the engine\ncycle that produced the row.\n\n```json\n[\n  {\n    \"timestamp\": \"2026-04-22T18:55:00Z\",\n    \"composite_score\": 63.42,\n    \"components\": {\n      \"net_gex_sign\":          {\"max_points\": 16, \"contribution\":  9.60, \"score\":  0.6},\n      \"gamma_anchor\":          {\"max_points\": 30, \"contribution\": -2.10, \"score\": -0.07,\n                                \"context\": {\"flip_distance_subscore\": 0.21,\n                                            \"local_gamma_subscore\": -0.42,\n                                            \"price_vs_max_gamma_subscore\": 0.17}},\n      \"put_call_ratio\":        {\"max_points\": 12, \"contribution\":  2.40, \"score\":  0.2},\n      \"volatility_regime\":     {\"max_points\":  6, \"contribution\": -0.08, \"score\": -0.013},\n      \"order_flow_imbalance\":  {\"max_points\": 19, \"contribution\":  6.65, \"score\":  0.35},\n      \"dealer_delta_pressure\": {\"max_points\": 17, \"contribution\":  3.40, \"score\":  0.2}\n    }\n  }\n]\n```\n\n**Page design.** Line chart of `composite_score` over `timestamp` with shaded\nregime bands at 20/40/70. Stacked-area chart of component `contribution`\nvalues underneath shows which component flipped the regime.","operationId":"get_score_history_api_signals_score_history_get","parameters":[{"name":"underlying","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Underlying"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":90,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/vol-expansion":{"get":{"tags":["Trade Signals"],"summary":"Get Vol Expansion Signal","description":"Volatility expansion forecast — expansion readiness + directional bias.\n\nAnswers two questions at once: *Will vol expand?* (GEX-driven) and\n*If it does, which way?* (momentum-driven).\n\n**Logic highlights** (`src/signals/advanced/vol_expansion.py`):\n- `expansion = gex_readiness × 100` (0–100); short-gamma regimes raise readiness.\n- `direction_score = tanh(momentum_z / 1.0) × 100` based on a 5-bar z-score.\n- `score = (expansion × direction_score) / 100` — sign matches direction,\n  magnitude gated by expansion readiness.\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\", \"timestamp\": \"...\",\n  \"clamped_score\": 0.42, \"weighted_score\": 0.084, \"weight\": 0.20,\n  \"direction\": \"bullish\",\n  \"score\": 42.0,\n  \"expansion\": 78.4,\n  \"direction_score\": 53.5,\n  \"magnitude\": 41.9,\n  \"expected_5min_move_bps\": 14.2,\n  \"context_values\": { \"...full engine context...\" },\n  \"score_history\": [{\"score\": 42.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100]; product of expansion × direction, scaled.\n- `expansion` — [0, 100]; GEX-driven vol-expansion readiness.\n- `direction_score` — [-100, +100]; momentum-driven directional bias.\n- `magnitude` — [0, 100]; absolute size of the combined signal.\n- `expected_5min_move_bps` — forecasted 5-minute move in basis points.\n- `direction` — `\"bullish\"` | `\"bearish\"` | `\"neutral\"`.\n- `score_history` — up to 90 recent scores; sort client-side by `timestamp`.\n\n**Trader interpretation:**\n- `expansion > 60` + `|direction_score| > 50` → high-conviction expansion;\n  long gamma or directional debit spread in the direction sign.\n- `expansion < 30` → wait; dealers long gamma, likely pinning.\n- Direction-score sign-flip while expansion stays high → whipsaw warning.\n\n**Page design.** Two half-circle gauges (expansion + direction_score), a\n\"expected 5-min move\" number (bps), and a sparkline of `score_history`.\nColor the card green/red by direction when `|score| ≥ 25`.","operationId":"get_vol_expansion_signal_api_signals_advanced_vol_expansion_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/eod-pressure":{"get":{"tags":["Trade Signals"],"summary":"Get Eod Pressure Signal","description":"End-of-day close pin/drift forecast for the last ~75 minutes of the session.\n\nCombines (a) dealer charm exposure near spot, (b) gamma-gated pin gravity,\nand (c) an OpEx/quad-witching calendar amplifier into a directional close forecast.\n\n**Active window: 14:30–16:00 ET only.** Outside this window the endpoint returns\n`score = 0` and `time_ramp = 0` — treat as an \"inactive\" state, not neutral.\n\n**Logic highlights** (`src/signals/advanced/eod_pressure.py`):\n- `time_ramp` — 0 before T-90min, 1.0 by T-15min, linear in between.\n- `charm_score = tanh(charm_at_spot / 20M)` over strikes within the ATM band.\n- `pin_gravity = sign(net_gex) × min(1, pin_distance_pct / 0.3%)`.\n- `score = (0.6·charm + 0.4·pin) × calendar_amp × time_ramp`;\n  `calendar_amp` is 1.5× OpEx, 2.0× quad-witching.\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"score\": 48.1,\n  \"direction\": \"bullish\",\n  \"clamped_score\": 0.48, \"weighted_score\": 0.096, \"weight\": 0.20,\n  \"charm_at_spot\": 12850000.0,\n  \"pin_target\": 676.0,\n  \"pin_distance_pct\": 0.00042,\n  \"gamma_regime\": \"positive\",\n  \"time_ramp\": 0.76,\n  \"calendar_flags\": {\"opex\": false, \"quad_witching\": false},\n  \"context_values\": {\"...atm_band_pct, pin_source, calendar_amp, ...\"},\n  \"score_history\": [{\"score\": 48.1, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100]; positive = bullish close bias, negative = bearish.\n- `direction` — `\"bullish\"` | `\"bearish\"` | `\"neutral\"`.\n- `charm_at_spot` — signed dollar-delta of dealer charm in the ±ATM band.\n- `pin_target` — heavy-GEX strike, or `max_pain` as fallback.\n- `pin_distance_pct` — (pin − spot) / spot; signed; typically ±2%.\n- `gamma_regime` — `\"positive\"` | `\"negative\"` (flips pin-gravity direction).\n- `time_ramp` — [0, 1]; scaling ramp toward close.\n- `calendar_flags` — booleans for `opex` and `quad_witching`.\n\n**Trader interpretation:**\n- `time_ramp > 0.5` + `score > 50` → strong upside pin; trade drift toward `pin_target`.\n- `quad_witching = true` doubles the amplifier; treat `|score| > 60` as high-conviction.\n- Render an \"Inactive — EOD window opens at 14:30 ET\" state when `time_ramp == 0`.\n\n**Page design.** Horizontal close-bias bar (-100..+100). Show `pin_target` vs spot\non a small price axis with distance labeled. Badge for OpEx/quad-witching.\nGreyed-out card when `time_ramp == 0`.","operationId":"get_eod_pressure_signal_api_signals_advanced_eod_pressure_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/squeeze-setup":{"get":{"tags":["Trade Signals"],"summary":"Get Squeeze Setup Signal","description":"Squeeze-setup detector — directional flow z-scores correlated with momentum.\n\nDetects bullish/bearish squeeze setups by correlating directional flow z-scores\nwith momentum acceleration and dealer-gamma posture. Standalone event detector,\nnot part of the MSI composite.\n\n**Logic highlights** (`src/signals/advanced/squeeze_setup.py`):\n- Bullish: `call_flow_z × tanh_scaled(momentum) × momentum_strength × 1.2 (if accelerating)\n  × (1.0 if above flip else 0.6) × (1.0 if net_gex < 0 else 0.5)`.\n- Bearish: symmetric using `put_flow_z`.\n- **Triggered when `|score| ≥ 25` (clamped 0.25).**\n- Dead-VIX regime (`vix_level < 15`) attenuates strength ~50%.\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"score\": 38.0, \"clamped_score\": 0.38, \"direction\": \"bullish\",\n  \"triggered\": true,\n  \"signal\": \"bullish_squeeze\",\n  \"call_flow_delta\": 125000.0, \"put_flow_delta\": -45000.0,\n  \"call_flow_z\": 2.1, \"put_flow_z\": -0.8,\n  \"momentum_z\": 1.4,\n  \"vix_regime\": \"normal\",\n  \"context_values\": {\"...momentum_5bar, momentum_10bar, accel_up, accel_dn, net_gex, gamma_flip, flow_norm_used...\"},\n  \"score_history\": [{\"score\": 38.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100].\n- `signal` — `\"bullish_squeeze\"` | `\"bearish_squeeze\"` | `\"none\"`.\n- `triggered` — `true` when `|score| ≥ 25`.\n- `call_flow_z` / `put_flow_z` — z-scores; typically [-5, +5].\n- `vix_regime` — `\"dead\"` | `\"normal\"` | `\"elevated\"` | `\"panic\"` | `\"unknown\"`.\n\n**Trader interpretation:**\n- `signal == \"bullish_squeeze\"` + `accel_up == true` + price above gamma flip\n  + `net_gex < 0` → classic short-gamma squeeze; long call spreads.\n- `vix_regime == \"dead\"` → cut conviction; dead-vol regimes lack squeeze fuel.\n- `momentum_z` vs flow z-scores divergence: flow without price = early signal;\n  price without flow = exhausted move.\n\n**Page design.** Signal pill (bullish/bearish/none) with `triggered` as a bright dot.\nPaired bar showing `call_flow_z` and `put_flow_z`. VIX regime chip (color-coded).","operationId":"get_squeeze_setup_signal_api_signals_advanced_squeeze_setup_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/trap-detection":{"get":{"tags":["Trade Signals"],"summary":"Get Trap Detection Signal","description":"Trap detector — failed-breakout fade opportunities at gamma walls.\n\nFlags failed breakouts (bull trap / bear trap) as fade opportunities when\ndealer long gamma reinforces a reversal at a resistance/support wall.\nStandalone detector, not part of the MSI composite.\n\n**Logic highlights** (`src/signals/advanced/trap_detection.py`):\n- `breakout_buffer_pct = min(0.1%, 0.15 × realized_sigma × √5)` — vol-scaled noise floor.\n- Upside-fail (bear fade): `close > resistance + buffer` AND `net_gex > 0`\n  AND gamma strengthening AND wall NOT migrating up.\n- Score = `0.4 + 0.4 × distance_strength + 0.2 × gex_boost`, then flow multiplier.\n- **Triggered when `|score| ≥ 25` (clamped 0.25).**\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"score\": -35.0, \"clamped_score\": -0.35, \"direction\": \"bearish\",\n  \"triggered\": true,\n  \"signal\": \"bearish_fade\",\n  \"breakout_up\": true, \"breakout_down\": false,\n  \"net_gex_delta\": 840000000.0,\n  \"net_gex_delta_pct\": 0.018,\n  \"resistance_level\": 680.0,\n  \"support_level\": 678.0,\n  \"breakout_buffer_pct\": 0.0008,\n  \"wall_migrated_up\": false, \"wall_migrated_down\": false,\n  \"context_values\": {\"...close, realized_sigma, long_gamma, gamma_strengthening, call_wall, prior_call_wall, call_flow_decelerating, put_flow_decelerating...\"},\n  \"score_history\": [{\"score\": -35.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100].\n- `signal` — `\"bullish_fade\"` | `\"bearish_fade\"` | `\"none\"`.\n- `triggered` — `true` when `|score| ≥ 25`.\n- `breakout_up` / `breakout_down` — whether price has crossed the buffer.\n- `wall_migrated_up` / `wall_migrated_down` — invalidates the setup when `true`.\n\n**Trader interpretation:**\n- `signal == \"bearish_fade\"` + `breakout_up == true` → price poked above resistance\n  but dealers are long gamma and call wall hasn't migrated; short-call-spread / put-debit.\n- `signal == \"bullish_fade\"` → mirror play at support.\n- `wall_migrated_up == true` → setup invalidated; dealers repositioning with price.\n\n**Page design.** Price ladder showing support / close / resistance with breakout-buffer bands.\nRed/green \"TRAP\" badge when triggered. Two chips: `gamma_strengthening` and `wall_migrated_*`.","operationId":"get_trap_detection_signal_api_signals_advanced_trap_detection_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/0dte-position-imbalance":{"get":{"tags":["Trade Signals"],"summary":"Get Zero Dte Position Imbalance Signal","description":"Same-day-expiry flow tilt — 0DTE call vs put premium imbalance.\n\nMeasures when 0DTE call vs put net premium becomes lopsided enough to\nforecast short-term drift from dealer hedging. Falls back to all-expiry\nflow when 0DTE data is absent, reflected in `flow_source`.\n\n**Logic highlights** (`src/signals/advanced/zero_dte_position_imbalance.py`):\n- Buckets 0DTE flow by moneyness (ATM ±0.5%), weighting OTM most:\n  `0.6·OTM_call − 0.6·OTM_put + 0.3·ATM_call − 0.3·ATM_put + 0.1·ITM − ...`\n- `flow_imbalance = weighted / total_abs` (gated to 0 below $50k gross).\n- Combined = `0.55·flow + 0.30·smart_imbalance + 0.15·pcr_tilt`.\n- Multiplied by a time-of-day ramp (stronger near close, zero after hours).\n- **Triggered when `|score| ≥ 25` (clamped 0.25).**\n\n**Note on time-gating:** `tod_multiplier` zeros after hours — treat as\n\"inactive,\" not \"neutral.\"\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"score\": 31.0, \"clamped_score\": 0.31, \"direction\": \"bullish\",\n  \"triggered\": true,\n  \"signal\": \"call_heavy\",\n  \"flow_imbalance\": 0.42,\n  \"smart_imbalance\": 0.18,\n  \"context_values\": {\"...call_net_premium, put_net_premium, otm_call_net, atm_call_net, otm_put_net, atm_put_net, pcr_tilt, put_call_ratio, tod_multiplier, flow_source...\"},\n  \"score_history\": [{\"score\": 31.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100].\n- `signal` — `\"call_heavy\"` | `\"put_heavy\"` | `\"balanced\"`.\n- `triggered` — `true` when `|score| ≥ 25`.\n- `flow_imbalance` — [-1, +1]; bucket-weighted net imbalance.\n- `smart_imbalance` — [-1, +1]; smart-money subset.\n- `flow_source` (in `context_values`) — `\"zero_dte\"` | `\"all_expiry_fallback\"`.\n\n**Trader interpretation:**\n- `call_heavy` near close with rising momentum → lean long (dealers short 0DTE calls must chase).\n- `put_heavy` near close with falling momentum → lean short.\n- Warn when `flow_source == \"all_expiry_fallback\"`: 0DTE picture is inferred, not measured.\n\n**Page design.** Diverging bar chart with four moneyness buckets (OTM/ATM calls vs OTM/ATM puts).\n`flow_source` chip + `tod_multiplier` as a clock/progress indicator.","operationId":"get_zero_dte_position_imbalance_signal_api_signals_advanced_0dte_position_imbalance_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/gamma-vwap-confluence":{"get":{"tags":["Trade Signals"],"summary":"Get Gamma Vwap Confluence Signal","description":"Gamma+VWAP confluence detector — multi-level price cluster magnet.\n\nDetects when multiple reference levels (gamma flip, VWAP, max pain, max gamma,\ncall wall) cluster near the same price, creating a high-conviction magnet or\nbounce level.\n\n**Logic highlights** (`src/signals/advanced/gamma_vwap_confluence.py`):\n- Requires flip + VWAP within 0.15% of midpoint; adds max_pain / max_gamma /\n  call_wall if also within 0.15%.\n- `cluster_quality = max(0, 1 − cluster_gap_pct / 0.5%)`;\n  multi-member bonus `1.0 + 0.15 × extra_members`.\n- `net_gex < 0` → continuation (bullish if price above, bearish below);\n  long gamma → mean reversion (`−0.7 × directional`).\n- **Triggered when `|score| ≥ 20` (clamped 0.20).**\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"score\": 22.0, \"clamped_score\": 0.22, \"direction\": \"bullish\",\n  \"triggered\": true,\n  \"signal\": \"bullish_confluence\",\n  \"confluence_level\": 678.25,\n  \"cluster_gap_pct\": 0.0009,\n  \"gamma_flip\": 677.82, \"vwap\": 678.10,\n  \"max_pain\": 678.0, \"max_gamma\": 678.5, \"call_wall\": 681.0,\n  \"expected_target\": 680.5,\n  \"context_values\": {\"...gamma_flip, vwap, max_pain, max_gamma, call_wall, cluster_gap_pct, cluster_members, cluster_quality, distance_from_level_pct, regime_direction, net_gex...\"},\n  \"score_history\": [{\"score\": 22.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100].\n- `signal` — `\"bullish_confluence\"` | `\"bearish_confluence\"` | `\"neutral\"`.\n- `triggered` — `true` when `|score| ≥ 20`.\n- `confluence_level` — price of the cluster midpoint.\n- `cluster_gap_pct` — |flip − vwap| / close; [0, ~0.005].\n- `gamma_flip`, `vwap`, `max_pain`, `max_gamma`, `call_wall` — raw input\n  levels used in the computation; `null` when unavailable. Always present\n  regardless of whether the level ended up in `cluster_members`.\n- `expected_target` — reversion target (mean-reversion) or extrapolated (continuation).\n- `regime_direction` (in `context_values`) — `\"mean_reversion\"` | `\"continuation\"`.\n\n**Trader interpretation:**\n- `signal == \"bullish_confluence\"` + `cluster_quality > 0.8` + `regime_direction == \"mean_reversion\"`:\n  `confluence_level` is a buy zone; `expected_target` is the reversion target.\n- `regime_direction == \"continuation\"` (short gamma): breaks tend to run;\n  use `expected_target` as the first profit taker.\n\n**Page design.** Vertical price axis with cluster members as colored tick marks and\n`confluence_level` as a bold band. Arrow from current price to `expected_target`.\nRegime chip (\"reversion\" vs \"continuation\").","operationId":"get_gamma_vwap_confluence_signal_api_signals_advanced_gamma_vwap_confluence_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/range-break-imminence":{"get":{"tags":["Trade Signals"],"summary":"Get Range Break Imminence Signal","description":"Range-break imminence — regime-switch detector between chop and breakout.\n\nFuses four orthogonal inputs into a 0–100 imminence score so the\ndashboard can flip between *fade the range* and *follow the break*\nwithout the operator reading four panels at once. Standalone detector,\nnot part of the MSI composite.\n\n**Logic highlights** (`src/signals/advanced/range_break_imminence.py`):\n- Skew extreme (30%): OTM-put vs OTM-call IV deviation vs baseline.\n- Dealer delta pressure (25%): signed dealer net delta (explicit or\n  rolled up from `gex_by_strike` delta-OI columns).\n- Trap detection (25%): price pinned within ¼ of a 20-bar range\n  extreme while flow accelerates *against* that extreme's fade.\n- Volatility compression (20%): 10-bar / 60-bar realized sigma ratio.\n- Directional bias = weighted avg of the three directional inputs;\n  compression is directionless (adds magnitude only).\n- Imminence = weighted sum of absolute sub-scores; `score` = signed\n  direction × (imminence / 100).\n- **Triggered when `imminence ≥ 65` (entering the Break Watch band).**\n\n**Params:** `symbol` (default `SPY`). Returns 404 when no data exists.\n\n**Returns:**\n```json\n{\n  \"score\": -62.0, \"clamped_score\": -0.62, \"direction\": \"bearish\",\n  \"triggered\": true,\n  \"signal\": \"bearish_break_imminent\",\n  \"imminence\": 72.4,\n  \"label\": \"Break Watch\",\n  \"playbook\": \"Stop blindly fading lows. Only fade after failed breakouts/reclaims; start preparing continuation entries.\",\n  \"bias\": -0.58,\n  \"context_values\": {\"...skew, dealer, trap, compression, weights...\"},\n  \"score_history\": [{\"score\": -62.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` — [-100, +100]; sign = break direction, magnitude = imminence.\n- `signal` — `\"range_fade\"` | `\"bearish_break_imminent\"` |\n  `\"bullish_break_imminent\"` | `\"break_watch_neutral\"`.\n- `imminence` — [0, 100]; composite break risk magnitude.\n- `label` — `\"Range Fade\"` (0–39) | `\"Weak Range\"` (40–64) |\n  `\"Break Watch\"` (65–79) | `\"Breakout Mode\"` (80–100).\n- `playbook` — trader-facing guidance string matching the label.\n- `triggered` — `true` when `imminence ≥ 65`.\n\n**Trader interpretation:**\n- `label == \"Range Fade\"` → fade extremes normally.\n- `label == \"Weak Range\"` → still fade, but smaller size / faster targets.\n- `label == \"Break Watch\"` → stop blindly fading; prepare retest trades.\n- `label == \"Breakout Mode\"` + direction set → trade the retest of the\n  broken level rather than fading back into the range.\n\n**Page design.** Half-circle gauge (0–100) colored by direction with the\nlabel badge below. Four-bar stack chart of sub-score contributions\n(skew / dealer / trap / compression). Playbook text under the gauge.\nFlip the card's accent color between \"fade\" (neutral) and \"follow\"\n(break) colors at the 65-imminence threshold.","operationId":"get_range_break_imminence_signal_api_signals_advanced_range_break_imminence_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic":{"get":{"tags":["Trade Signals"],"summary":"Get Basic Signals Bundle","description":"Latest snapshot of all six Basic Signals in a single round-trip.\n\nBasic Signals are continuous directional reads (clamped to `[-1, +1]`,\nscaled to `[-100, +100]`) that complement the 6 MSI components and 6\nAdvanced Signals. They do **not** contribute to the composite MSI\n(weight=0). Each entry is the most recent row persisted to\n`signal_component_scores` by `BasicSignalEngine` each cycle.\n\nUse this to populate a dashboard overview without firing six separate\nrequests. Click-through to the individual `/api/signals/basic/{name}`\nendpoint for signal-specific decomposition and history.\n\n**Signals (6, fixed order):** `tape_flow_bias`, `skew_delta`,\n`vanna_charm_flow`, `dealer_delta_pressure`, `gex_gradient`,\n`positioning_trap`.\n\n**Params:**\n- `symbol` (default `SPY`).\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\",\n  \"signals\": {\n    \"tape_flow_bias\":        {\"score\": 28.4,  \"clamped_score\": 0.284,  \"direction\": \"bullish\", \"timestamp\": \"2026-04-22T18:55:00Z\", \"context_values\": {...}},\n    \"skew_delta\":            {\"score\": -12.7, \"clamped_score\": -0.127, \"direction\": \"bearish\", \"timestamp\": \"...\", \"context_values\": {...}},\n    \"vanna_charm_flow\":      {\"score\": 0.0,   \"clamped_score\": 0.0,    \"direction\": \"neutral\", \"timestamp\": \"...\", \"context_values\": {...}},\n    \"dealer_delta_pressure\": {\"score\": 45.1,  \"clamped_score\": 0.451,  \"direction\": \"bullish\", \"timestamp\": \"...\", \"context_values\": {...}},\n    \"gex_gradient\":          {\"score\": -8.3,  \"clamped_score\": -0.083, \"direction\": \"bearish\", \"timestamp\": \"...\", \"context_values\": {...}},\n    \"positioning_trap\":      null\n  }\n}\n```\n\n- `signals[name]` — `null` when the signal has never persisted a row\n  for this symbol (first-deployment case). Render `\"—\"` in the UI, not `0`.\n- `signals[name].score` — `clamped_score × 100`; `[-100, +100]`; 2 decimals.\n- `signals[name].clamped_score` — raw `[-1, +1]`.\n- `signals[name].direction` — `\"bullish\"` | `\"bearish\"` | `\"neutral\"` (sign of score).\n- `signals[name].timestamp` — ISO-8601 UTC of the engine cycle.\n- `signals[name].context_values` — signal-specific inputs/derived fields;\n  same keys as the per-signal endpoint.\n\n**Trader interpretation.**\n- **All six aligned** (same sign) → high-conviction regime; follow the direction.\n- **Flow side** (`tape_flow_bias`, `positioning_trap`) **diverging from structure**\n  (`gex_gradient`, `vanna_charm_flow`) → potential reversal; flow leads structure intraday.\n- **`0.0` during market hours** → signal *abstained* (below its data threshold),\n  not \"neutral conviction.\" Don't treat as a bearish read.\n\n**Page design.** Six KPI tiles in a 3×2 grid. Each tile: direction chip\n(green/red/gray), large `score` number, signal label. Click-through to\nthe `/api/signals/basic/{name}` detail view. Null tiles render as `\"—\"`.\nPoll this endpoint together with `/basic/confluence-matrix` at cycle cadence.","operationId":"get_basic_signals_bundle_api_signals_basic_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/tape-flow-bias":{"get":{"tags":["Trade Signals"],"summary":"Get Tape Flow Bias Signal","description":"Signed option-tape premium imbalance — continuous order-flow bias.\n\nAnswers: *right now, is the tape aggressively buying calls and selling\nputs (bullish) or the reverse (bearish)?* The ingestion layer\nLee-Ready-classifies every print into `buy_premium` / `sell_premium`;\nthis signal nets them and scores the per-side imbalance. Unlike\n`smart_money` (discrete \"large premium\" events), this watches the\ncontinuous tape — gives an earlier read on directional conviction.\n\n**Logic highlights** (`src/signals/basic/tape_flow_bias.py`):\n- `call_net = call_buy_premium − call_sell_premium` (aggressor side).\n- `put_net  = put_buy_premium  − put_sell_premium`.\n- `directional = call_net − put_net` (call buying = bullish; put buying = bearish).\n- `ratio = directional / (|call_net| + |put_net|)` in `[-1, +1]`.\n- `score = clip(ratio / SIGNAL_TAPE_FLOW_SATURATION, [-1, 1])` (default saturation 0.6).\n- **Abstains (score=0)** if `|call_net| + |put_net| < SIGNAL_TAPE_FLOW_MIN_PREMIUM`\n  (default $250K). Treat abstention as \"no data,\" not neutral conviction.\n\n**Params:**\n- `symbol` (default `SPY`). Returns 404 if no row exists yet.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\",\n  \"timestamp\": \"2026-04-22T18:55:00Z\",\n  \"clamped_score\": 0.28, \"score\": 28.0, \"direction\": \"bullish\",\n  \"weighted_score\": 0.0, \"weight\": 0.0,\n  \"call_net_premium\": 312000.0,\n  \"put_net_premium\": -85000.0,\n  \"source\": \"flow_by_type\",\n  \"context_values\": {\n    \"call_net_premium\": 312000.0, \"put_net_premium\": -85000.0,\n    \"call_buy_premium\": 450000.0, \"call_sell_premium\": 138000.0,\n    \"put_buy_premium\": 120000.0, \"put_sell_premium\": 205000.0,\n    \"source\": \"flow_by_type\"\n  },\n  \"score_history\": [{\"score\": 12.4, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` / `clamped_score` — `[-100, +100]` / `[-1, +1]`. `+` = calls bought / puts sold.\n- `direction` — `\"bullish\"` | `\"bearish\"` | `\"neutral\"` (sign of score).\n- `call_net_premium` / `put_net_premium` — USD, signed. `+` = net aggressor buying.\n- `source` — `\"flow_by_type\"` (data present) | `\"unavailable\"` (abstained).\n- `context_values` — the four per-side premium totals plus `source`.\n- `score_history` — up to 90 recent `{score, timestamp}` points, oldest→newest.\n\n**Trader interpretation.**\n- `score > +50` with flat price → early bullish accumulation; potential breakout.\n- `score < −50` with flat price → early distribution; watch for breakdown.\n- Score **sign-flips** while price keeps trending → exhaustion warning.\n- Score ≈ 0 during market hours with `source=\"unavailable\"` → thin tape, not neutral.\n\n**Page design.** Horizontal bidirectional bar (−100 → +100) with center\nneedle, green right / red left. Below: stacked bar of the four premium\ncomponents so the trader sees *which side* drives the imbalance.\nSparkline of `score_history` (90 pts) beneath. Footer chip shows `source`.","operationId":"get_tape_flow_bias_signal_api_signals_basic_tape_flow_bias_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/skew-delta":{"get":{"tags":["Trade Signals"],"summary":"Get Skew Delta Signal","description":"Short-dated OTM put-vs-call IV deviation — real-time fear gauge.\n\nAnswers: *are traders paying an unusual premium for downside protection\nright now?* Equity-index skew is structurally positive (OTM puts always\ntrade richer than OTM calls), so this signal scores the **deviation\nfrom normal**, not the raw spread. Bid-up put skew typically moves\n*before* the tape confirms bearishness — useful leading-indicator.\n\n**Logic highlights** (`src/signals/basic/skew_delta.py`):\n- `spread = otm_put_iv − otm_call_iv` from `ctx.extra['skew']`\n  (populated by the unified engine from `option_chains` near ATM).\n- `deviation = spread − SIGNAL_SKEW_BASELINE` (default baseline 0.02).\n- `score = −clip(deviation / SIGNAL_SKEW_SATURATION, [-1, 1])`\n  (default saturation 0.04). Negative sign: elevated put skew → bearish.\n- **Abstains (score=0)** if `otm_put_iv` or `otm_call_iv` is missing.\n\n**Params:**\n- `symbol` (default `SPY`). Returns 404 if no row exists yet.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\", \"timestamp\": \"...\",\n  \"clamped_score\": -0.35, \"score\": -35.0, \"direction\": \"bearish\",\n  \"weighted_score\": 0.0, \"weight\": 0.0,\n  \"otm_put_iv\": 0.192,\n  \"otm_call_iv\": 0.147,\n  \"spread\": 0.045,\n  \"deviation\": 0.025,\n  \"context_values\": {\n    \"otm_put_iv\": 0.192, \"otm_call_iv\": 0.147,\n    \"spread\": 0.045, \"baseline\": 0.02, \"deviation\": 0.025\n  },\n  \"score_history\": [{\"score\": -14.1, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` / `clamped_score` — `[-100, +100]` / `[-1, +1]`; negative = fear bid.\n- `otm_put_iv` / `otm_call_iv` — IV as a fraction (e.g. `0.18` = 18%). `null` if missing.\n- `spread` — `otm_put_iv − otm_call_iv`; typically `[0, 0.10]` for SPY. `null` if missing.\n- `deviation` — `spread − baseline`; sign drives the score (positive → bearish score).\n- `context_values` — the above plus `baseline` (the neutral-skew reference).\n- `score_history` — up to 90 recent points.\n\n**Trader interpretation.**\n- `score < −40` → meaningful fear bid; tighten longs, consider downside hedges.\n- `score > +30` (rare, call skew) → potential upside squeeze / short-covering setup.\n- Steady negative drift while price rallies → distribution / bull-trap warning.\n- `otm_put_iv == null` → no short-dated data this cycle; not the same as neutral.\n\n**Page design.** Bidirectional ±100 gauge labeled \"fear\" (left) / \"euphoria\"\n(right). Below, a two-line mini-chart of `otm_put_iv` and `otm_call_iv` as\n% IV over `score_history` length, with a horizontal reference line at\n`baseline` (the \"normal skew\" line). Color the gauge card red when\n`score ≤ -40`, green when `score ≥ +30`.","operationId":"get_skew_delta_signal_api_signals_basic_skew_delta_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/vanna-charm-flow":{"get":{"tags":["Trade Signals"],"summary":"Get Vanna Charm Flow Signal","description":"Second-order greek dealer-hedging pressure (vanna + charm).\n\nAnswers: *which way are dealers being forced to trade right now from IV\nmoves and time decay, independently of spot moves?*\n\n- **Vanna** (dVega/dSpot) — dealer delta changes when IV moves. Morning\n  IV crush forces vanna-short dealers to buy underlying (the classic\n  \"vol-crush rally\" that kills naked put sellers).\n- **Charm** (dDelta/dTime) — decay of short-dated deltas toward expiry.\n  In the final ~2h, charm-short dealers short calls above spot are\n  forced to sell into weakness — accelerates afternoon drift.\n\n**Logic highlights** (`src/signals/basic/vanna_charm_flow.py`):\n- Sum `dealer_vanna_exposure` + `dealer_charm_exposure × charm_amplification`\n  across all strikes in `gex_by_strike`.\n- `charm_amplification` — 1.0 most of the day, ramps to 1.5 in the final\n  ~40% of the session (charm flow dominates into the close).\n- `score = clip(combined / vc_norm, [-1, 1])`; `vc_norm` defaults to 5e7\n  (may be scaled per symbol via `normalizers`).\n- **Abstains (score=0)** if `gex_by_strike` is empty.\n- Legacy rows (no dealer columns) fall back to negated market-aggregate\n  exposures — signal still valid, less precise.\n\n**Sign convention:** `+` score = dealer buying pressure (bullish tailwind);\n`−` score = dealer selling pressure (bearish headwind).\n\n**Params:**\n- `symbol` (default `SPY`). Returns 404 if no row exists yet.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\", \"timestamp\": \"...\",\n  \"clamped_score\": 0.42, \"score\": 42.0, \"direction\": \"bullish\",\n  \"weighted_score\": 0.0, \"weight\": 0.0,\n  \"vanna_total\": 18500000.0,\n  \"charm_total\": 9200000.0,\n  \"charm_amplification\": 1.18,\n  \"source\": \"dealer_exposure\",\n  \"context_values\": {\n    \"vanna_total\": 18500000.0, \"charm_total\": 9200000.0,\n    \"charm_amplification\": 1.18, \"vc_norm\": 50000000.0,\n    \"source\": \"dealer_exposure\"\n  },\n  \"score_history\": [{\"score\": 31.2, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` / `clamped_score` — `[-100, +100]` / `[-1, +1]`; `+` = bullish.\n- `vanna_total` — sum of dealer vanna exposure; `+` = dealer delta grows with spot ↑.\n- `charm_total` — sum of dealer charm exposure; `+` = dealer delta grows with time.\n- `charm_amplification` — `[1.0, 1.5]`; session-time multiplier. `1.5` = final 40%.\n- `source` — `\"dealer_exposure\"` | `\"market_exposure_negated\"` (legacy fallback) | `\"unavailable\"`.\n- `context_values` — the above plus `vc_norm` (saturation denominator).\n- `score_history` — up to 90 recent points.\n\n**Trader interpretation.**\n- `score > +40` in the morning → vanna-driven melt-up; trend-follow upside.\n- `score < −40` in the final 90 minutes → charm-driven afternoon fade; momentum shorts.\n- Crosses zero into the afternoon → pressure reversal; trim directional size.\n- `charm_amplification = 1.5` means we're in the EOD acceleration window.\n- `source = \"market_exposure_negated\"` → lower-precision fallback; widen thresholds.\n\n**Page design.** Two stacked horizontal bars: `vanna_total` and\n`charm_total × charm_amplification`, colored by sign. A small clock gauge\nshows `charm_amplification` on a 1.0→1.5 scale as \"time pressure.\"\nComposite `score` as a big number + direction chip on top. Source chip in footer.","operationId":"get_vanna_charm_flow_signal_api_signals_basic_vanna_charm_flow_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/dealer-delta-pressure":{"get":{"tags":["Trade Signals"],"summary":"Get Dealer Delta Pressure Signal","description":"Dealer net-delta imbalance (DNI) — intraday leading indicator.\n\nAnswers: *are dealers net-short delta (forced to buy rallies, bullish)\nor net-long (forced to sell rallies, bearish)?* Delta flow leads gamma\nexposure by minutes intraday — closest thing to a leading indicator\nfor 0DTE regimes. Gamma tells you *where* dealers will hedge; delta\ntells you *how much they already are*.\n\n**Logic highlights** (`src/signals/basic/dealer_delta_pressure.py`).\nThree data paths in priority order:\n1. `ctx.dealer_net_delta` — if populated upstream, used directly.\n2. `gex_by_strike.{call_delta_oi, put_delta_oi}` — sum\n   `−(call_delta_oi + put_delta_oi)` across strikes (dealer sign is\n   flipped from customer OI; customers are typically long calls & puts).\n3. Distance-proxy fallback — use `call_oi` / `put_oi` with a linear\n   delta proxy (0.5 at ATM, decaying to 0 at ±5% OTM), ×100 shares/contract.\n\n- `score = −clip(dni / SIGNAL_DNI_NORM, [-1, 1])` (default norm ~$3e8\n  shares-equivalent). **Inverted**: dealer short delta (negative DNI)\n  scores bullish, because they must buy into strength.\n- **Abstains (score=0)** if no data path yields an estimate.\n\n**Params:**\n- `symbol` (default `SPY`). Returns 404 if no row exists yet.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\", \"timestamp\": \"...\",\n  \"clamped_score\": 0.45, \"score\": 45.1, \"direction\": \"bullish\",\n  \"weighted_score\": 0.0, \"weight\": 0.0,\n  \"dealer_net_delta_estimated\": -135000000.0,\n  \"dni_normalized\": -0.45,\n  \"source\": \"gex_by_strike.delta_oi\",\n  \"context_values\": {\n    \"dealer_net_delta_estimated\": -135000000.0,\n    \"dni_normalized\": -0.45,\n    \"source\": \"gex_by_strike.delta_oi\"\n  },\n  \"score_history\": [{\"score\": 28.1, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` / `clamped_score` — `[-100, +100]` / `[-1, +1]`; `+` = bullish.\n- `dealer_net_delta_estimated` — shares-equivalent, signed.\n  Negative = dealer net **short** delta (bullish for price after inversion).\n- `dni_normalized` — `dni / DNI_NORM` clipped to `[-1, +1]`.\n  **Sign is opposite the score** (signal is inverted).\n- `source` — data-path quality:\n  `\"dealer_net_delta_field\"` (best) | `\"gex_by_strike.delta_oi\"` |\n  `\"gex_by_strike.distance_proxy\"` (weakest) | `\"unavailable\"`.\n- `score_history` — up to 90 recent points.\n\n**Trader interpretation.**\n- `score > +60` → dealers deeply short delta; any up-move likely accelerated\n  (chase risk). Favor long-delta plays (calls, long futures).\n- `score < −60` → dealers net long; rallies will be sold into. Favor\n  mean-reversion or short-delta debit spreads.\n- `source = \"gex_by_strike.distance_proxy\"` → fallback-quality estimate;\n  widen conviction threshold before acting.\n- **Cross-signal:** when this disagrees with `gex_gradient` (structural\n  view), trust `dealer_delta_pressure` on a ≤ 30m horizon.\n\n**Page design.** Single horizontal ±100 bar labeled \"Dealer Delta Pressure.\"\nSubtext: `\"Dealers short delta → bullish\"` on `+` side;\n`\"Dealers long delta → bearish\"` on `−` side. Data-quality chip shows\nthe `source` value. Sparkline of `score_history` beneath.","operationId":"get_dealer_delta_pressure_signal_api_signals_basic_dealer_delta_pressure_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/gex-gradient":{"get":{"tags":["Trade Signals"],"summary":"Get Gex Gradient Signal","description":"Gamma asymmetry around spot — above- vs below-spot dealer gamma skew.\n\nAnswers: *is dealer gamma stacked above or below current price, and\nhow does that bias the next move?* Decomposes per-strike gamma\nexposure into four zones (above / below spot, ATM, wings) and scores\nthe asymmetry, flipping sign and damping under long-gamma regimes.\n\n- Heavy **above-spot** concentration + short gamma → any up-move\n  unwinds → **bullish**. Below-spot mirror is **bearish**.\n- Under **long-gamma** the same concentration acts as resistance\n  instead of fuel, so the signal is inverted and damped.\n\n**Logic highlights** (`src/signals/basic/gex_gradient.py`):\n- Classify each strike in `gex_by_strike` by `(strike − spot) / spot`:\n  above/below, plus ATM (`≤ ±1.5%`) and wing (`≥ ±4%`) tags.\n- `asymmetry = (above_abs − below_abs) / (above_abs + below_abs)` ∈ `[-1, +1]`.\n- `raw = asymmetry` if `net_gex < 0`, else `−asymmetry × 0.40`\n  (`SIGNAL_GEX_GRADIENT_LONG_GAMMA_DAMPING`).\n- `confidence = max(0.25, 1 − wing_fraction)` — wings pin, kill directional edge.\n- `score = clip(raw × confidence, [-1, 1])`.\n- **Abstains (score=0)** if total gamma `< SIGNAL_GEX_GRADIENT_MIN_GAMMA`\n  (default 5e7 — thin-OI guard).\n\n**Params:**\n- `symbol` (default `SPY`). Returns 404 if no row exists yet.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\", \"timestamp\": \"...\",\n  \"clamped_score\": 0.38, \"score\": 38.0, \"direction\": \"bullish\",\n  \"weighted_score\": 0.0, \"weight\": 0.0,\n  \"above_spot_gamma_abs\": 72500000.0,\n  \"below_spot_gamma_abs\": 31200000.0,\n  \"asymmetry\": 0.3986,\n  \"wing_fraction\": 0.21,\n  \"context_values\": {\n    \"source\": \"gex_by_strike\",\n    \"above_spot_gamma_abs\": 72500000.0, \"below_spot_gamma_abs\": 31200000.0,\n    \"atm_gamma_abs\": 45800000.0, \"wing_gamma_abs\": 21900000.0,\n    \"above_spot_gamma_signed\": 54300000.0, \"below_spot_gamma_signed\": -18700000.0,\n    \"wing_fraction\": 0.21, \"asymmetry\": 0.3986, \"strike_count\": 42\n  },\n  \"score_history\": [{\"score\": 22.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` / `clamped_score` — `[-100, +100]` / `[-1, +1]`.\n- `above_spot_gamma_abs` / `below_spot_gamma_abs` — `|Σ gamma|` for each side; USD-scaled. `null` if `source=\"unavailable\"`.\n- `asymmetry` — `[-1, +1]`; pre-regime adjustment. Matches score sign under `net_gex < 0`, flipped under `net_gex > 0`.\n- `wing_fraction` — `[0, 1]`; share of total `|gamma|` at wing strikes (`> ±4%` OTM).\n- `context_values.atm_gamma_abs` / `wing_gamma_abs` — absolute gamma in each bucket.\n- `context_values.above_spot_gamma_signed` / `below_spot_gamma_signed` — signed sums.\n- `context_values.strike_count` — int; strikes surveyed. Thin data → widen thresholds.\n- `context_values.source` — `\"gex_by_strike\"` | `\"unavailable\"`.\n\n**Trader interpretation.**\n- `score > +50` with `net_gex < 0` → classic short-gamma upside setup;\n  dealers will chase. Favor calls.\n- `score < −50` with `net_gex < 0` → short-gamma downside setup; dealers\n  accelerate flush.\n- **Strong score with `net_gex > 0`** → structural resistance in that\n  direction; fade instead of follow.\n- `wing_fraction > 0.5` → confidence already reduced by code; treat score\n  as weak even if magnitude is high.\n- `strike_count < 10` → sparse data; widen threshold.\n\n**Page design.** Four-zone horizontal strike map centered on spot: above-\nand below-spot buckets as mirrored bars, intensity by `|signed gamma|`.\nSeparate ATM / wing donut slices showing concentration share. `asymmetry`\ngauge (−1 → +1). Regime chip (`net_gex > 0` vs `< 0`) since the same\nasymmetry has opposite implications in each regime.","operationId":"get_gex_gradient_signal_api_signals_basic_gex_gradient_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/positioning-trap":{"get":{"tags":["Trade Signals"],"summary":"Get Positioning Trap Signal","description":"Crowd-positioning trap — squeeze/flush risk from one-way crowding.\n\nFlags setups where tape behavior is starting to invalidate crowd\ndirection — the classic squeeze/flush patterns.\n\n- **`+score` (squeeze risk):** puts crowded + aggressive put-buying +\n  up-momentum + price above gamma flip + short-gamma regime →\n  upside squeeze fuel.\n- **`−score` (flush risk):** calls crowded + aggressive call-buying +\n  down-momentum + price below gamma flip + short-gamma → downside\n  air-pocket.\n\nUses **signed** net smart-money premium (`buy − sell`) from\n`flow_contract_facts` when available — more informative than legacy\ntotal_premium because opposite-side buying nets out (a big put-buy\n+ big put-sell should *not* count as crowd skew).\n\n**Logic highlights** (`src/signals/basic/positioning_trap.py`):\n```\nshort_crowding = clip((put_call_ratio − 1.05) / 0.35, [0, 1])\nlong_crowding  = clip((0.95 − put_call_ratio) / 0.35, [0, 1])\nput_skew       = max(0, −smart_imbalance)\ncall_skew      = max(0, +smart_imbalance)\n\nsqueeze = 0.45·short_crowding + 0.25·put_skew\n        + 0.15·clip(momentum_5bar / 0.004, [0,1])\n        + 0.10·above_flip + 0.05·neg_gex\nflush   = 0.45·long_crowding  + 0.25·call_skew\n        + 0.15·clip(−momentum_5bar / 0.004, [0,1])\n        + 0.10·below_flip + 0.05·neg_gex\nscore   = clip(squeeze − flush, [-1, 1])\n```\n- `smart_imbalance = (smart_call_net − smart_put_net) / (|call_net| + |put_net|)`,\n  abstaining when denominator `< $100K`.\n\n**Params:**\n- `symbol` (default `SPY`). Returns 404 if no row exists yet.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\", \"timestamp\": \"...\",\n  \"clamped_score\": 0.52, \"score\": 52.0, \"direction\": \"bullish\",\n  \"weighted_score\": 0.0, \"weight\": 0.0,\n  \"smart_imbalance\": -0.41,\n  \"smart_imbalance_source\": \"signed_net_premium\",\n  \"momentum_5bar\": 0.0025,\n  \"context_values\": {\n    \"put_call_ratio\": 1.28, \"smart_imbalance\": -0.41,\n    \"smart_imbalance_source\": \"signed_net_premium\",\n    \"momentum_5bar\": 0.0025, \"close\": 577.24,\n    \"gamma_flip\": 574.5, \"net_gex\": -1.4e9\n  },\n  \"score_history\": [{\"score\": 31.0, \"timestamp\": \"...\"}, \"...up to 90\"]\n}\n```\n\n- `score` / `clamped_score` — `[-100, +100]` / `[-1, +1]`. `+` = squeeze risk, `−` = flush risk.\n- `smart_imbalance` — `[-1, +1]`; `+` = call-buy heavy, `−` = put-buy heavy.\n  Counter-intuitively, *put-heavy imbalance* drives `+score` (squeeze fuel).\n- `smart_imbalance_source` — `\"signed_net_premium\"` (best) | `\"signed_top_level\"` (older fields).\n- `momentum_5bar` — 5-bar price %, e.g. `0.0035` = +0.35%.\n- `context_values.put_call_ratio` — float, typically `[0.5, 2.0]`.\n- `context_values.close` / `gamma_flip` — used to derive `above_flip`/`below_flip`.\n- `context_values.net_gex` — signed; `< 0` amplifies both sides.\n- `score_history` — up to 90 recent points.\n\n**Trader interpretation.**\n- `score > +50` → upside squeeze setup. Long-delta; size up if\n  `close > gamma_flip` AND `net_gex < 0`.\n- `score < −50` → downside flush setup. Put debit spreads; trim longs.\n- Moderate magnitude (±25–50) **plus contradictory `tape_flow_bias`**\n  → the trap may already be unwinding; wait.\n- `smart_imbalance_source = \"signed_top_level\"` → lower-precision fields;\n  signal still valid.\n\n**Page design.** Horizontal ±100 \"trap meter\" with \"Flush Risk\" (left)\nand \"Squeeze Risk\" (right). Decomposition panel showing the five input\nfactors as mini-bars (short/long_crowding, put/call_skew, momentum,\nabove/below_flip, neg_gex) so the trader sees *why*. Contextual footer\nwith `put_call_ratio`, `momentum_5bar %`, `close vs gamma_flip`, `net_gex` sign.","operationId":"get_positioning_trap_signal_api_signals_basic_positioning_trap_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/{signal_name}/events":{"get":{"tags":["Trade Signals"],"summary":"Get Signal Events","description":"Time-stamped history of a single signal's scores with direction-flip detection and realized returns.\n\nProvides per-bar snapshots of a component's score, direction, and input context,\nplus *forward* realized returns for backtesting and diagnostic overlays.\n\n**Params:**\n- `signal_name` — one of: `vol_expansion`, `eod_pressure`, `squeeze_setup`,\n  `trap_detection`, `zero_dte_position_imbalance`, `gamma_vwap_confluence`,\n  `range_break_imminence`, `positioning_trap`, `vanna_charm_flow`.\n  Returns 400 for unknown names.\n- `symbol` (default `SPY`).\n- `limit` — 1–1000, default 100.\n- `horizon` — `\"30m\"` | `\"60m\"` | `\"120m\"` (default `\"60m\"`); forward window for realized return.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\",\n  \"signal_name\": \"vol_expansion\",\n  \"horizon\": \"60m\",\n  \"rows\": [\n    {\n      \"underlying\": \"SPY\",\n      \"timestamp\": \"2026-04-22T14:55:00Z\",\n      \"component_name\": \"vol_expansion\",\n      \"score\": 42.31,\n      \"weighted_score\": 0.0846,\n      \"weight\": 0.20,\n      \"direction\": \"bullish\",\n      \"direction_flip\": true,\n      \"inputs\": { \"...context_values snapshot...\" },\n      \"close\": 677.12,\n      \"horizon_close\": 678.40,\n      \"realized_return\": 0.00189\n    }\n  ],\n  \"count\": 100,\n  \"summary\": {\n    \"flips\": 7,\n    \"bullish\": 43, \"bearish\": 38, \"neutral\": 19,\n    \"latest_timestamp\": \"...\",\n    \"latest_direction\": \"bullish\"\n  }\n}\n```\n\n- `score` — clamped_score × 100; [-100, +100].\n- `direction_flip` — `true` when sign changed since previous non-zero row.\n- `realized_return` — (horizon_close − close) / close; 6-decimal fractional;\n  `null` if no forward quote exists yet.\n- `horizon_close` — underlying close at `timestamp + horizon`.\n\n**Trader interpretation:**\n- Use `realized_return` to validate direction (bullish rows should average positive returns).\n- Low `flips` count = cleaner trend-following signal.\n- `direction_flip` markers make great overlay pins on a price chart.\n\n**Page design.** Time-series panel: top line = `score` colored by direction;\nbottom histogram of `realized_return`. Triangle glyphs at each `direction_flip`.\nKPI row from `summary`.","operationId":"get_signal_events_api_signals__signal_name__events_get","parameters":[{"name":"signal_name","in":"path","required":true,"schema":{"type":"string","title":"Signal Name"}},{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"horizon","in":"query","required":false,"schema":{"type":"string","pattern":"^(30m|60m|120m)$","default":"60m","title":"Horizon"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/advanced/confluence-matrix":{"get":{"tags":["Trade Signals"],"summary":"Get Advanced Confluence Matrix","description":"N×N advanced-signal agreement matrix — pairwise directional confluence over a rolling window.\n\nShows how often each pair of Advanced Signals points the same direction over the\nlast N snapshots. Useful for spotting persistent divergences and unusual\nbreakdowns in normally-correlated signals. Matrix size follows\n`_ADVANCED_SIGNAL_NAMES`.\n\n**Logic** (`src/api/database.py`): Joins `signal_scores` and\n`signal_component_scores` for the last `lookback` timestamps, filtering to\nthe Advanced Signals persisted by `AdvancedSignalEngine`. Signs are\nbucketed with `neutral_epsilon = 0.02` (±0.02 counts as neutral).\nAgreement = same non-zero sign; disagreement = opposite non-zero signs.\n\n**Params:**\n- `symbol` (default `SPY`).\n- `lookback` — 10–2000, default 120.\n\n**Signals (fixed order):** `vol_expansion`, `eod_pressure`, `squeeze_setup`,\n`trap_detection`, `zero_dte_position_imbalance`, `gamma_vwap_confluence`,\n`range_break_imminence`.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\",\n  \"lookback\": 120,\n  \"components\": [\"vol_expansion\", \"eod_pressure\", \"...4 more...\"],\n  \"row_order\": [\"vol_expansion\", \"eod_pressure\", \"...4 more...\"],\n  \"matrix\": {\n    \"vol_expansion\": {\n      \"eod_pressure\": {\n        \"observations\": 118,\n        \"active_observations\": 92,\n        \"agreement_count\": 74,\n        \"disagreement_count\": 18,\n        \"neutral_count\": 26,\n        \"agreement_ratio\": 0.8043,\n        \"disagreement_ratio\": 0.1957,\n        \"net_confluence\": 0.6087\n      }\n    }\n  },\n  \"sample_count\": 118,\n  \"latest_timestamp\": \"2026-04-22T14:55:00Z\"\n}\n```\n\n- `agreement_ratio` — agree / active_observations; 4 decimals; `null` when active == 0.\n- `disagreement_ratio` — disagree / active_observations; `null` when active == 0.\n- `net_confluence` — (agree − disagree) / active_observations; [-1, +1].\n\n**Trader interpretation:**\n- `net_confluence > 0.5` — signals that routinely agree; unexpected divergence is a flag.\n- `net_confluence < -0.3` — persistent disagreement pairs; useful early-warning divergences.\n\n**Page design.** N×N heatmap sized to `_ADVANCED_SIGNAL_NAMES`. Color =\n`net_confluence` (green +1 → red -1, white neutral). Cell tooltip:\nagreement_ratio / disagreement_ratio / observations. Sort rows by average\nagreement to surface consensus signals at top, outliers at bottom.","operationId":"get_advanced_confluence_matrix_api_signals_advanced_confluence_matrix_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"lookback","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":10,"default":120,"title":"Lookback"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/signals/basic/confluence-matrix":{"get":{"tags":["Trade Signals"],"summary":"Get Basic Confluence Matrix","description":"6×6 basic-signal agreement matrix — pairwise directional confluence.\n\nParallel to `/api/signals/advanced/confluence-matrix`, scoped to the six\nBasic Signals persisted by `BasicSignalEngine`. Answers: *which of my\nbasic signals normally agree, and where is an unusual divergence right now?*\nContinuous directional reads (no triggered events) — every non-zero\nsnapshot contributes to agreement/disagreement counts.\n\n**Logic** (`src/api/database.py`): Joins `signal_scores` ×\n`signal_component_scores` for the last `lookback` timestamps, filtered\nto the six basic signal names. Each score is bucketed `+1 / 0 / −1`\nwith `neutral_epsilon = 0.02`. For each ordered pair `(c1, c2)`:\n- `observations` = cycles where both signals have data.\n- `active_observations` = cycles where both signs are non-zero.\n- `agreement` = same non-zero sign; `disagreement` = opposite non-zero signs.\n\n**Params:**\n- `symbol` (default `SPY`).\n- `lookback` — 10–2000, default 120. Number of recent timestamps.\n\n**Signals (6, fixed order):** `tape_flow_bias`, `skew_delta`,\n`vanna_charm_flow`, `dealer_delta_pressure`, `gex_gradient`, `positioning_trap`.\n\n**Returns:**\n```json\n{\n  \"underlying\": \"SPY\",\n  \"lookback\": 120,\n  \"components\": [\"tape_flow_bias\", \"skew_delta\", \"vanna_charm_flow\",\n                 \"dealer_delta_pressure\", \"gex_gradient\", \"positioning_trap\"],\n  \"row_order\":  [\"tape_flow_bias\", \"skew_delta\", \"...4 more...\"],\n  \"matrix\": {\n    \"tape_flow_bias\": {\n      \"skew_delta\": {\n        \"observations\": 118,\n        \"active_observations\": 92,\n        \"agreement_count\": 74,\n        \"disagreement_count\": 18,\n        \"neutral_count\": 26,\n        \"agreement_ratio\": 0.8043,\n        \"disagreement_ratio\": 0.1957,\n        \"net_confluence\": 0.6087\n      }\n    }\n  },\n  \"sample_count\": 118,\n  \"latest_timestamp\": \"2026-04-22T18:55:00Z\"\n}\n```\n\n- `components` / `row_order` — length-6 string array; axis labels.\n- `matrix[c1][c2].observations` — int, `[0, lookback]`; cycles where both had data.\n- `matrix[c1][c2].active_observations` — int, `[0, observations]`; both non-zero.\n- `matrix[c1][c2].agreement_count` — int, `[0, active_observations]`.\n- `matrix[c1][c2].disagreement_count` — int, `[0, active_observations]`.\n- `matrix[c1][c2].neutral_count` — int, `[0, observations]`; at least one side was 0.\n- `matrix[c1][c2].agreement_ratio` — `[0, 1]` | `null` if `active == 0`; 4 decimals.\n- `matrix[c1][c2].disagreement_ratio` — `[0, 1]` | `null`.\n- `matrix[c1][c2].net_confluence` — `[-1, +1]`; `0.0` if `active == 0`. Heatmap value.\n- `sample_count` — int; distinct timestamps aggregated.\n- `latest_timestamp` — ISO-8601 UTC | `null` if empty.\n\n**Trader interpretation.**\n- `net_confluence > +0.5` — pair agrees > 75% of active cycles. Live\n  **disagreement** from such a pair is a flag.\n- `net_confluence < −0.3` — pair structurally disagrees. Live\n  **agreement** = unusual consensus.\n- `active_observations < ~20` — weak sample; discount.\n- Diagonal cells always `net_confluence = 1.0`; sanity check only.\n\n**Page design.** 6×6 heatmap with diverging color scale (green = +1\nagree, white = 0, red = −1 disagree). Cell tooltip shows\n`agreement_ratio / disagreement_ratio / observations`. Sort rows by\naverage `agreement_ratio` to surface consensus signals at top, outliers\nat bottom. Symmetric — render only the upper triangle if space-constrained.","operationId":"get_basic_confluence_matrix_api_signals_basic_confluence_matrix_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"lookback","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":10,"default":120,"title":"Lookback"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/market/vix":{"get":{"tags":["Market Data"],"summary":"Get Volatility Gauge","description":"Returns $VIX.X volatility metrics as two scored dimensions.\n\n**Level** — *where is VIX right now?*\nMaps the current $VIX.X reading to a 0–10 log scale anchored to\nhistorical percentiles:\n- `0–2`  → Subdued  (VIX ~10–15, historically quiet)\n- `2–4`  → Low      (VIX ~15–19, below-average vol)\n- `4–6`  → Moderate (VIX ~19–27, near long-run average)\n- `6–8`  → Elevated (VIX ~27–38, above-average fear)\n- `8–10` → Extreme  (VIX ~38+, crisis-level fear)\n\n**Momentum** — *which direction and how fast is VIX moving?*\nWeighted composite rate-of-change across five time scales (5 min through\n2 hrs), normalised against realised per-bar volatility of VIX.\n\n**Data source** — reads the rolling 5-min VIX bar window maintained by\nthe ingestion engine's VIX poller from the `vix_bars` table.","operationId":"get_volatility_gauge_api_market_vix_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolatilityGaugeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/option/contract":{"get":{"tags":["Market Data"],"summary":"Get Option Contract","description":"Returns all rows for the specified option contract for today's trading\nsession if the market is currently open, otherwise for the most recent\ndate that has data for this contract.","operationId":"get_option_contract_api_option_contract_get","parameters":[{"name":"underlying","in":"query","required":true,"schema":{"type":"string","description":"Underlying symbol, e.g. SPY","title":"Underlying"},"description":"Underlying symbol, e.g. SPY"},{"name":"strike","in":"query","required":true,"schema":{"type":"number","description":"Strike price","title":"Strike"},"description":"Strike price"},{"name":"expiration","in":"query","required":true,"schema":{"type":"string","description":"Expiration date (YYYY-MM-DD)","title":"Expiration"},"description":"Expiration date (YYYY-MM-DD)"},{"name":"option_type","in":"query","required":true,"schema":{"enum":["C","P"],"type":"string","description":"Option type: C or P","title":"Option Type"},"description":"Option type: C or P"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OptionContractRow"},"title":"Response Get Option Contract Api Option Contract Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gex/vol_surface":{"get":{"tags":["GEX"],"summary":"Get Vol Surface","description":"Return the implied-volatility surface, ATM term structure, and 25-delta skew.","operationId":"get_vol_surface_api_gex_vol_surface_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","description":"Underlying symbol (e.g. SPY)","default":"SPY","title":"Symbol"},"description":"Underlying symbol (e.g. SPY)"},{"name":"dte_max","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"Max days to expiration to include","default":60,"title":"Dte Max"},"description":"Max days to expiration to include"},{"name":"strike_count","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":5,"description":"Number of strikes centered on spot","default":30,"title":"Strike Count"},"description":"Number of strikes centered on spot"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolSurfaceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/health":{"get":{"tags":["Health"],"summary":"Health Check","description":"Check API and database health","operationId":"health_check_api_health_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gex/summary":{"get":{"tags":["GEX"],"summary":"Get Gex Summary","description":"Get latest GEX summary","operationId":"get_gex_summary_api_gex_summary_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GEXSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gex/by-strike":{"get":{"tags":["GEX"],"summary":"Get Gex By Strike","description":"Get GEX breakdown by strike\n\nReturns detailed gamma exposure data including vanna/charm for each strike.\n\n- sort_by=distance: Returns strikes closest to current spot price (default)\n- sort_by=impact: Returns strikes with highest absolute net GEX (like 'make gex-strikes')","operationId":"get_gex_by_strike_api_gex_by_strike_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"default":50,"title":"Limit"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","pattern":"^(distance|impact)$","description":"Sort by 'distance' (closest to spot) or 'impact' (highest absolute net GEX)","default":"distance","title":"Sort By"},"description":"Sort by 'distance' (closest to spot) or 'impact' (highest absolute net GEX)"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GEXByStrike"},"title":"Response Get Gex By Strike Api Gex By Strike Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gex/historical":{"get":{"tags":["GEX"],"summary":"Get Historical Gex","description":"Get historical GEX data","operationId":"get_historical_gex_api_gex_historical_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"}},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":90,"title":"Window Units"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"1min","title":"Timeframe"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GEXSummary"},"title":"Response Get Historical Gex Api Gex Historical Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gex/heatmap":{"get":{"tags":["GEX"],"summary":"Get Gex Heatmap","description":"Get GEX heatmap data (strike x time)","operationId":"get_gex_heatmap_api_gex_heatmap_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"5min","title":"Timeframe"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":60,"title":"Window Units"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/flow/by-contract":{"get":{"tags":["Options Flow"],"summary":"Get Flow By Contract","description":"Per-contract option flow in 5-min buckets with session-cumulative values.\n\nReturns one row per (option_type, strike, expiration) per 5-min bucket.\nraw_volume, raw_premium, net_volume and net_premium are day-to-date\ncumulative for each contract as of the end of its bucket; counters reset\nat 09:30 ET (TradeStation RTH open).\n\nsession=current returns today's open session (or most recent if closed);\nsession=prior returns the previous full session. Pass intervals=N to\nlimit the response to the most recent N 5-minute buckets.","operationId":"get_flow_by_contract_api_flow_by_contract_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"session","in":"query","required":false,"schema":{"type":"string","pattern":"^(current|prior)$","default":"current","title":"Session"}},{"name":"intervals","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":390,"minimum":1},{"type":"null"}],"description":"Number of trailing 5-minute buckets to return. Defaults to the entire session (09:30–16:15 ET, ~81 buckets). Capped at 390 (one trading day at 1-minute resolution) to bound DB load.","title":"Intervals"},"description":"Number of trailing 5-minute buckets to return. Defaults to the entire session (09:30–16:15 ET, ~81 buckets). Capped at 390 (one trading day at 1-minute resolution) to bound DB load."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FlowPoint"},"title":"Response Get Flow By Contract Api Flow By Contract Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/flow/series":{"get":{"tags":["Options Flow"],"summary":"Get Flow Series","description":"Server-accumulated flow series — one row per 5-minute bar.\n\nReturns cumulative call/put premium, volume, position, net volume, and\nput/call ratio per bar across all contracts matching the optional\n``strikes``/``expirations`` filters. Rows are contiguous (quiet bars\ncarry forward as synthetic rows flagged by ``is_synthetic``). Frontend\nrenders this series directly — no client-side accumulators.\n\n``session=current`` is the most recent ET trading day that has any data\nfor the symbol; ``session=prior`` is the ET day immediately before that.\nUnknown symbols return 404; symbols that exist but have no data for the\nrequested session return 200 with ``[]``.","operationId":"get_flow_series_api_flow_series_get","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":10,"title":"Symbol"}},{"name":"session","in":"query","required":false,"schema":{"enum":["current","prior"],"type":"string","default":"current","title":"Session"}},{"name":"strikes","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated strikes to include. Empty/missing = all strikes.","title":"Strikes"},"description":"Comma-separated strikes to include. Empty/missing = all strikes."},{"name":"expirations","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated YYYY-MM-DD expirations to include. Empty/missing = all.","title":"Expirations"},"description":"Comma-separated YYYY-MM-DD expirations to include. Empty/missing = all."},{"name":"intervals","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":390,"minimum":1},{"type":"null"}],"description":"If provided, return only the last N 5-minute bars (tail window) for cheap incremental polling. A full regular session is 81 bars.","title":"Intervals"},"description":"If provided, return only the last N 5-minute bars (tail window) for cheap incremental polling. A full regular session is 81 bars."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FlowSeriesPoint"},"title":"Response Get Flow Series Api Flow Series Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/flow/contracts":{"get":{"tags":["Options Flow"],"summary":"Get Flow Contracts","description":"Distinct strikes and expirations that traded in the resolved session.\n\nPowers the Strike / Expiration filter chips on the Flow Analysis page.\nCompanion to ``/api/flow/series``: same session resolution, same 404\nsemantics for unknown symbols.","operationId":"get_flow_contracts_api_flow_contracts_get","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":10,"title":"Symbol"}},{"name":"session","in":"query","required":false,"schema":{"enum":["current","prior"],"type":"string","default":"current","title":"Session"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowContractsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/flow/smart-money":{"get":{"tags":["Options Flow"],"summary":"Get Smart Money Flow","description":"Get unusual activity / smart money flow — 1-min intervals.\nSession runs 07:15–16:15 ET. session=current returns today's open session (or most recent if closed); session=prior returns the previous full session.","operationId":"get_smart_money_flow_api_flow_smart_money_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"session","in":"query","required":false,"schema":{"type":"string","pattern":"^(current|prior)$","default":"current","title":"Session"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":50,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SmartMoneyFlowPoint"},"title":"Response Get Smart Money Flow Api Flow Smart Money Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/flow/buying-pressure":{"get":{"tags":["Options Flow"],"summary":"Get Flow Buying Pressure","description":"Get underlying buying/selling pressure","operationId":"get_flow_buying_pressure_api_flow_buying_pressure_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FlowBuyingPressurePoint"},"title":"Response Get Flow Buying Pressure Api Flow Buying Pressure Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/market/quote":{"get":{"tags":["Market Data"],"summary":"Get Current Quote","description":"Get current underlying quote","operationId":"get_current_quote_api_market_quote_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnderlyingQuote"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/market/session-closes":{"get":{"tags":["Market Data"],"summary":"Get Session Closes","description":"Get the two most recently completed regular session closes.\n\n- current_session_close: the most recent cash session close (last bar <= 16:00 ET\n  on the most recent completed trading day).\n- prior_session_close: the session close immediately before current.","operationId":"get_session_closes_api_market_session_closes_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionCloses"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/market/historical":{"get":{"tags":["Market Data"],"summary":"Get Historical Quotes","description":"Get historical quotes","operationId":"get_historical_quotes_api_market_historical_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"}},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":90,"title":"Window Units"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"1min","title":"Timeframe"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UnderlyingQuote"},"title":"Response Get Historical Quotes Api Market Historical Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/option/quote":{"get":{"tags":["Market Data"],"summary":"Get Option Quote","description":"Get the most recent quote for a specific option contract","operationId":"get_option_quote_api_option_quote_get","parameters":[{"name":"underlying","in":"query","required":false,"schema":{"type":"string","description":"Underlying symbol, e.g. SPY","default":"SPY","title":"Underlying"},"description":"Underlying symbol, e.g. SPY"},{"name":"strike","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Strike price","title":"Strike"},"description":"Strike price"},{"name":"expiration","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Expiration date (YYYY-MM-DD)","title":"Expiration"},"description":"Expiration date (YYYY-MM-DD)"},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"enum":["C","P"],"type":"string"},{"type":"null"}],"description":"Option type: C for Call, P for Put","title":"Type"},"description":"Option type: C for Call, P for Put"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptionQuote"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/market/open-interest":{"get":{"tags":["Market Data"],"summary":"Get Open Interest","description":"Get current open interest for each option contract for the underlying.\n\nReturns one record per (strike, expiration, option_type) from the most recent\noption chain snapshot, ordered by expiration, strike, and option type.","operationId":"get_open_interest_api_market_open_interest_get","parameters":[{"name":"underlying","in":"query","required":false,"schema":{"type":"string","description":"Underlying symbol, e.g. SPY","default":"SPY","title":"Underlying"},"description":"Underlying symbol, e.g. SPY"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenInterestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/max-pain/timeseries":{"get":{"tags":["Max Pain"],"summary":"Get Max Pain Timeseries","description":"Get max pain over time aggregated by timeframe.","operationId":"get_max_pain_timeseries_api_max_pain_timeseries_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"5min","title":"Timeframe"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":90,"title":"Window Units"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MaxPainTimeseriesPoint"},"title":"Response Get Max Pain Timeseries Api Max Pain Timeseries Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/max-pain/current":{"get":{"tags":["Max Pain"],"summary":"Get Max Pain Current","description":"Get current max pain and strike-by-strike call/put payout notional.","operationId":"get_max_pain_current_api_max_pain_current_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"strike_limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":10,"default":200,"title":"Strike Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaxPainCurrent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/technicals/vwap-deviation":{"get":{"tags":["Technicals"],"summary":"Get Vwap Deviation","description":"Get VWAP deviation for mean reversion signals","operationId":"get_vwap_deviation_api_technicals_vwap_deviation_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"1min","title":"Timeframe"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":20,"title":"Window Units"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/technicals/opening-range":{"get":{"tags":["Technicals"],"summary":"Get Opening Range","description":"Get opening range breakout status","operationId":"get_opening_range_api_technicals_opening_range_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"1min","title":"Timeframe"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":20,"title":"Window Units"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/technicals/dealer-hedging":{"get":{"tags":["Technicals"],"summary":"Get Dealer Hedging","description":"Get dealer hedging pressure","operationId":"get_dealer_hedging_api_technicals_dealer_hedging_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/technicals/volume-spikes":{"get":{"tags":["Technicals"],"summary":"Get Volume Spikes","description":"Get unusual volume spikes","operationId":"get_volume_spikes_api_technicals_volume_spikes_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/technicals/momentum-divergence":{"get":{"tags":["Technicals"],"summary":"Get Momentum Divergence","description":"Get momentum divergence signals","operationId":"get_momentum_divergence_api_technicals_momentum_divergence_get","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string","default":"SPY","title":"Symbol"}},{"name":"timeframe","in":"query","required":false,"schema":{"enum":["1min","5min","15min","1hr","1day","1hour"],"type":"string","default":"1min","title":"Timeframe"}},{"name":"window_units","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":20,"title":"Window Units"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MomentumDivergencePoint"},"title":"Response Get Momentum Divergence Api Technicals Momentum Divergence Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ATMTermPoint":{"properties":{"dte":{"type":"integer","title":"Dte"},"atm_iv":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Atm Iv"}},"type":"object","required":["dte"],"title":"ATMTermPoint"},"ExpirationSlice":{"properties":{"expiration":{"type":"string","format":"date","title":"Expiration"},"dte":{"type":"integer","title":"Dte"},"ivs":{"items":{"$ref":"#/components/schemas/StrikeIV"},"type":"array","title":"Ivs"}},"type":"object","required":["expiration","dte","ivs"],"title":"ExpirationSlice"},"FlowBuyingPressurePoint":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Price"},"volume":{"type":"integer","title":"Volume"},"buy_pct":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Buy Pct"},"period_buy_pct":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Period Buy Pct"},"price_chg":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Price Chg"},"momentum":{"type":"string","title":"Momentum"}},"type":"object","required":["timestamp","symbol","price","volume","buy_pct","period_buy_pct","momentum"],"title":"FlowBuyingPressurePoint"},"FlowContractsResponse":{"properties":{"strikes":{"items":{"type":"number"},"type":"array","title":"Strikes"},"expirations":{"items":{"type":"string"},"type":"array","title":"Expirations"}},"type":"object","required":["strikes","expirations"],"title":"FlowContractsResponse","description":"Distinct strikes and expirations that traded in the resolved session."},"FlowPoint":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"option_type":{"type":"string","title":"Option Type"},"strike":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Strike"},"expiration":{"type":"string","format":"date","title":"Expiration"},"dte":{"type":"integer","title":"Dte"},"raw_volume":{"type":"integer","title":"Raw Volume"},"raw_premium":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Raw Premium"},"net_volume":{"type":"integer","title":"Net Volume"},"net_premium":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Net Premium"},"underlying_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Underlying Price"}},"type":"object","required":["timestamp","symbol","option_type","strike","expiration","dte","raw_volume","raw_premium","net_volume","net_premium"],"title":"FlowPoint","description":"Per-contract 5-min-bucketed flow row with session-cumulative values.\n\nOne row per (option_type, strike, expiration) per 5-min bucket. Values\nare day-to-date cumulative for THIS contract as of the end of the\nbucket, with the session resetting at 09:30 ET (TradeStation RTH open).\n\nraw_volume / raw_premium: total session volume and flow-weighted premium\nregardless of buy/sell direction.\nnet_volume / net_premium: session buys minus sells (classified via the\nask/bid volume ratio from each tick), scaled so unclassified volume is\nattributed proportionally."},"FlowSeriesPoint":{"properties":{"timestamp":{"type":"string","title":"Timestamp"},"bar_start":{"type":"string","title":"Bar Start"},"bar_end":{"type":"string","title":"Bar End"},"call_premium_cum":{"type":"number","title":"Call Premium Cum"},"put_premium_cum":{"type":"number","title":"Put Premium Cum"},"call_volume_cum":{"type":"integer","title":"Call Volume Cum"},"put_volume_cum":{"type":"integer","title":"Put Volume Cum"},"net_volume_cum":{"type":"integer","title":"Net Volume Cum"},"raw_volume_cum":{"type":"integer","title":"Raw Volume Cum"},"call_position_cum":{"type":"integer","title":"Call Position Cum"},"put_position_cum":{"type":"integer","title":"Put Position Cum"},"net_premium_cum":{"type":"number","title":"Net Premium Cum"},"put_call_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Put Call Ratio"},"underlying_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Underlying Price"},"contract_count":{"type":"integer","title":"Contract Count"},"is_synthetic":{"type":"boolean","title":"Is Synthetic"}},"type":"object","required":["timestamp","bar_start","bar_end","call_premium_cum","put_premium_cum","call_volume_cum","put_volume_cum","net_volume_cum","raw_volume_cum","call_position_cum","put_position_cum","net_premium_cum","contract_count","is_synthetic"],"title":"FlowSeriesPoint","description":"Server-accumulated 5-minute flow bar from /api/flow/series.\n\nOne row per bar from 09:30 ET through the latest bar covered by the\nresolved session. Carry-forward synthetic rows fill quiet bars so the\nseries is contiguous — the ``is_synthetic`` flag distinguishes them."},"GEXByStrike":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"strike":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Strike"},"expiration":{"type":"string","format":"date","title":"Expiration"},"call_oi":{"type":"integer","title":"Call Oi"},"put_oi":{"type":"integer","title":"Put Oi"},"call_volume":{"type":"integer","title":"Call Volume"},"put_volume":{"type":"integer","title":"Put Volume"},"call_gex":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Call Gex"},"put_gex":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Put Gex"},"net_gex":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Net Gex"},"vanna_exposure":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Vanna Exposure"},"charm_exposure":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Charm Exposure"},"spot_price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Spot Price"},"distance_from_spot":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Distance From Spot"}},"type":"object","required":["timestamp","symbol","strike","expiration","call_oi","put_oi","call_volume","put_volume","call_gex","put_gex","net_gex","spot_price","distance_from_spot"],"title":"GEXByStrike"},"GEXSummary":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"spot_price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Spot Price"},"total_call_gex":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Call Gex"},"total_put_gex":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Put Gex"},"net_gex":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Net Gex"},"gamma_flip":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Gamma Flip"},"flip_distance":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Flip Distance"},"local_gex":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Local Gex"},"convexity_risk":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Convexity Risk"},"max_pain":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Max Pain"},"call_wall":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Call Wall"},"put_wall":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Put Wall"},"total_call_oi":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Call Oi"},"total_put_oi":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Put Oi"},"put_call_ratio":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Put Call Ratio"}},"type":"object","required":["timestamp","symbol","spot_price","total_call_gex","total_put_gex","net_gex"],"title":"GEXSummary"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthStatus":{"properties":{"status":{"type":"string","title":"Status","description":"healthy, degraded, or unhealthy"},"database_connected":{"type":"boolean","title":"Database Connected"},"last_data_update":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Data Update"},"data_age_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Data Age Seconds"}},"type":"object","required":["status","database_connected"],"title":"HealthStatus"},"MaxPainCurrent":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"underlying_price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Underlying Price"},"max_pain":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Max Pain"},"difference":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Difference"},"expirations":{"items":{"$ref":"#/components/schemas/MaxPainExpiration"},"type":"array","title":"Expirations"}},"type":"object","required":["timestamp","symbol","underlying_price","max_pain","difference","expirations"],"title":"MaxPainCurrent"},"MaxPainExpiration":{"properties":{"expiration":{"type":"string","format":"date","title":"Expiration"},"max_pain":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Max Pain"},"difference_from_underlying":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Difference From Underlying"},"strikes":{"items":{"$ref":"#/components/schemas/MaxPainPoint"},"type":"array","title":"Strikes"}},"type":"object","required":["expiration","max_pain","difference_from_underlying","strikes"],"title":"MaxPainExpiration"},"MaxPainPoint":{"properties":{"expiration":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expiration"},"settlement_price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Settlement Price"},"call_notional":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Call Notional"},"put_notional":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Put Notional"},"total_notional":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Notional"}},"type":"object","required":["settlement_price","call_notional","put_notional","total_notional"],"title":"MaxPainPoint"},"MaxPainTimeseriesPoint":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"max_pain":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Max Pain"}},"type":"object","required":["timestamp","symbol","max_pain"],"title":"MaxPainTimeseriesPoint"},"MomentumDivergencePoint":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Price"},"chg_5m":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Chg 5M"},"opt_flow":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Opt Flow"},"divergence_signal":{"type":"string","title":"Divergence Signal"}},"type":"object","required":["timestamp","symbol","price","chg_5m","opt_flow","divergence_signal"],"title":"MomentumDivergencePoint"},"OpenInterestRecord":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"underlying":{"type":"string","title":"Underlying"},"strike":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Strike"},"expiration":{"type":"string","format":"date","title":"Expiration"},"option_type":{"type":"string","title":"Option Type"},"open_interest":{"type":"integer","title":"Open Interest"},"exposure":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Exposure"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["timestamp","underlying","strike","expiration","option_type","open_interest","exposure"],"title":"OpenInterestRecord"},"OpenInterestResponse":{"properties":{"underlying":{"type":"string","title":"Underlying"},"spot_price":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Spot Price"},"contracts":{"items":{"$ref":"#/components/schemas/OpenInterestRecord"},"type":"array","title":"Contracts"}},"type":"object","required":["underlying","spot_price","contracts"],"title":"OpenInterestResponse"},"OptionContractRow":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"underlying":{"type":"string","title":"Underlying"},"strike":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Strike"},"expiration":{"type":"string","format":"date","title":"Expiration"},"option_type":{"type":"string","title":"Option Type"},"last":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Last"},"bid":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Bid"},"ask":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Ask"},"mid":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Mid"},"volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Volume"},"volume_delta":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Volume Delta"},"open_interest":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Open Interest"},"ask_volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ask Volume"},"mid_volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Mid Volume"},"bid_volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Bid Volume"},"implied_volatility":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Implied Volatility"},"delta":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Delta"},"gamma":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Gamma"},"theta":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Theta"},"vega":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Vega"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["timestamp","underlying","strike","expiration","option_type"],"title":"OptionContractRow"},"OptionQuote":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"underlying":{"type":"string","title":"Underlying"},"strike":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Strike"},"expiration":{"type":"string","format":"date","title":"Expiration"},"option_type":{"type":"string","title":"Option Type"},"bid":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Bid"},"ask":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Ask"},"volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Volume"},"open_interest":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Open Interest"}},"type":"object","required":["timestamp","underlying","strike","expiration","option_type"],"title":"OptionQuote"},"SessionCloses":{"properties":{"symbol":{"type":"string","title":"Symbol"},"current_session_close":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Current Session Close"},"current_session_close_ts":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Session Close Ts"},"prior_session_close":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Prior Session Close"},"prior_session_close_ts":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Prior Session Close Ts"}},"type":"object","required":["symbol","current_session_close","current_session_close_ts","prior_session_close","prior_session_close_ts"],"title":"SessionCloses"},"Skew25dPoint":{"properties":{"dte":{"type":"integer","title":"Dte"},"skew":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Skew"}},"type":"object","required":["dte"],"title":"Skew25dPoint"},"SmartMoneyFlowPoint":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"contract":{"type":"string","title":"Contract"},"strike":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Strike"},"expiration":{"type":"string","format":"date","title":"Expiration"},"dte":{"type":"integer","title":"Dte"},"option_type":{"type":"string","title":"Option Type"},"flow":{"type":"integer","title":"Flow"},"notional":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Notional"},"trade_side":{"type":"string","title":"Trade Side"},"delta":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Delta"},"score":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Score"},"notional_class":{"type":"string","title":"Notional Class"},"size_class":{"type":"string","title":"Size Class"},"underlying_price":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Underlying Price"}},"type":"object","required":["timestamp","symbol","contract","strike","expiration","dte","option_type","flow","notional","trade_side","notional_class","size_class"],"title":"SmartMoneyFlowPoint"},"StrikeIV":{"properties":{"strike":{"type":"number","title":"Strike"},"call_iv":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Call Iv"},"put_iv":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Put Iv"}},"type":"object","required":["strike"],"title":"StrikeIV"},"UnderlyingQuote":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"symbol":{"type":"string","title":"Symbol"},"open":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Open"},"high":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"High"},"low":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Low"},"close":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Close"},"up_volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Up Volume"},"down_volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Down Volume"},"volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Volume"},"session":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session"}},"type":"object","required":["timestamp","symbol","open","high","low","close"],"title":"UnderlyingQuote"},"VIXBar":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"close":{"type":"number","title":"Close"}},"type":"object","required":["timestamp","close"],"title":"VIXBar"},"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"},"VolSurfaceResponse":{"properties":{"symbol":{"type":"string","title":"Symbol"},"spot_price":{"type":"number","title":"Spot Price"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"expirations":{"items":{"type":"string","format":"date"},"type":"array","title":"Expirations"},"strikes":{"items":{"type":"number"},"type":"array","title":"Strikes"},"surface":{"items":{"$ref":"#/components/schemas/ExpirationSlice"},"type":"array","title":"Surface"},"atm_term_structure":{"items":{"$ref":"#/components/schemas/ATMTermPoint"},"type":"array","title":"Atm Term Structure"},"skew_25d":{"items":{"$ref":"#/components/schemas/Skew25dPoint"},"type":"array","title":"Skew 25D"}},"type":"object","required":["symbol","spot_price","timestamp","expirations","strikes","surface","atm_term_structure","skew_25d"],"title":"VolSurfaceResponse"},"VolatilityGaugeResponse":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp","description":"Timestamp of the latest VIX bar (ET)"},"vix":{"type":"number","title":"Vix","description":"Current $VIX.X close"},"level":{"type":"number","title":"Level","description":"VIX level mapped to 0–10 (log scale). 0 = ultra-calm (VIX ~10), 5 = VIX ~25, 10 = extreme fear (VIX ~50+)."},"level_label":{"type":"string","title":"Level Label","description":"Human-readable label: Subdued / Low / Moderate / Elevated / Extreme"},"momentum":{"type":"number","title":"Momentum","description":"VIX rate-of-change mapped to 0–10 (±4σ range). 0 = collapsing, 5 = stable, 10 = surging."},"momentum_label":{"type":"string","title":"Momentum Label","description":"Human-readable label: Collapsing / Easing / Stable / Rising / Surging"},"cache_bars":{"type":"integer","title":"Cache Bars","description":"5-min bars used from vix_bars for this response"},"latest_bars":{"items":{"$ref":"#/components/schemas/VIXBar"},"type":"array","title":"Latest Bars","description":"Most-recent 10 bars for debugging / charting"}},"type":"object","required":["timestamp","vix","level","level_label","momentum","momentum_label","cache_bars"],"title":"VolatilityGaugeResponse"}}},"tags":[{"name":"Health","description":"API and database health checks"},{"name":"GEX","description":"Gamma Exposure (GEX) analytics"},{"name":"Options Flow","description":"Options flow and buying pressure data"},{"name":"Market Data","description":"Underlying and option quote data"},{"name":"Max Pain","description":"Max pain analysis"},{"name":"Technicals","description":"Intraday technical signals: VWAP, ORB, dealer hedging, volume, momentum"},{"name":"Trade Signals","description":"Options-structure signal engine: composite Market State Index (MSI) gauge, advanced signal components (vol-expansion, eod-pressure, squeeze-setup, trap-detection, 0dte-position-imbalance, gamma-vwap-confluence, range-break-imminence), per-component event history with realized returns, a pairwise confluence matrix, and live/historical trade records. Default symbol is SPY; pass ?symbol= or ?underlying= to override."}]}