feat(frontend): 添加交易看板,统一时区为CST

refactor(db): 移除所有SQLite相关代码,迁移至MySQL
This commit is contained in:
crypto_predictor committed 2026-02-07 16:48:14 +08:00
1 parent 5e0d6b18ef
commit 55453d3739
12 files changed
+2116 -501

No files matched your search

+191
View File
@@ -0,0 +1,191 @@
"""
FastAPI 主应用 - 交易看板 API
"""
import os
import sys
from datetime import datetime
from typing import Optional
from zoneinfo import ZoneInfo
from fastapi import FastAPI, Query, HTTPException
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
# 添加项目路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from api.models import TradeModel, PredictionModel
from api.prediction_service import get_prediction_service
# 创建 FastAPI 应用
app = FastAPI(
title="Crypto Predictor Dashboard API",
description="BTC 预测交易看板 API",
version="1.0.0"
)
# 启用 CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 静态文件目录
STATIC_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
# 挂载静态文件
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
# ==================== 页面路由 ====================
@app.get("/")
async def index():
"""返回主页"""
return FileResponse(os.path.join(STATIC_DIR, 'index.html'))
# ==================== 交易 API ====================
@app.get("/api/trades/current")
async def get_current_trade():
"""获取当前/最新交易"""
try:
trade = TradeModel.get_current_trade()
if trade:
return {"success": True, "data": trade}
return {"success": True, "data": None, "message": "暂无交易记录"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/trades/history")
async def get_trade_history(
page: int = Query(1, ge=1, description="页码"),
limit: int = Query(10, ge=1, le=100, description="每页条数"),
month: Optional[str] = Query(None, description="月份筛选 (YYYY-MM)"),
day: Optional[str] = Query(None, description="日期筛选 (YYYY-MM-DD)")
):
"""获取历史交易记录"""
try:
result = TradeModel.get_history(page=page, limit=limit, month=month, day=day)
return {"success": True, **result}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 准确率 API ====================
@app.get("/api/accuracy/current")
async def get_current_prediction():
"""获取当前小时的预测"""
try:
service = get_prediction_service()
prediction = service.predict_current_hour()
return {"success": True, "data": prediction}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/accuracy/monthly")
async def get_monthly_accuracy(
month: Optional[str] = Query(None, description="月份 (YYYY-MM),默认当月")
):
"""获取月度准确率统计"""
try:
# 默认当月
if not month:
et_tz = ZoneInfo('America/New_York')
month = datetime.now(et_tz).strftime('%Y-%m')
# 确保有数据
service = get_prediction_service()
service.ensure_predictions_for_month(month)
# 获取统计
stats = PredictionModel.get_monthly_stats(month)
return {
"success": True,
"month": month,
"data": stats
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/accuracy/daily")
async def get_daily_accuracy(
month: Optional[str] = Query(None, description="月份 (YYYY-MM),默认当月"),
page: int = Query(1, ge=1, description="页码"),
limit: int = Query(10, ge=1, le=100, description="每页条数")
):
"""获取每日准确率统计"""
try:
# 默认当月
if not month:
et_tz = ZoneInfo('America/New_York')
month = datetime.now(et_tz).strftime('%Y-%m')
# 确保有数据
service = get_prediction_service()
service.ensure_predictions_for_month(month)
# 获取统计
result = PredictionModel.get_daily_stats(month=month, page=page, limit=limit)
return {
"success": True,
"month": month,
**result
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/accuracy/hourly/{date}")
async def get_hourly_accuracy(date: str):
"""获取指定日期的每小时准确率详情"""
try:
# 确保有数据
service = get_prediction_service()
service.ensure_predictions_for_date(date)
# 获取详情
details = PredictionModel.get_hourly_details(date)
return {
"success": True,
"date": date,
"data": details
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 状态 API ====================
@app.get("/api/status")
async def get_status():
"""获取服务状态"""
et_tz = ZoneInfo('America/New_York')
now_et = datetime.now(et_tz)
return {
"success": True,
"status": "running",
"server_time": datetime.now().isoformat(),
"server_time_et": now_et.isoformat(),
"version": "1.0.0"
}
# ==================== 启动入口 ====================
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)