118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
"""每日复盘报告生成"""
|
||
|
||
import logging
|
||
from datetime import datetime
|
||
|
||
from app.config import settings
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
async def generate_review() -> dict:
|
||
"""生成每日复盘报告"""
|
||
if not settings.deepseek_api_key:
|
||
return {"status": "error", "message": "未配置 DeepSeek API Key"}
|
||
|
||
from app.data.tushare_client import tushare_client
|
||
from app.data import tencent_client
|
||
from app.engine.recommender import get_latest_recommendations, get_latest_sectors
|
||
from app.llm.client import get_client
|
||
|
||
trade_date = tushare_client.get_latest_trade_date()
|
||
|
||
# 收集市场数据
|
||
result = await get_latest_recommendations()
|
||
mt = result.get("market_temp")
|
||
sectors = await get_latest_sectors()
|
||
recs = result.get("recommendations", [])
|
||
|
||
# 实时指数
|
||
try:
|
||
index_data = await tencent_client.get_index_realtime()
|
||
except Exception:
|
||
index_data = {}
|
||
|
||
# 构建数据摘要
|
||
market_summary = ""
|
||
if mt:
|
||
market_summary = (
|
||
f"市场温度: {mt.temperature}/100, "
|
||
f"上涨{mt.up_count}家/下跌{mt.down_count}家, "
|
||
f"涨停{mt.limit_up_count}家/跌停{mt.limit_down_count}家, "
|
||
f"连板最高{mt.max_streak}板, 炸板率{mt.broken_rate}%"
|
||
)
|
||
|
||
index_summary = ""
|
||
name_map = {"000001.SH": "上证", "399001.SZ": "深证", "399006.SZ": "创业板"}
|
||
for code in ["000001.SH", "399001.SZ", "399006.SZ"]:
|
||
d = index_data.get(code, {})
|
||
if d:
|
||
index_summary += f"{name_map[code]}: {d.get('price', 0):.2f} ({d.get('pct_chg', 0):+.2f}%), "
|
||
|
||
sector_summary = "热门板块: " + "、".join(
|
||
f"{s.sector_name}({s.pct_change:+.1f}%)" for s in sectors[:5]
|
||
)
|
||
|
||
rec_summary = ""
|
||
for r in recs[:5]:
|
||
signal_map = {"breakout": "突破", "breakout_confirm": "确认", "pullback": "回踩",
|
||
"launch": "启动", "reversal": "反转"}
|
||
st = signal_map.get(r.entry_signal_type, r.entry_signal_type)
|
||
rec_summary += f"\n- {r.name}({r.ts_code}): {st}型, 评分{r.score}, {r.signal}"
|
||
|
||
user_msg = f"""请根据以下数据生成今日A股市场复盘报告(中文):
|
||
|
||
日期: {trade_date}
|
||
{market_summary}
|
||
{index_summary}
|
||
{sector_summary}
|
||
|
||
今日推荐股票:
|
||
{rec_summary}
|
||
|
||
请按以下格式输出(Markdown格式,总字数300-500字):
|
||
## 市场概况
|
||
(指数走势、量能变化)
|
||
|
||
## 板块热点
|
||
(哪些板块领涨、资金流向)
|
||
|
||
## 交易机会
|
||
(今日推荐个股简要点评)
|
||
|
||
## 明日关注
|
||
(关注方向和操作建议)"""
|
||
|
||
try:
|
||
client = get_client()
|
||
response = await client.chat.completions.create(
|
||
model=settings.deepseek_model,
|
||
messages=[
|
||
{"role": "system", "content": "你是一位专业的A股市场分析师,擅长市场复盘和策略分析。回复使用Markdown格式,简洁专业。"},
|
||
{"role": "user", "content": user_msg},
|
||
],
|
||
max_tokens=1500,
|
||
temperature=0.5,
|
||
)
|
||
content = response.choices[0].message.content.strip()
|
||
|
||
# 保存到数据库
|
||
from sqlalchemy import text
|
||
from app.db.database import get_db
|
||
async with get_db() as db:
|
||
await db.execute(
|
||
text(
|
||
"INSERT OR REPLACE INTO daily_reviews (trade_date, content) "
|
||
"VALUES (:td, :content)"
|
||
),
|
||
{"td": trade_date, "content": content},
|
||
)
|
||
await db.commit()
|
||
|
||
logger.info(f"已生成 {trade_date} 复盘报告")
|
||
return {"status": "ok", "trade_date": trade_date, "content": content}
|
||
|
||
except Exception as e:
|
||
logger.error(f"生成复盘报告失败: {e}")
|
||
return {"status": "error", "message": str(e)}
|