{"openapi":"3.1.0","info":{"title":"Security Performance Review (SPR) API","description":"Open, no-auth Security Performance Review: returns, drawdowns and risk metrics for one or more symbols over a date range, computed with the open-source ffn library and returned as an HTML report plus downloadable CSVs.\n\n## Quick start\n\nOne `POST`, no API key. Copy this, then change the symbols and the dates:\n\n```\ncurl -X POST https://ffn.tigzig.com/v1/analyze -H 'Content-Type: application/json' -d '{\"symbols\": \"AAPL,MSFT,GOOG\", \"start_date\": \"2023-01-01\", \"end_date\": \"2023-12-31\", \"risk_free_rate\": 5.0}'\n```\n\n## What you send\n\n`POST /v1/analyze` with a JSON body containing `symbols`, `start_date` and `end_date`. Symbols follow the Yahoo Finance convention, so non-US listings carry an exchange suffix: RELIANCE.NS (India NSE), .BO (BSE), .L (London), .HK (Hong Kong), .T (Tokyo). Indices look like ^NSEI and FX like EURUSD=X. Broker, scheme or company names do not resolve. Dates are YYYY-MM-DD.\n\n**Dates are strings, not numbers.** `start_date` and `end_date` must be written as `YYYY-MM-DD`. A bare number is rejected rather than guessed at: it could be a unix timestamp or a spreadsheet date serial, and guessing wrong produces a confidently incorrect date range. If your value came from a spreadsheet cell, wrap it as `TEXT(A1,\"YYYY-MM-DD\")`.\n\n## What you get back\n\nURLs to a generated HTML report and downloadable CSVs. The analysis lives in those files, not in the JSON.\n\n## Public endpoints\n\n`POST /v1/analyze`. `GET /v1/` returns the discovery block as JSON.\n\n## Request limits\n\n- **Report generation is serialised**, so parallel calls queue rather than finish sooner. Send them sequentially - firing them at once makes the whole set slower, not faster.\n- A typical run takes **10-30 seconds**. Set your client timeout accordingly.\n- At most **4 concurrent analyses per IP**; beyond that you get a 429 with `Retry-After`.\n- **Read your budget off the response headers, do not hard-code a number**: `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` are on every response and come out of the running limiter, so they cannot go stale.\n\n## Partial results\n\nWhen a request is not served exactly as asked, the response carries an `X-Tigzig-Warnings` header holding a JSON array of plain-English notes - a symbol that returned no data and was excluded, or an analysis window narrowed to the range every security shares.\n\n**The header is absent when the request was served in full, so its presence is the signal.** The report body is unaffected either way.\n\n## Errors\n\nEvery 4xx and 5xx returns `{error: {code, message}, help: {docs, openapi, catalog}}`.\n\n- A 4xx caused by the **shape** of the request - a missing field, or one that cannot be parsed - also carries `example`, a runnable curl built from this spec.\n- A 4xx caused by a **value** does not, because the shape was already right and an example would only show you what you already sent. Read the message instead.\n\n## Attribution\n\nDrawdown and monthly-return analysis is computed with the open-source **ffn** library. Performance statistics are custom calculations.\n\nMore Tigzig tools: https://api.tigzig.com/.well-known/api-catalog","version":"1.3.0"},"paths":{"/":{"get":{"summary":"Read Root","operationId":"read_root__get","parameters":[{"name":"error","in":"query","required":false,"schema":{"type":"string","description":"Error message to display","title":"Error"},"description":"Error message to display"},{"name":"success","in":"query","required":false,"schema":{"type":"string","description":"Success message to display","title":"Success"},"description":"Success message to display"},{"name":"report_path","in":"query","required":false,"schema":{"type":"string","description":"Path to generated report","title":"Report Path"},"description":"Path to generated report"}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/analyze":{"post":{"summary":"Analyze","description":"Generates a comprehensive SPR (Security Performance Review) portfolio analysis report using custom calculations and FFN metrics.\n\nThis endpoint performs detailed SPR portfolio analysis including:\n- Performance statistics using custom calculations (returns, volatility, Sharpe ratio, etc.)\n- Drawdown analysis using FFN library (maximum drawdown, drawdown periods)\n- Monthly returns breakdown by security via FFN\n\nSupports multiple stock symbols for SPR portfolio analysis. The risk-free rate is used in\ncustom Sharpe ratio and other risk-adjusted return calculations.\n\nThe SPR analysis is returned as an HTML report with:\n- Data summary with date ranges and price information\n- Comprehensive performance metrics table using custom calculations (including Sharpe ratios calculated with provided risk-free rate)\n- Detailed drawdown analysis for each security via FFN\n- Monthly return tables with color-coded performance via FFN\n\nExample request:\n{\n    \"symbols\": \"AAPL,MSFT,GOOG\",\n    \"start_date\": \"2023-01-01\",\n    \"end_date\": \"2023-12-31\",\n    \"risk_free_rate\": 5.0\n}\n\nParameters:\n- symbols: Comma-separated Yahoo Finance ticker symbols (e.g., 'AAPL,MSFT,GOOG'). Supports multiple symbols for SPR analysis.\n- start_date: SPR analysis start date (YYYY-MM-DD format)\n- end_date: SPR analysis end date (YYYY-MM-DD format)\n- risk_free_rate: Annual risk-free rate percentage (default: 0.0%). Used for custom Sharpe ratio calculations in SPR.\n\nReturns:\n- PortfolioAnalysisResponse with SPR HTML report URL and success message\n\nRaises:\n- HTTPException 400: Invalid parameters or insufficient data for SPR analysis\n- HTTPException 500: Data fetching or SPR processing errors\n\nNote: a typical run takes 10-30 seconds, longer with more symbols or a wider range.\nThis figure is also published in the GET /v1/ discovery block; the two must agree.\nSet a client timeout of at least 120s so a slow upstream fetch does not look like a failure.\n\nPart of Tigzig: free interactive tools, open-source repos, APIs and MCP servers for\nanalytics and live data across global and Indian markets, macro indicators and\nfilings. Catalog: https://api.tigzig.com/.well-known/api-catalog\nGuide: https://www.tigzig.com/llms.txt","operationId":"analyze_portfolio","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioAnalysisRequest","description":"Portfolio analysis request parameters"},"example":{"symbols":"AAPL,MSFT,GOOG","start_date":"2023-01-01","end_date":"2023-12-31","risk_free_rate":5.0}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"PortfolioAnalysisRequest":{"properties":{"symbols":{"type":"string","title":"Symbols","description":"Stock symbols to analyze, comma-separated (e.g., 'AAPL,GOOG,MSFT'). Must be valid Yahoo Finance ticker symbols. Supports multiple symbols for SPR portfolio analysis using custom calculations and FFN metrics.","example":"AAPL,MSFT,GOOG"},"start_date":{"type":"string","format":"date","title":"Start Date","description":"Start date for SPR analysis. Should be at least 6 months before end_date for meaningful analysis. Format: YYYY-MM-DD","example":"2023-01-01"},"end_date":{"type":"string","format":"date","title":"End Date","description":"End date for SPR analysis. Must be after start_date and not in the future. Format: YYYY-MM-DD","example":"2023-12-31"},"risk_free_rate":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Risk Free Rate","description":"Risk-free rate as annual percentage (e.g., 5.0 for 5%). Used in SPR custom Sharpe ratio and other risk-adjusted return calculations. Default is 0.0% if not provided.","default":0.0,"example":5.0}},"type":"object","required":["symbols","start_date","end_date"],"title":"PortfolioAnalysisRequest","description":"Request model for SPR (Security Performance Review) portfolio analysis generation.","example":{"end_date":"2023-12-31","risk_free_rate":5.0,"start_date":"2023-01-01","symbols":"AAPL,MSFT,GOOG"}},"PortfolioAnalysisResponse":{"properties":{"html_report_ffn_url":{"type":"string","title":"Html Report Ffn Url","description":"URL to access the SPR HTML report with portfolio analysis and visualizations using custom calculations and FFN metrics"},"input_price_data_csv_url":{"type":"string","title":"Input Price Data Csv Url","description":"URL to download the processed price data CSV file used in SPR analysis"},"cumulative_returns_csv_url":{"type":"string","title":"Cumulative Returns Csv Url","description":"URL to download the cumulative returns data CSV file from SPR analysis"},"success":{"type":"string","title":"Success","description":"Success message indicating SPR report generation status"}},"type":"object","required":["html_report_ffn_url","input_price_data_csv_url","cumulative_returns_csv_url","success"],"title":"PortfolioAnalysisResponse","description":"Response model for SPR (Security Performance Review) portfolio analysis."},"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"}}}}