{"openapi":"3.1.0","info":{"title":"QREP Backend API","description":"Portfolio analytics API powered by QuantStats","version":"1.0.0"},"paths":{"/":{"get":{"summary":"Root","description":"Health check and info endpoint","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","description":"Health check endpoint","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/qpulse/analyze":{"post":{"summary":"Qpulse Analyze","description":"Generate QREP tearsheet (powered by QuantStats).\n\nProtected by API key if QPULSE_API_KEY env var is set.","operationId":"qpulse_analyze_qpulse_analyze_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QREPAnalysisRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QREPAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Qpulse Analyze Get","description":"GET version of QREP analyze for browser/curl testing","operationId":"qpulse_analyze_get_qpulse_analyze_get","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string","description":"Stock symbol","title":"Symbol"},"description":"Stock symbol"},{"name":"benchmark","in":"query","required":false,"schema":{"type":"string","description":"Benchmark symbol","default":"SPY","title":"Benchmark"},"description":"Benchmark symbol"},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","description":"Start date (YYYY-MM-DD)","title":"Start Date"},"description":"Start date (YYYY-MM-DD)"},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","description":"End date (YYYY-MM-DD)","title":"End Date"},"description":"End date (YYYY-MM-DD)"},{"name":"risk_free_rate","in":"query","required":false,"schema":{"type":"number","description":"Risk-free rate as decimal","default":0.0,"title":"Risk Free Rate"},"description":"Risk-free rate as decimal"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QREPAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{filename}":{"get":{"summary":"Serve Report","description":"Serve generated report files","operationId":"serve_report_reports__filename__get","parameters":[{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/qpulse/compare":{"post":{"summary":"Qpulse Compare","description":"Compare multiple securities with full metrics.\nReturns categorized metrics for tabs UI.\nMax 6 securities.","operationId":"qpulse_compare_qpulse_compare_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiSecurityCompareRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiSecurityCompareResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/qpulse/compare/export":{"post":{"summary":"Export Comparison","description":"Export comparison results as HTML or PDF","operationId":"export_comparison_qpulse_compare_export_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string","title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareExportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/qpulse/portfolio":{"post":{"summary":"Portfolio Compare","description":"Compare multiple portfolios with weighted holdings.\nEach portfolio can have up to 10 holdings with custom weights.\nReturns all QuantStats metrics for each portfolio.","operationId":"portfolio_compare_qpulse_portfolio_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string","title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioCompareRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioCompareResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/compare":{"get":{"summary":"Mcp Compare","description":"QREP security comparison — returns 81 portfolio metrics per symbol (powered by QuantStats).\nLightweight endpoint for LLM/MCP consumption (no time series, no chart data, no price data).\nNo API key required.\n\nRESPONSE STRUCTURE:\n- success: boolean indicating overall success\n- benchmark: the benchmark symbol used\n- start_date / end_date: the date range used\n- risk_free_rate: the risk-free rate used\n- symbols: array of per-symbol results, each containing:\n    - symbol: ticker string\n    - success: boolean\n    - trading_days: number of trading days in the period\n    - error: null on success, error message on failure\n    - all_metrics: object with 81 key-value metric pairs (see list below)\n- benchmark_metrics: same structure as a symbol entry, but for the benchmark itself.\n  NOTE: Beta, Alpha, Correlation, and Treynor Ratio are null for the benchmark (cannot compare against itself).\n- message: summary string (e.g. \"Compared 3/3 securities successfully\")\n\nCOMPLETE LIST OF 81 METRICS (per symbol):\nAll values are decimals unless noted. Percentages as decimals (e.g. 0.31 = 31%).\n\nReturns & Performance:\nCumulative Return, CAGR%, MTD, 3M, 6M, YTD, 1Y, 3Y (ann.), 5Y (ann.), 10Y (ann.), All-time (ann.),\nBest Day, Worst Day, Best Month, Worst Month, Best Year, Worst Year,\nExpected Daily, Expected Monthly, Expected Yearly,\nAvg. Return, Avg. Win, Avg. Loss, Avg. Up Month, Avg. Down Month\n\nRisk-Adjusted Ratios:\nSharpe, Smart Sharpe, Prob. Sharpe Ratio,\nSortino, Smart Sortino, Sortino/sqrt(2), Smart Sortino/sqrt(2),\nOmega, Calmar, Treynor Ratio, Information Ratio,\nRisk-Adjusted Return, Risk-Return Ratio, Ulcer Performance Index\n\nDrawdown:\nMax Drawdown, Max DD Date (YYYY-MM-DD), Max DD Period Start, Max DD Period End,\nLongest DD Days (integer), Avg. Drawdown, Avg. Drawdown Days (integer),\nRecovery Factor, Ulcer Index, Serenity Index\n\nVolatility & Distribution:\nVolatility (ann.), Skew, Kurtosis, R-squared\n\nBenchmark-Relative (null for the benchmark itself):\nBeta, Alpha, Correlation\n\nValue-at-Risk & Tail Risk:\nDaily Value-at-Risk, Expected Shortfall (cVaR),\nRisk of Ruin, Kelly Criterion,\nTail Ratio, Outlier Win Ratio, Outlier Loss Ratio\n\nWin/Loss & Trade Statistics:\nWin Days %, Win Month %, Win Quarter %, Win Year %,\nWin/Loss Ratio, Profit Ratio, Payoff Ratio, Profit Factor,\nMax Consecutive Wins (integer), Max Consecutive Losses (integer),\nGain/Pain Ratio, Gain/Pain (1M), Common Sense Ratio, CPC Index\n\nTime Context:\nStart Period (YYYY-MM-DD), End Period (YYYY-MM-DD),\nRisk-Free Rate (as percentage, e.g. 4.5), Time in Market (decimal, 1.0 = 100%)\n\nNOTES:\n1. 3Y, 5Y, 10Y, All-time annualized returns equal CAGR if the data period is shorter than those horizons.\n2. Dates in Max DD fields are strings in YYYY-MM-DD format.\n3. Integer metrics (Longest DD Days, Avg. Drawdown Days, Max Consecutive Wins/Losses) are returned as floats (e.g. 133.0).","operationId":"mcp_compare_securities","parameters":[{"name":"symbols","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated Yahoo Finance ticker symbols, max 6 (e.g. AAPL,MSFT,GOOG)","title":"Symbols"},"description":"Comma-separated Yahoo Finance ticker symbols, max 6 (e.g. AAPL,MSFT,GOOG)"},{"name":"benchmark","in":"query","required":false,"schema":{"type":"string","description":"Benchmark symbol. Can be any valid Yahoo Finance ticker.","default":"SPY","title":"Benchmark"},"description":"Benchmark symbol. Can be any valid Yahoo Finance ticker."},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","description":"Start date YYYY-MM-DD. Should be at least 6 months before end_date for meaningful analysis.","title":"Start Date"},"description":"Start date YYYY-MM-DD. Should be at least 6 months before end_date for meaningful analysis."},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","description":"End date YYYY-MM-DD. Must not be in the future.","title":"End Date"},"description":"End date YYYY-MM-DD. Must not be in the future."},{"name":"risk_free_rate","in":"query","required":false,"schema":{"type":"number","description":"Risk-free rate as decimal (e.g. 0.045 for 4.5%). Used in Sharpe, Sortino, Treynor, and other risk-adjusted calculations.","default":0.0,"title":"Risk Free Rate"},"description":"Risk-free rate as decimal (e.g. 0.045 for 4.5%). Used in Sharpe, Sortino, Treynor, and other risk-adjusted calculations."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPCompareResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/cleanup":{"post":{"summary":"Cleanup Reports Endpoint","description":"Clean up old report files. Protected by CLEANUP_API_KEY or QPULSE_API_KEY.","operationId":"cleanup_reports_endpoint_cleanup_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"CompareExportRequest":{"properties":{"symbols":{"items":{"type":"string"},"type":"array","title":"Symbols","description":"List of symbols to compare"},"benchmark":{"type":"string","title":"Benchmark","description":"Benchmark symbol","default":"SPY"},"start_date":{"type":"string","title":"Start Date","description":"Start date YYYY-MM-DD"},"end_date":{"type":"string","title":"End Date","description":"End date YYYY-MM-DD"},"risk_free_rate":{"type":"number","title":"Risk Free Rate","description":"Risk-free rate as decimal","default":0.0},"omega_threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Omega Threshold","description":"Optional Omega ratio threshold as decimal"},"var_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Var Confidence","description":"Optional VaR/CVaR confidence level as decimal"},"tail_cutoff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tail Cutoff","description":"Optional Tail Ratio percentile as decimal"},"format":{"type":"string","title":"Format","description":"Export format: html or pdf","default":"html"}},"type":"object","required":["symbols","start_date","end_date"],"title":"CompareExportRequest","description":"Request model for comparison export"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HoldingInput":{"properties":{"symbol":{"type":"string","title":"Symbol","description":"Stock ticker symbol"},"weight":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Weight","description":"Weight as decimal (0.0-1.0), e.g., 0.40 for 40%"}},"type":"object","required":["symbol","weight"],"title":"HoldingInput","description":"Single holding in a portfolio"},"MCPCompareResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"benchmark":{"type":"string","title":"Benchmark"},"start_date":{"type":"string","title":"Start Date"},"end_date":{"type":"string","title":"End Date"},"risk_free_rate":{"type":"number","title":"Risk Free Rate"},"symbols":{"items":{"$ref":"#/components/schemas/MCPCompareSymbolMetrics"},"type":"array","title":"Symbols"},"benchmark_metrics":{"anyOf":[{"$ref":"#/components/schemas/MCPCompareSymbolMetrics"},{"type":"null"}],"description":"Metrics for the benchmark"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","benchmark","start_date","end_date","risk_free_rate","symbols","message"],"title":"MCPCompareResponse","description":"Slim response for MCP compare endpoint - metrics only, no chart data"},"MCPCompareSymbolMetrics":{"properties":{"symbol":{"type":"string","title":"Symbol"},"success":{"type":"boolean","title":"Success"},"trading_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trading Days"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"all_metrics":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"All Metrics","description":"81 key-value portfolio metric pairs (powered by QuantStats)"}},"type":"object","required":["symbol","success"],"title":"MCPCompareSymbolMetrics","description":"Slim metrics for MCP - only all_metrics, no charts/time_series"},"MultiSecurityCompareRequest":{"properties":{"symbols":{"items":{"type":"string"},"type":"array","maxItems":6,"minItems":1,"title":"Symbols","description":"List of stock symbols (max 6)"},"benchmark":{"type":"string","title":"Benchmark","description":"Benchmark symbol","default":"SPY"},"start_date":{"type":"string","title":"Start Date","description":"Start date (YYYY-MM-DD)"},"end_date":{"type":"string","title":"End Date","description":"End date (YYYY-MM-DD)"},"risk_free_rate":{"type":"number","title":"Risk Free Rate","description":"Risk-free rate as decimal (e.g., 0.045 for 4.5%)","default":0.0},"omega_threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Omega Threshold","description":"Optional Omega ratio threshold as decimal (e.g., 0.05 for 5%). If not provided, uses default 0%"},"var_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Var Confidence","description":"Optional VaR/CVaR confidence level as decimal (e.g., 0.99 for 99%). If not provided, uses default 0.95"},"tail_cutoff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tail Cutoff","description":"Optional Tail Ratio percentile as decimal (e.g., 0.99 for 99%). If not provided, uses default 0.95"}},"type":"object","required":["symbols","start_date","end_date"],"title":"MultiSecurityCompareRequest","description":"Request model for multi-security comparison"},"MultiSecurityCompareResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"benchmark":{"type":"string","title":"Benchmark"},"start_date":{"type":"string","title":"Start Date"},"end_date":{"type":"string","title":"End Date"},"risk_free_rate":{"type":"number","title":"Risk Free Rate"},"symbols":{"items":{"$ref":"#/components/schemas/SymbolMetrics"},"type":"array","title":"Symbols"},"benchmark_metrics":{"anyOf":[{"$ref":"#/components/schemas/SymbolMetrics"},{"type":"null"}],"description":"Metrics for the benchmark itself"},"categories":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Categories","description":"List of category keys and titles for tabs"},"message":{"type":"string","title":"Message"},"price_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Price Data","description":"Adjusted close price data for CSV download"}},"type":"object","required":["success","benchmark","start_date","end_date","risk_free_rate","symbols","categories","message"],"title":"MultiSecurityCompareResponse","description":"Response model for multi-security comparison"},"PortfolioCompareRequest":{"properties":{"portfolios":{"items":{"$ref":"#/components/schemas/PortfolioInput"},"type":"array","maxItems":6,"minItems":1,"title":"Portfolios","description":"List of portfolios (1-6)"},"benchmark":{"type":"string","title":"Benchmark","description":"Benchmark symbol","default":"SPY"},"start_date":{"type":"string","title":"Start Date","description":"Start date (YYYY-MM-DD)"},"end_date":{"type":"string","title":"End Date","description":"End date (YYYY-MM-DD)"},"risk_free_rate":{"type":"number","title":"Risk Free Rate","description":"Risk-free rate as decimal","default":0.0},"rebalance":{"type":"string","title":"Rebalance","description":"Rebalance frequency: 1ME (monthly), 1QE (quarterly), 1YE (yearly), or empty for none","default":"1ME"},"omega_threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Omega Threshold","description":"Optional Omega ratio threshold"},"var_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Var Confidence","description":"Optional VaR/CVaR confidence level"},"tail_cutoff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tail Cutoff","description":"Optional Tail Ratio percentile"}},"type":"object","required":["portfolios","start_date","end_date"],"title":"PortfolioCompareRequest","description":"Request model for portfolio comparison"},"PortfolioCompareResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"benchmark":{"type":"string","title":"Benchmark"},"start_date":{"type":"string","title":"Start Date"},"end_date":{"type":"string","title":"End Date"},"risk_free_rate":{"type":"number","title":"Risk Free Rate"},"rebalance":{"type":"string","title":"Rebalance"},"portfolios":{"items":{"$ref":"#/components/schemas/PortfolioMetrics"},"type":"array","title":"Portfolios"},"benchmark_metrics":{"anyOf":[{"$ref":"#/components/schemas/SymbolMetrics"},{"type":"null"}],"description":"Metrics for the benchmark"},"categories":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Categories","description":"List of category keys and titles for tabs"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","benchmark","start_date","end_date","risk_free_rate","rebalance","portfolios","categories","message"],"title":"PortfolioCompareResponse","description":"Response model for portfolio comparison"},"PortfolioInput":{"properties":{"name":{"type":"string","maxLength":6,"title":"Name","description":"Portfolio name (max 6 chars)"},"holdings":{"items":{"$ref":"#/components/schemas/HoldingInput"},"type":"array","maxItems":10,"minItems":1,"title":"Holdings","description":"List of holdings (1-10)"}},"type":"object","required":["name","holdings"],"title":"PortfolioInput","description":"Portfolio definition with name and holdings"},"PortfolioMetrics":{"properties":{"name":{"type":"string","title":"Name"},"success":{"type":"boolean","title":"Success"},"holdings":{"items":{"$ref":"#/components/schemas/HoldingInput"},"type":"array","title":"Holdings"},"total_weight":{"type":"number","title":"Total Weight"},"trading_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trading Days"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"all_metrics":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"All Metrics"},"categorized":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Categorized"},"time_series":{"anyOf":[{"$ref":"#/components/schemas/TimeSeriesData"},{"type":"null"}]}},"type":"object","required":["name","success","holdings","total_weight"],"title":"PortfolioMetrics","description":"Metrics for a single portfolio"},"QREPAnalysisRequest":{"properties":{"symbol":{"type":"string","title":"Symbol","description":"Stock symbol (e.g., 'AAPL', 'MSFT')"},"benchmark":{"type":"string","title":"Benchmark","description":"Benchmark symbol","default":"SPY"},"start_date":{"type":"string","title":"Start Date","description":"Start date (YYYY-MM-DD)"},"end_date":{"type":"string","title":"End Date","description":"End date (YYYY-MM-DD)"},"risk_free_rate":{"type":"number","title":"Risk Free Rate","description":"Risk-free rate as decimal (e.g., 0.045 for 4.5%)","default":0.0}},"type":"object","required":["symbol","start_date","end_date"],"title":"QREPAnalysisRequest","description":"Request model for QREP tearsheet generation"},"QREPAnalysisResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"html_url":{"type":"string","title":"Html Url","description":"URL to the generated HTML tearsheet"},"message":{"type":"string","title":"Message"},"price_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Price Data","description":"Adjusted close price data for CSV download"}},"type":"object","required":["success","html_url","message"],"title":"QREPAnalysisResponse","description":"Response model for QREP tearsheet"},"SymbolMetrics":{"properties":{"symbol":{"type":"string","title":"Symbol"},"success":{"type":"boolean","title":"Success"},"trading_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trading Days"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"all_metrics":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"All Metrics"},"categorized":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Categorized"},"time_series":{"anyOf":[{"$ref":"#/components/schemas/TimeSeriesData"},{"type":"null"}]}},"type":"object","required":["symbol","success"],"title":"SymbolMetrics","description":"Metrics for a single symbol"},"TimeSeriesData":{"properties":{"dates":{"items":{"type":"string"},"type":"array","title":"Dates","description":"ISO date strings"},"cumulative_returns":{"items":{"type":"number"},"type":"array","title":"Cumulative Returns","description":"Cumulative returns (1 = 100%)"},"drawdowns":{"items":{"type":"number"},"type":"array","title":"Drawdowns","description":"Drawdown values (negative, 0 to -1)"}},"type":"object","required":["dates","cumulative_returns","drawdowns"],"title":"TimeSeriesData","description":"Time series data for charts"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}