astock-agent/backend/app/api/market.py
2026-04-15 08:58:21 +08:00

133 lines
4.0 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.data.tushare_client import tushare_client
from app.data import tencent_client
from app.engine.recommender import get_latest_recommendations
from app.config import is_trading_hours, is_market_session
router = APIRouter(prefix="/api/market", tags=["market"])
@router.get("/temperature")
async def get_temperature():
"""获取市场温度(只读缓存,不触发扫描)"""
result = await get_latest_recommendations()
mt = result.get("market_temp")
if mt:
return {
"trade_date": mt.trade_date,
"temperature": mt.temperature,
"up_count": mt.up_count,
"down_count": mt.down_count,
"limit_up_count": mt.limit_up_count,
"limit_down_count": mt.limit_down_count,
"max_streak": mt.max_streak,
"broken_rate": mt.broken_rate,
"index_above_ma20": getattr(mt, "index_above_ma20", False),
"is_trading": is_trading_hours(),
}
return {
"trade_date": "",
"temperature": 0,
"up_count": 0,
"down_count": 0,
"limit_up_count": 0,
"limit_down_count": 0,
"max_streak": 0,
"broken_rate": 0,
"index_above_ma20": False,
"is_trading": is_trading_hours(),
}
@router.get("/overview")
async def get_overview():
"""市场概况:上证、深证、创业板指数
盘中用腾讯实时行情,盘后用 Tushare 日线(有缓存)。
"""
if is_market_session():
return await _overview_realtime()
return _overview_daily()
@router.get("/daily-review")
async def get_daily_review():
"""获取每日复盘报告"""
from sqlalchemy import text
from app.db.database import get_db
async with get_db() as db:
result = await db.execute(
text("SELECT * FROM daily_reviews ORDER BY trade_date DESC LIMIT 5")
)
reviews = []
for row in result.fetchall():
r = row._mapping
reviews.append({
"trade_date": r["trade_date"],
"content": r["content"] or "",
"created_at": str(r["created_at"]) if r["created_at"] else "",
})
return {"reviews": reviews}
@router.post("/generate-review")
async def generate_daily_review():
"""手动触发生成每日复盘"""
from app.llm.daily_review import generate_review
result = await generate_review()
return result
async def _overview_realtime():
"""盘中:腾讯实时指数行情"""
index_data = await tencent_client.get_index_realtime()
result = []
name_map = {
"000001.SH": "上证指数",
"399001.SZ": "深证成指",
"399006.SZ": "创业板指",
}
for code in ["000001.SH", "399001.SZ", "399006.SZ"]:
data = index_data.get(code)
if not data:
continue
result.append({
"name": name_map.get(code, data.get("name", code)),
"code": code,
"close": round(data["price"], 2),
"pct_chg": round(data["pct_chg"], 2),
"volume": round(data["volume"], 2),
"realtime": True,
})
return result
def _overview_daily():
"""盘后Tushare 日线数据"""
indices = {
"上证指数": "000001.SH",
"深证成指": "399001.SZ",
"创业板指": "399006.SZ",
}
result = []
for name, code in indices.items():
df = tushare_client.get_index_daily(code, days=5)
if df.empty:
continue
df = df.sort_values("trade_date")
latest = df.iloc[-1]
prev = df.iloc[-2] if len(df) > 1 else latest
pct = (latest["close"] - prev["close"]) / prev["close"] * 100
result.append({
"name": name,
"code": code,
"close": round(float(latest["close"]), 2),
"pct_chg": round(pct, 2),
"volume": round(float(latest["vol"]), 2),
"realtime": False,
})
return result