Initial commit: stock market platform
This commit is contained in:
133
backend/app/api/v1/stocks.py
Normal file
133
backend/app/api/v1/stocks.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import json
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from app.api.deps import get_current_user
|
||||
from app.models.user import User
|
||||
from app.core.redis import get_redis
|
||||
from app.services import stock_service
|
||||
|
||||
router = APIRouter(prefix="/stocks", tags=["stocks"])
|
||||
|
||||
CACHE_TTL = 30 # seconds
|
||||
|
||||
|
||||
# ── market overview ───────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/market/overview")
|
||||
async def market_overview(current_user: User = Depends(get_current_user)):
|
||||
redis = await get_redis()
|
||||
cache_key = "market:overview"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_market_overview()
|
||||
await redis.setex(cache_key, CACHE_TTL, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
# ── heatmap ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/market/heatmap")
|
||||
async def market_heatmap(current_user: User = Depends(get_current_user)):
|
||||
redis = await get_redis()
|
||||
cache_key = "market:heatmap"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_all_stocks_spot()
|
||||
await redis.setex(cache_key, CACHE_TTL, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
# ── sector ────────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/market/sectors")
|
||||
async def market_sectors(current_user: User = Depends(get_current_user)):
|
||||
redis = await get_redis()
|
||||
cache_key = "market:sectors"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_sector_spot()
|
||||
await redis.setex(cache_key, CACHE_TTL, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
# ── single stock quote ────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/{symbol}/quote")
|
||||
async def stock_quote(symbol: str, current_user: User = Depends(get_current_user)):
|
||||
redis = await get_redis()
|
||||
cache_key = f"quote:{symbol}"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_stock_quote(symbol)
|
||||
if data:
|
||||
await redis.setex(cache_key, CACHE_TTL, json.dumps(data))
|
||||
return data or {}
|
||||
|
||||
|
||||
# ── K-line ────────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/{symbol}/kline")
|
||||
async def stock_kline(
|
||||
symbol: str,
|
||||
period: str = Query("daily", pattern="^(daily|weekly|monthly)$"),
|
||||
adjust: str = Query("qfq", pattern="^(qfq|hfq|)$"),
|
||||
limit: int = Query(250, ge=10, le=1000),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
redis = await get_redis()
|
||||
cache_key = f"kline:{symbol}:{period}:{adjust}:{limit}"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_kline(symbol, period, adjust, limit)
|
||||
await redis.setex(cache_key, 300, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
# ── intraday ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/{symbol}/intraday")
|
||||
async def stock_intraday(symbol: str, current_user: User = Depends(get_current_user)):
|
||||
redis = await get_redis()
|
||||
cache_key = f"intraday:{symbol}"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_intraday(symbol)
|
||||
await redis.setex(cache_key, CACHE_TTL, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
# ── 5-day ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/{symbol}/fiveday")
|
||||
async def stock_fiveday(symbol: str, current_user: User = Depends(get_current_user)):
|
||||
redis = await get_redis()
|
||||
cache_key = f"fiveday:{symbol}"
|
||||
cached = await redis.get(cache_key)
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
|
||||
data = await stock_service.get_five_day(symbol)
|
||||
await redis.setex(cache_key, CACHE_TTL, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
# ── search ────────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/search")
|
||||
async def search(
|
||||
q: str = Query(..., min_length=1),
|
||||
limit: int = Query(20, ge=1, le=50),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
return await stock_service.search_stocks(q, limit)
|
||||
Reference in New Issue
Block a user