{"openapi":"3.1.0","info":{"title":"Spark","description":"Agentic Trade Intelligence — AI-powered volatility analysis and options strategy generation","version":"1.0.0"},"paths":{"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ready":{"get":{"summary":"Ready","operationId":"ready_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/info":{"get":{"summary":"Info","operationId":"info_v1_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/handshake":{"get":{"summary":"Handshake","operationId":"handshake_v1_handshake_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandshakeResponse"}}}}}}},"/v1/market-insights":{"post":{"summary":"Market Insights","operationId":"market_insights_v1_market_insights_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketInsightRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TradeIdeasResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/portfolio-recommendations":{"post":{"summary":"Portfolio Recommendations","operationId":"portfolio_recommendations_v1_portfolio_recommendations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioRecommendationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TradeIdeasResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/schwab/status":{"get":{"summary":"Schwab Status","operationId":"schwab_status_v1_schwab_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}}}}},"/v1/schwab/refresh":{"post":{"summary":"Schwab Refresh","description":"Returns 410 Gone — refresh is no longer owned by spark-api.\n\nThe single-writer Schwab token chain on this deployment is owned by\nbot-claude-bridge on bot-ctrl. spark-api is a read-only consumer and\nmust never call ``grant_type=refresh_token`` (would invalidate the\nbridge's refresh_token on its next call and break the chain).","operationId":"schwab_refresh_v1_schwab_refresh_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/universes":{"get":{"summary":"Universes","description":"Return available symbol macros and the tickers each resolves to.\n\nMacros may be passed in the ``symbols`` field of a market-insights or\nportfolio-recommendations request and will be expanded server-side.","operationId":"universes_v1_universes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Universes V1 Universes Get"}}}}}}},"/v1/binary/pricing":{"get":{"summary":"Binary Pricing","description":"Analytical pricing ladders for XSPBW binaries and QSB $1-wide verticals.\n\nBinary prices are $0-$100 cash-or-nothing values on the XSPBX\nsettlement index (SPX close / 10). Greeks are closed-form:\ndelta/gamma per $1 XSPBX, theta per trading day, vega per vol point,\nrho per 1% rate.","operationId":"binary_pricing_v1_binary_pricing_get","parameters":[{"name":"expiry","in":"query","required":false,"schema":{"type":"string","pattern":"^(0dte|1dte)$","description":"Contract expiry: 0dte or 1dte","default":"0dte","title":"Expiry"},"description":"Contract expiry: 0dte or 1dte"},{"name":"iv","in":"query","required":false,"schema":{"anyOf":[{"type":"number","exclusiveMaximum":10,"exclusiveMinimum":0},{"type":"null"}],"description":"Override IV (annualized, e.g. 0.18); default VIX/100","title":"Iv"},"description":"Override IV (annualized, e.g. 0.18); default VIX/100"},{"name":"r","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":0.25,"minimum":-0.05},{"type":"null"}],"description":"Override risk-free rate","title":"R"},"description":"Override risk-free rate"},{"name":"q","in":"query","required":false,"schema":{"type":"number","maximum":0.1,"minimum":0,"description":"Dividend yield","default":0.012,"title":"Q"},"description":"Dividend yield"},{"name":"ladder_span","in":"query","required":false,"schema":{"type":"integer","maximum":15,"minimum":1,"description":"Strikes each side of ATM","default":5,"title":"Ladder Span"},"description":"Strikes each side of ATM"},{"name":"skew_slope","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":0.1,"minimum":-0.1},{"type":"null"}],"description":"d(sigma)/dK per $1 XSPBX strike for skew-adjusted call prices (SPX skew is negative)","title":"Skew Slope"},"description":"d(sigma)/dK per $1 XSPBX strike for skew-adjusted call prices (SPX skew is negative)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Binary Pricing V1 Binary Pricing Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/binary/implied-vol":{"get":{"summary":"Binary Implied Vol","description":"Branch-aware implied volatility for an XSPBW binary price.\n\nBinary prices are not globally monotonic in vol: when the forward is\nbelow the strike there is a critical vol where the call price peaks\n(put troughs), so a single price can map to TWO implied vols. The\nresponse returns every root plus regime metadata.","operationId":"binary_implied_vol_v1_binary_implied_vol_get","parameters":[{"name":"price","in":"query","required":true,"schema":{"type":"number","exclusiveMaximum":100,"exclusiveMinimum":0,"description":"Observed binary price in dollars (0-100)","title":"Price"},"description":"Observed binary price in dollars (0-100)"},{"name":"strike","in":"query","required":true,"schema":{"type":"number","exclusiveMinimum":0,"description":"XSPBW strike","title":"Strike"},"description":"XSPBW strike"},{"name":"option_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(call|put)$","default":"call","title":"Option Type"}},{"name":"expiry","in":"query","required":false,"schema":{"type":"string","pattern":"^(0dte|1dte)$","default":"0dte","title":"Expiry"}},{"name":"spot","in":"query","required":false,"schema":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"description":"Override XSPBX spot (default: live quote)","title":"Spot"},"description":"Override XSPBX spot (default: live quote)"},{"name":"r","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":0.25,"minimum":-0.05},{"type":"null"}],"title":"R"}},{"name":"q","in":"query","required":false,"schema":{"type":"number","maximum":0.1,"minimum":0,"default":0.012,"title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Binary Implied Vol V1 Binary Implied Vol Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/robots.txt":{"get":{"summary":"Robots Txt","operationId":"robots_txt_robots_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"ExpectedGreeks":{"properties":{"delta":{"type":"string","title":"Delta","default":""},"gamma":{"type":"string","title":"Gamma","default":""},"vega":{"type":"string","title":"Vega","default":""},"theta":{"type":"string","title":"Theta","default":""}},"type":"object","title":"ExpectedGreeks","description":"Per-idea aggregated Greeks for the entire multi-leg structure.\n\nEach leg's per-share greek is multiplied by ``side_sign * quantity *\n100`` (option contract multiplier) and summed across legs. Decimal\nstrings preserve precision. The bot adds these into a portfolio-wide\nGlobal Risk total without recomputing.\n\nReturned as ``None`` on the response if no leg had usable greek data\nin the chain — consumers should treat that as \"compute your own\"."},"GreekIntent":{"properties":{"delta_target":{"type":"string","title":"Delta Target","default":""},"gamma_exposure":{"type":"string","title":"Gamma Exposure","default":""},"vega_exposure":{"type":"string","title":"Vega Exposure","default":""},"theta_target":{"type":"string","title":"Theta Target","default":""}},"type":"object","title":"GreekIntent","description":"Categorical Greek exposure intent from the LLM (e.g. 'bullish', 'short').\n\nDistinct from ``ExpectedGreeks`` (numeric per-trade aggregate computed\nfrom the chain). ``GreekIntent`` is the LLM's stated thesis;\n``ExpectedGreeks`` is what the chain actually says the trade exposes."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HandshakeResponse":{"properties":{"service":{"type":"string","title":"Service","default":"spark"},"version":{"type":"string","title":"Version","default":"1.0.0"},"capabilities":{"items":{"type":"string"},"type":"array","title":"Capabilities"},"pricing":{"$ref":"#/components/schemas/PricingInfo"},"demo_trades":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Demo Trades"},"sample_context":{"additionalProperties":true,"type":"object","title":"Sample Context"}},"type":"object","title":"HandshakeResponse","description":"Response for the free handshake endpoint."},"LegGreeks":{"properties":{"delta":{"type":"string","title":"Delta","default":""},"gamma":{"type":"string","title":"Gamma","default":""},"vega":{"type":"string","title":"Vega","default":""},"theta":{"type":"string","title":"Theta","default":""}},"type":"object","title":"LegGreeks","description":"Per-leg per-share Greeks pulled from the chain entry.\n\nValues are unsigned — they reflect the raw market quote, not the\nposition direction. The bot multiplies by side (BUY=+1 / SELL=-1)\nand ``quantity * 100`` to roll up portfolio exposure.\n\nAll fields are decimal strings to preserve precision. Empty string\nmeans the chain did not surface that greek (Schwab returns ``-999``\nsentinels for unavailable greeks; we drop them)."},"MarketContext":{"properties":{"sabr_params":{"additionalProperties":true,"type":"object","title":"Sabr Params"},"risk_reversal":{"additionalProperties":true,"type":"object","title":"Risk Reversal"},"term_structure":{"type":"string","title":"Term Structure","default":""},"model_used":{"type":"string","title":"Model Used","default":""},"spot_prices":{"additionalProperties":{"type":"string"},"type":"object","title":"Spot Prices","description":"Per-ticker spot price snapshot Spark used when proposing the ideas. Keys are uppercase tickers, values are decimal strings (e.g. {'AAPD': '48.32'}). Lets consumers ground ATM strikes without a second market-data round-trip."},"spot_prices_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spot Prices At","description":"ISO-8601 UTC timestamp ('Z' suffix) of the spot_prices snapshot. Within a few minutes of processing_time_ms when populated."},"ml_regime_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ml Regime Summary","description":"One-line summary of the regime block in the packed ml_regime payload. e.g. 'composite=Bull + Low Vol, GARCH persistence=0.97, vol_regime=Low'. Format: 'composite={regime_name}, GARCH persistence={alpha+beta:.2f}, vol_regime={regime_name}'. None when regime detection skipped or failed."},"macro_stress_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Macro Stress Level","description":"FRED-aggregated macro stress label. One of 'low_stress' / 'normal' / 'elevated' / 'crisis' (verbatim from library/risk/extreme_crash._compute_macro_regime). None when FRED unavailable or all indicators non-finite."},"diversification_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Diversification Ratio","description":"Portfolio diversification ratio (standalone VaR sum / correlation-adjusted VaR). >1 = diversified. Populated only on /v1/portfolio-recommendations when at least 2 held symbols have >=60 close candles."}},"type":"object","title":"MarketContext","description":"Market context returned alongside trade ideas."},"MarketInsightRequest":{"properties":{"agent_id":{"type":"string","title":"Agent Id","description":"Unique identifier for the calling agent"},"symbols":{"items":{"type":"string"},"type":"array","maxItems":10,"minItems":1,"title":"Symbols","description":"Ticker symbols, or macro sentinels prefixed with '@' (e.g. '@ssetf_underlying', '@ssetf_all'). Macros expand server-side; see GET /v1/universes for available macros."},"num_ideas":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Num Ideas","description":"Number of trade ideas to generate","default":3},"preferred_strategies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Preferred Strategies","description":"Preferred strategy types (e.g. credit_spread, calendar_spread)"},"market_context":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Market Context","description":"Agent's market context or thesis"},"market_reference_symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Reference Symbol","description":"Optional benchmark ticker for risk-side computations: tail-beta vs. this benchmark in extreme-crash analysis, and a zero-weight reference column in the correlation panel. When None (default), no benchmark is fetched and those risk blocks run benchmark-free. Per round-X 'no-implicit-benchmark' rule, no symbol is silently added on the agent's behalf. Whitespace is stripped; empty/whitespace-only values normalize to None."}},"type":"object","required":["agent_id","symbols"],"title":"MarketInsightRequest","description":"Request for market insights — trade ideas for specified symbols."},"OptionLegStructured":{"properties":{"underlying":{"type":"string","title":"Underlying","description":"Traded ticker the OCC chain belongs to"},"right":{"type":"string","title":"Right","description":"'CALL' or 'PUT'"},"side":{"type":"string","title":"Side","description":"'BUY' or 'SELL' (derived from instruction)"},"instruction":{"type":"string","title":"Instruction","description":"Original Schwab-style instruction (SELL_TO_OPEN, BUY_TO_OPEN, SELL_TO_CLOSE, BUY_TO_CLOSE).","default":""},"expiry":{"type":"string","title":"Expiry","description":"Expiration in YYYY-MM-DD format"},"strike":{"type":"string","title":"Strike","description":"Strike price as decimal string, e.g. '48.50'"},"quantity":{"type":"integer","minimum":1.0,"title":"Quantity","description":"Number of contracts"},"occ_symbol":{"type":"string","title":"Occ Symbol","description":"OCC option symbol (e.g. 'AAPD  260501P00048500'). Round-trips cleanly to the structured fields."},"limit_price":{"type":"string","title":"Limit Price","description":"Recommended LIMIT order price for this leg as a 2-decimal string (e.g. '1.85'). Computed server-side as the mid of the bid-ask spread observed in the chain Spark used for evaluation. Falls back to ``mark`` then ``last`` when bid/ask are unavailable. Empty string when no usable price could be computed — consumers should fall back to their own quote source rather than trade blind.","default":""},"bid":{"type":"string","title":"Bid","description":"Bid quote observed by Spark, decimal string. Informational.","default":""},"ask":{"type":"string","title":"Ask","description":"Ask quote observed by Spark, decimal string. Informational.","default":""},"greeks":{"anyOf":[{"$ref":"#/components/schemas/LegGreeks"},{"type":"null"}],"description":"Per-share unsigned Greeks from the chain entry. ``None`` if the chain did not surface usable greeks for this contract."},"iv_source":{"type":"string","title":"Iv Source","description":"Provenance of the IV used to compute this leg's Greeks. One of: ``'chain'`` (Schwab's per-strike IV), ``'bs_solved_from_mid'`` (Newton-Raphson IV solved from the bid/ask mid), ``'atm_chain'`` (closest-to-spot strike's IV on the same expiry), ``'sabr'`` (Hagan smile evaluator on calibrated SABR params), ``'vix_default'`` (last-resort VIX-derived). Empty string when no IV could be recovered. Lets consumers weight risk by data quality.","default":""}},"type":"object","required":["underlying","right","side","expiry","strike","quantity","occ_symbol"],"title":"OptionLegStructured","description":"Structured option leg with resolved strike, expiry, and OCC symbol.\n\nSurfaces the same data as the OCC string in ``legs[]`` but split into\ntyped fields so consumers do not have to parse OCC formatting (which\nhas provider-specific padding rules). Strike is sent as a string to\npreserve trailing zeros / fractional pennies without floating-point drift."},"PortfolioData":{"properties":{"cash_balance":{"type":"number","minimum":0.0,"title":"Cash Balance"},"positions":{"items":{"$ref":"#/components/schemas/PortfolioPosition"},"type":"array","title":"Positions"}},"type":"object","required":["cash_balance"],"title":"PortfolioData","description":"Agent-provided portfolio data."},"PortfolioPosition":{"properties":{"symbol":{"type":"string","title":"Symbol"},"quantity":{"type":"integer","title":"Quantity"},"average_price":{"type":"number","title":"Average Price"},"asset_type":{"type":"string","title":"Asset Type","description":"EQUITY or OPTION"},"underlying_symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Underlying Symbol"},"put_call":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Put Call"},"strike_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Strike Price"},"expiration":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiration"}},"type":"object","required":["symbol","quantity","average_price","asset_type"],"title":"PortfolioPosition","description":"A single position in the agent's portfolio."},"PortfolioRecommendationRequest":{"properties":{"agent_id":{"type":"string","title":"Agent Id","description":"Unique identifier for the calling agent"},"symbols":{"items":{"type":"string"},"type":"array","maxItems":10,"minItems":1,"title":"Symbols","description":"Ticker symbols, or macro sentinels prefixed with '@' (e.g. '@ssetf_underlying', '@ssetf_all'). Macros expand server-side."},"portfolio":{"$ref":"#/components/schemas/PortfolioData"},"num_ideas":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Num Ideas","default":3},"preferred_strategies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Preferred Strategies"},"market_context":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Market Context"},"market_reference_symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Reference Symbol","description":"Optional benchmark ticker for risk-side computations. See MarketInsightRequest.market_reference_symbol — same semantics + same validation. None (default) skips benchmark fetches."}},"type":"object","required":["agent_id","symbols","portfolio"],"title":"PortfolioRecommendationRequest","description":"Request for portfolio-aware trade recommendations."},"PricingInfo":{"properties":{"market_insights":{"type":"string","title":"Market Insights","default":"$0.05"},"portfolio_recommendations":{"type":"string","title":"Portfolio Recommendations","default":"$0.10"},"network":{"type":"string","title":"Network","default":"eip155:8453"},"currency":{"type":"string","title":"Currency","default":"USDC"}},"type":"object","title":"PricingInfo","description":"Pricing for paid endpoints."},"StatusResponse":{"properties":{"connected":{"type":"boolean","title":"Connected"},"expired":{"type":"boolean","title":"Expired","default":false},"saved_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Saved At"}},"type":"object","required":["connected"],"title":"StatusResponse"},"TradeIdea":{"properties":{"title":{"type":"string","title":"Title"},"sentiment":{"type":"string","title":"Sentiment","default":""},"rationale":{"type":"string","title":"Rationale","default":""},"regime_alignment":{"type":"string","title":"Regime Alignment","default":""},"greek_intent":{"anyOf":[{"$ref":"#/components/schemas/GreekIntent"},{"type":"null"}]},"expected_greeks":{"anyOf":[{"$ref":"#/components/schemas/ExpectedGreeks"},{"type":"null"}],"description":"Per-idea numeric Greek exposure aggregated from the chain. Each leg's per-share greek is signed by side and scaled by ``quantity * 100`` (option contract multiplier), then summed. ``None`` when no leg had usable chain Greeks. Distinct from ``greek_intent`` which is the LLM's categorical thesis."},"expected_vrp":{"type":"string","title":"Expected Vrp","description":"Variance Risk Premium: representative implied vol minus realized vol, expressed in vol **points** as a decimal string (e.g. ``'1.20'`` = 1.20 percentage points). Positive ⇒ options are rich vs realized (vol-selling favorable); negative ⇒ options are cheap (vol-buying). IV is the mean of the legs' BS IVs (whatever rung of the IV-recovery chain supplied them); RV is 20-day annualized (``√252``) std-dev of log returns from Schwab daily bars. Empty string when RV could not be computed (no daily-bar history available) — bot should fall back to its own estimate rather than treating zero as a real signal.","default":""},"target_dte":{"type":"string","title":"Target Dte","default":""},"legs":{"items":{"type":"string"},"type":"array","title":"Legs"},"legs_structured":{"items":{"$ref":"#/components/schemas/OptionLegStructured"},"type":"array","title":"Legs Structured","description":"Structured echo of legs[] with resolved strike/expiry/right/occ_symbol/limit_price/greeks. Same length as legs when server-side resolution succeeds; empty list when resolution failed (older consumers should keep using legs[] for back-compat)."},"symbol":{"type":"string","title":"Symbol","default":""}},"type":"object","required":["title"],"title":"TradeIdea","description":"A single trade idea."},"TradeIdeasResponse":{"properties":{"decision":{"type":"string","title":"Decision","default":"GENERATED"},"trade_ideas":{"items":{"$ref":"#/components/schemas/TradeIdea"},"type":"array","title":"Trade Ideas"},"context":{"$ref":"#/components/schemas/MarketContext"},"processing_time_ms":{"type":"integer","title":"Processing Time Ms","default":0},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"}},"type":"object","title":"TradeIdeasResponse","description":"Response for both market-insights and portfolio-recommendations."},"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"}}}}