mirror of
https://github.com/shawnkim1997/All-in-one-Financial-Analysis.git
synced 2026-08-21 06:38:05 +00:00
Complete migration from Streamlit to Next.js 14 App Router + FastAPI backend. Frontend (Next.js 14): - 10 pages: Overview, Research, Valuation, Technical, Markets, Earnings, News, Portfolio, Filings, Settings - Terminal Noir dark theme with custom Tailwind config - TradingView Lightweight Charts for candlestick/volume - Valuation: DCF, Sensitivity Matrix, Monte Carlo, Tornado, Reverse DCF - Financial Statements table with YoY growth badges and margin rows - SEC EDGAR inline filing viewer with section tabs - News split-view with iframe article embedding - Technical Analysis with RSI, MACD, Bollinger, Fibonacci, Moving Averages - Earnings beat/miss visualization - AI Copilot chat panel with Gemini integration Backend (FastAPI): - 13 routers: market_data, financials, valuation, technical, earnings, insider, edgar, news, portfolio, analysis, chat, estimates, fx - Services: DCF engine, Monte Carlo simulation, sensitivity analysis, risk metrics, SEC parser, technical indicators - yfinance + yahooquery data sources with fallback pattern - SQLite caching layer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
159 lines
4.6 KiB
Python
159 lines
4.6 KiB
Python
"""Crypto price fetcher -- Bithumb (KRW) and Binance (USD) public APIs.
|
|
|
|
Provides standalone fetcher functions that can be used by the crypto router
|
|
or any other service that needs cryptocurrency price data.
|
|
"""
|
|
|
|
import time
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
import requests
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Top 20 coins
|
|
# ---------------------------------------------------------------------------
|
|
|
|
TOP_20_COINS: List[str] = [
|
|
"BTC", "ETH", "BNB", "XRP", "SOL", "ADA", "DOGE", "AVAX", "DOT", "MATIC",
|
|
"LINK", "SHIB", "TRX", "UNI", "ATOM", "LTC", "ETC", "XLM", "NEAR", "APT",
|
|
]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# In-memory cache
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_cache: Dict[str, Any] = {}
|
|
_cache_ts: Dict[str, float] = {}
|
|
_CACHE_TTL = 30 # seconds
|
|
|
|
|
|
def _get_cached(key: str) -> Optional[Any]:
|
|
if key in _cache and (time.time() - _cache_ts.get(key, 0)) < _CACHE_TTL:
|
|
return _cache[key]
|
|
return None
|
|
|
|
|
|
def _set_cached(key: str, value: Any) -> None:
|
|
_cache[key] = value
|
|
_cache_ts[key] = time.time()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Bithumb (KRW)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def fetch_bithumb_all_krw(symbols: Optional[List[str]] = None) -> Dict[str, float]:
|
|
"""Fetch KRW prices from Bithumb ALL_KRW endpoint.
|
|
|
|
Uses the bulk endpoint (https://api.bithumb.com/public/ticker/ALL_KRW)
|
|
to avoid per-symbol rate limits.
|
|
|
|
Parameters
|
|
----------
|
|
symbols:
|
|
Coin symbols to include. Defaults to TOP_20_COINS.
|
|
|
|
Returns
|
|
-------
|
|
dict
|
|
Mapping of symbol -> KRW price (float).
|
|
"""
|
|
cached = _get_cached("bithumb_all_krw")
|
|
if cached is not None:
|
|
return cached
|
|
|
|
symbols = symbols or TOP_20_COINS
|
|
url = "https://api.bithumb.com/public/ticker/ALL_KRW"
|
|
prices: Dict[str, float] = {}
|
|
try:
|
|
resp = requests.get(url, timeout=10)
|
|
resp.raise_for_status()
|
|
body = resp.json()
|
|
if body.get("status") != "0000":
|
|
return prices
|
|
data = body.get("data", {})
|
|
for sym in symbols:
|
|
coin_data = data.get(sym.upper())
|
|
if coin_data and isinstance(coin_data, dict):
|
|
closing = coin_data.get("closing_price")
|
|
if closing:
|
|
prices[sym.upper()] = float(closing)
|
|
except Exception:
|
|
pass
|
|
|
|
_set_cached("bithumb_all_krw", prices)
|
|
return prices
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Binance (USD)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def fetch_binance_prices(symbols: Optional[List[str]] = None) -> Dict[str, float]:
|
|
"""Fetch USD prices from Binance ticker/price endpoint.
|
|
|
|
Parameters
|
|
----------
|
|
symbols:
|
|
Coin symbols to include. Defaults to TOP_20_COINS.
|
|
|
|
Returns
|
|
-------
|
|
dict
|
|
Mapping of symbol -> USD price (float).
|
|
"""
|
|
cached = _get_cached("binance_prices")
|
|
if cached is not None:
|
|
return cached
|
|
|
|
symbols = symbols or TOP_20_COINS
|
|
url = "https://api.binance.com/api/v3/ticker/price"
|
|
prices: Dict[str, float] = {}
|
|
try:
|
|
resp = requests.get(url, timeout=10)
|
|
resp.raise_for_status()
|
|
data = resp.json()
|
|
lookup = {item["symbol"]: float(item["price"]) for item in data}
|
|
for sym in symbols:
|
|
key = f"{sym.upper()}USDT"
|
|
if key in lookup:
|
|
prices[sym.upper()] = lookup[key]
|
|
except Exception:
|
|
pass
|
|
|
|
_set_cached("binance_prices", prices)
|
|
return prices
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Combined
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def fetch_top20_prices(
|
|
symbols: Optional[List[str]] = None,
|
|
) -> List[Dict[str, Any]]:
|
|
"""Return top-20 crypto prices with both KRW and USD.
|
|
|
|
Each entry contains:
|
|
- symbol: str
|
|
- price_usd: float | None
|
|
- price_krw: float | None
|
|
|
|
Parameters
|
|
----------
|
|
symbols:
|
|
Override default TOP_20_COINS list.
|
|
"""
|
|
symbols = symbols or TOP_20_COINS
|
|
usd = fetch_binance_prices(symbols)
|
|
krw = fetch_bithumb_all_krw(symbols)
|
|
|
|
results: List[Dict[str, Any]] = []
|
|
for sym in symbols:
|
|
results.append({
|
|
"symbol": sym.upper(),
|
|
"price_usd": usd.get(sym.upper()),
|
|
"price_krw": krw.get(sym.upper()),
|
|
})
|
|
return results
|