mirror of
https://github.com/Mihirkansara/nexus-quant-terminal.git
synced 2026-08-21 22:58:08 +00:00
Full-stack forex options analytics terminal with Bloomberg-inspired UI. Backend (FastAPI + Python): - Garman-Kohlhagen options pricing engine with full Greeks - Goldman Sachs gs-quant AI signals (RSI, MACD, Bollinger, Hurst, OU) - Monte Carlo GBM simulation and volatility surface generation - CFTC COT institutional positioning + Forex Factory economic calendar - Live data proxy: OpenSky aircraft + USGS earthquakes (CORS-safe) - Multi-leg strategy library (straddle, iron condor, butterfly, spreads) Frontend (React 18 + Vite): - NEXUS animated orbital logo (3-ring SVG) + canvas favicon animation - Bloomberg terminal design: JetBrains Mono, color-mix() tokens - 11 dashboard tabs: Greeks, Chart, AI Signals, 3D Surfaces, Breakeven, Scenarios, Monte Carlo, Institutional, Calendar, Live Map, Live Feeds - Live World Map (react-leaflet): aircraft, earthquakes, weather radar - Live Feeds: CoinGecko crypto top-12 + Windy.com global webcams - Economic calendar with filters + institutional flow (CFTC COT) - Animated landing page + session-based routing - Fully responsive dark-only terminal design system Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
from fastapi import APIRouter, HTTPException
|
|
import yfinance as yf
|
|
|
|
router = APIRouter(prefix="/market", tags=["market"])
|
|
|
|
|
|
@router.get("/{ticker}")
|
|
def get_market_data(ticker: str):
|
|
"""Return current spot price, company name, and daily change for a ticker."""
|
|
try:
|
|
t = yf.Ticker(ticker.upper())
|
|
info = t.fast_info
|
|
spot = info.last_price
|
|
prev = info.previous_close
|
|
if not spot:
|
|
raise HTTPException(status_code=404, detail=f"Ticker '{ticker}' not found.")
|
|
change_pct = round((spot - prev) / prev * 100, 2) if prev else 0.0
|
|
name = getattr(info, "exchange", ticker.upper())
|
|
return {
|
|
"ticker": ticker.upper(),
|
|
"spot": round(float(spot), 2),
|
|
"prev_close": round(float(prev), 2) if prev else None,
|
|
"change_pct": change_pct,
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
|
|
@router.get("/iv-surface/{ticker}")
|
|
def get_iv_surface(ticker: str):
|
|
"""
|
|
Fetch the real implied volatility surface from market option chains.
|
|
Returns strikes, expiries, and IV values for a heatmap.
|
|
"""
|
|
try:
|
|
t = yf.Ticker(ticker.upper())
|
|
expiries = t.options[:6] # Limit to 6 nearest expiries
|
|
if not expiries:
|
|
raise HTTPException(status_code=404, detail="No options data found.")
|
|
|
|
rows = []
|
|
for exp in expiries:
|
|
chain = t.option_chain(exp)
|
|
for _, row in chain.calls.iterrows():
|
|
if row.get("impliedVolatility") and row["impliedVolatility"] > 0:
|
|
rows.append({
|
|
"expiry": exp,
|
|
"strike": float(row["strike"]),
|
|
"iv": round(float(row["impliedVolatility"]), 4),
|
|
"type": "call",
|
|
})
|
|
for _, row in chain.puts.iterrows():
|
|
if row.get("impliedVolatility") and row["impliedVolatility"] > 0:
|
|
rows.append({
|
|
"expiry": exp,
|
|
"strike": float(row["strike"]),
|
|
"iv": round(float(row["impliedVolatility"]), 4),
|
|
"type": "put",
|
|
})
|
|
|
|
spot = float(t.fast_info.last_price)
|
|
return {"ticker": ticker.upper(), "spot": spot, "data": rows}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|