Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Fetch raw Yahoo Finance Options data and output the schema. | |
| Shows raw API response structure for options chain data. | |
| """ | |
| import asyncio | |
| import json | |
| from datetime import datetime | |
| from pathlib import Path | |
| import httpx | |
| YAHOO_HEADERS = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", | |
| "Accept": "application/json", | |
| } | |
| def print_table(title: str, rows: list, col_widths: list = None): | |
| """Print ASCII table.""" | |
| if not rows: | |
| return | |
| # Calculate column widths | |
| if col_widths is None: | |
| col_widths = [] | |
| for col in range(len(rows[0])): | |
| width = max(len(str(row[col])) for row in rows) | |
| col_widths.append(width) | |
| # Print header | |
| print(f"\n{title}") | |
| # Top border | |
| line = "β" + "β¬".join("β" * (w + 2) for w in col_widths) + "β" | |
| print(line) | |
| # Header row | |
| header = rows[0] | |
| row_str = "β" + "β".join(f" {str(header[i]).ljust(col_widths[i])} " for i in range(len(header))) + "β" | |
| print(row_str) | |
| # Separator | |
| line = "β" + "βΌ".join("β" * (w + 2) for w in col_widths) + "β€" | |
| print(line) | |
| # Data rows | |
| for row in rows[1:]: | |
| row_str = "β" + "β".join(f" {str(row[i]).ljust(col_widths[i])} " for i in range(len(row))) + "β" | |
| print(row_str) | |
| # Bottom border | |
| line = "β" + "β΄".join("β" * (w + 2) for w in col_widths) + "β" | |
| print(line) | |
| async def fetch_options(ticker: str) -> dict: | |
| """Fetch options chain from Yahoo Finance.""" | |
| try: | |
| async with httpx.AsyncClient() as client: | |
| url = f"https://query1.finance.yahoo.com/v7/finance/options/{ticker}" | |
| response = await client.get(url, headers=YAHOO_HEADERS, timeout=15) | |
| return response.json() | |
| except Exception as e: | |
| return {"error": str(e)} | |
| async def main(): | |
| print("Yahoo Finance Options Data Schema") | |
| print("=" * 60) | |
| print() | |
| print("Endpoint: https://query1.finance.yahoo.com/v7/finance/options/{ticker}") | |
| print() | |
| print("Fetching AAPL options chain...") | |
| data = await fetch_options("AAPL") | |
| if "error" in data: | |
| print(f"ERROR: {data}") | |
| return | |
| option_chain = data.get("optionChain", {}) | |
| result = option_chain.get("result", [{}])[0] if option_chain.get("result") else {} | |
| if not result: | |
| print("ERROR: No options data returned") | |
| return | |
| print() | |
| print("=" * 60) | |
| print() | |
| # Print raw API response structure | |
| print("Raw API Response Structure") | |
| print("-" * 40) | |
| # Underlying quote | |
| quote = result.get("quote", {}) | |
| rows = [["field", "value"]] | |
| rows.append(["symbol", quote.get("symbol", "")]) | |
| rows.append(["regularMarketPrice", quote.get("regularMarketPrice", "")]) | |
| rows.append(["regularMarketTime", quote.get("regularMarketTime", "")]) | |
| rows.append(["regularMarketChange", quote.get("regularMarketChange", "")]) | |
| rows.append(["regularMarketChangePercent", quote.get("regularMarketChangePercent", "")]) | |
| print_table("quote (Underlying)", rows) | |
| # Expiration dates | |
| expirations = result.get("expirationDates", []) | |
| rows = [["field", "description"]] | |
| rows.append(["expirationDates[]", "Unix timestamps of available expiration dates"]) | |
| rows.append(["count", str(len(expirations))]) | |
| if expirations: | |
| rows.append(["first", str(expirations[0])]) | |
| rows.append(["last", str(expirations[-1])]) | |
| print_table("Expiration Dates", rows) | |
| # Strikes | |
| strikes = result.get("strikes", []) | |
| rows = [["field", "description"]] | |
| rows.append(["strikes[]", "Available strike prices"]) | |
| rows.append(["count", str(len(strikes))]) | |
| if strikes: | |
| rows.append(["min", str(min(strikes))]) | |
| rows.append(["max", str(max(strikes))]) | |
| print_table("Strike Prices", rows) | |
| # Options data structure | |
| options = result.get("options", [{}])[0] if result.get("options") else {} | |
| calls = options.get("calls", []) | |
| puts = options.get("puts", []) | |
| rows = [["field", "description"]] | |
| rows.append(["expirationDate", "Expiration date (Unix timestamp)"]) | |
| rows.append(["calls[]", f"Call options array (count: {len(calls)})"]) | |
| rows.append(["puts[]", f"Put options array (count: {len(puts)})"]) | |
| print_table("options[0] (First Expiration)", rows) | |
| # Call/Put contract fields | |
| if calls: | |
| sample_call = calls[0] | |
| rows = [["field", "value"]] | |
| rows.append(["contractSymbol", sample_call.get("contractSymbol", "")]) | |
| rows.append(["strike", sample_call.get("strike", "")]) | |
| rows.append(["currency", sample_call.get("currency", "")]) | |
| rows.append(["lastPrice", sample_call.get("lastPrice", "")]) | |
| rows.append(["change", sample_call.get("change", "")]) | |
| rows.append(["percentChange", sample_call.get("percentChange", "")]) | |
| rows.append(["volume", sample_call.get("volume", "")]) | |
| rows.append(["openInterest", sample_call.get("openInterest", "")]) | |
| rows.append(["bid", sample_call.get("bid", "")]) | |
| rows.append(["ask", sample_call.get("ask", "")]) | |
| rows.append(["impliedVolatility", sample_call.get("impliedVolatility", "")]) | |
| rows.append(["inTheMoney", sample_call.get("inTheMoney", "")]) | |
| rows.append(["expiration", sample_call.get("expiration", "")]) | |
| rows.append(["lastTradeDate", sample_call.get("lastTradeDate", "")]) | |
| print_table("calls[0] / puts[0] (Contract Fields)", rows) | |
| # ATM implied volatility example | |
| print() | |
| print() | |
| print("Implied Volatility Extraction") | |
| print("-" * 40) | |
| current_price = quote.get("regularMarketPrice", 0) | |
| if calls and current_price: | |
| atm_call = min(calls, key=lambda x: abs(x.get("strike", 0) - current_price)) | |
| iv = atm_call.get("impliedVolatility", 0) * 100 | |
| rows = [["field", "value"]] | |
| rows.append(["currentPrice", f"{current_price:.2f}"]) | |
| rows.append(["atmStrike", atm_call.get("strike", "")]) | |
| rows.append(["impliedVolatility (raw)", atm_call.get("impliedVolatility", "")]) | |
| rows.append(["impliedVolatility (%)", f"{iv:.2f}%"]) | |
| print_table("ATM Call Option", rows) | |
| # Save raw JSON | |
| output_path = Path(__file__).parent.parent / "docs" / "yahoo_options_raw.json" | |
| with open(output_path, 'w') as f: | |
| json.dump(data, f, indent=2, default=str) | |
| print(f"\nRaw JSON saved to: {output_path}") | |
| if __name__ == "__main__": | |
| asyncio.run(main()) | |