Initial commit: stock market platform

This commit is contained in:
admin
2026-06-11 01:41:47 +08:00
commit 63718906e9
62 changed files with 8962 additions and 0 deletions

89
backend/app/main.py Normal file
View File

@@ -0,0 +1,89 @@
import asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends
from fastapi.middleware.cors import CORSMiddleware
from loguru import logger
from app.core.config import settings
from app.core.database import init_db
from app.core.redis import close_redis
from app.api.v1 import api_router
from app.websocket.manager import manager
from app.services import stock_service
from app.api.deps import get_current_user
# ── background task: push heatmap every 5s ───────────────────────────────────
async def _heatmap_pusher():
while True:
try:
data = await stock_service.get_all_stocks_spot()
await manager.broadcast_all(data)
except Exception as e:
logger.warning(f"heatmap pusher error: {e}")
await asyncio.sleep(5)
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("Starting up...")
await init_db()
task = asyncio.create_task(_heatmap_pusher())
yield
task.cancel()
await close_redis()
logger.info("Shut down.")
# ── app ───────────────────────────────────────────────────────────────────────
app = FastAPI(
title=settings.APP_NAME,
docs_url="/api/docs",
redoc_url="/api/redoc",
openapi_url="/api/openapi.json",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(api_router, prefix=settings.API_V1_PREFIX)
# ── WebSocket endpoints ───────────────────────────────────────────────────────
@app.websocket("/ws/heatmap")
async def ws_heatmap(websocket: WebSocket):
"""Subscribe to full market heatmap updates."""
await manager.connect(websocket)
try:
while True:
await websocket.receive_text()
except WebSocketDisconnect:
manager.disconnect(websocket)
@app.websocket("/ws/quote/{symbol}")
async def ws_quote(websocket: WebSocket, symbol: str):
"""Subscribe to real-time quote updates for a single stock."""
await manager.connect(websocket, symbol)
try:
while True:
await asyncio.sleep(3)
data = await stock_service.get_stock_quote(symbol)
if data:
await manager.broadcast_quote(symbol, data)
except WebSocketDisconnect:
manager.disconnect(websocket, symbol)
@app.get("/api/health")
async def health():
return {"status": "ok"}