astock-agent/backend/app/api/recommendations.py
2026-04-15 23:32:22 +08:00

102 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""推荐列表 API"""
from fastapi import APIRouter
from app.engine.recommender import (
refresh_recommendations,
get_latest_recommendations,
get_recommendation_history,
get_performance_stats,
)
from app.config import is_trading_hours
router = APIRouter(prefix="/api/recommendations", tags=["recommendations"])
@router.get("/latest")
async def get_latest():
"""获取最新推荐列表"""
result = await get_latest_recommendations()
mt = result.get("market_temp")
return {
"market_temperature": {
"trade_date": mt.trade_date if mt else "",
"temperature": mt.temperature if mt else 0,
"up_count": mt.up_count if mt else 0,
"down_count": mt.down_count if mt else 0,
"limit_up_count": mt.limit_up_count if mt else 0,
"limit_down_count": mt.limit_down_count if mt else 0,
"max_streak": mt.max_streak if mt else 0,
"broken_rate": mt.broken_rate if mt else 0,
"index_above_ma20": mt.index_above_ma20 if mt else False,
} if mt else None,
"recommendations": [
{
"ts_code": r.ts_code,
"name": r.name,
"sector": r.sector,
"score": r.score,
"level": r.level,
"signal": r.signal,
"market_temp_score": r.market_temp_score,
"sector_score": r.sector_score,
"capital_score": r.capital_score,
"technical_score": r.technical_score,
"position_score": r.position_score,
"valuation_score": r.valuation_score,
"entry_price": r.entry_price,
"target_price": r.target_price,
"stop_loss": r.stop_loss,
"reasons": r.reasons,
"risk_note": r.risk_note,
"llm_analysis": r.llm_analysis,
"entry_timing": r.entry_timing,
"llm_score": r.llm_score,
"strategy": r.strategy,
"entry_signal_type": r.entry_signal_type,
"scan_session": r.scan_session,
"created_at": r.created_at.isoformat() if r.created_at else None,
}
for r in result.get("recommendations", [])
],
"scan_mode": result.get("scan_mode", "unknown"),
}
@router.post("/refresh")
async def refresh(scan_session: str = "manual"):
"""手动触发一次全量筛选"""
result = await refresh_recommendations(scan_session=scan_session)
rec_count = len(result.get("recommendations", []))
mt = result.get("market_temp")
return {
"status": "ok",
"count": rec_count,
"temperature": mt.temperature if mt else 0,
"scan_mode": result.get("scan_mode", "unknown"),
"is_trading": is_trading_hours(),
}
@router.get("/status")
async def get_scan_status():
"""获取当前扫描状态信息"""
return {
"is_trading": is_trading_hours(),
"scan_mode": "intraday" if is_trading_hours() else "post_market",
"description": "盘中实时扫描(腾讯行情)" if is_trading_hours() else "盘后分析Tushare日级数据",
}
@router.get("/history")
async def get_history(days: int = 7):
"""获取历史推荐(按日期分组)"""
return await get_recommendation_history(days)
@router.get("/performance")
async def performance():
"""获取推荐胜率统计"""
return await get_performance_stats()