From 865db50369e00d67fd492b7f440da3e664c2a1cd Mon Sep 17 00:00:00 2001 From: aaron <> Date: Fri, 17 Apr 2026 14:51:15 +0800 Subject: [PATCH] 1 --- .../recommendations.cpython-313.pyc | Bin 7621 -> 7872 bytes backend/app/api/recommendations.py | 3 + .../db/__pycache__/database.cpython-313.pyc | Bin 3118 -> 3676 bytes backend/app/db/database.py | 12 +- .../__pycache__/recommender.cpython-313.pyc | Bin 27331 -> 27874 bytes .../__pycache__/screener.cpython-313.pyc | Bin 53532 -> 53552 bytes backend/app/engine/recommender.py | 116 +++++++++--------- backend/app/engine/screener.py | 1 + backend/astock.db | Bin 2797568 -> 2797568 bytes frontend/.next/app-build-manifest.json | 27 ++-- frontend/.next/cache/.tsbuildinfo | 2 +- frontend/.next/server/app-paths-manifest.json | 2 +- .../interception-route-rewrite-manifest.js | 2 +- .../server/server-reference-manifest.json | 2 +- frontend/.next/trace | 54 +++++--- frontend/src/app/(auth)/dashboard/page.tsx | 29 ++++- .../src/app/(auth)/recommendations/page.tsx | 78 +----------- 17 files changed, 154 insertions(+), 174 deletions(-) diff --git a/backend/app/api/__pycache__/recommendations.cpython-313.pyc b/backend/app/api/__pycache__/recommendations.cpython-313.pyc index addff3b28939aae477b2aabdad484cd617ceb77c..fc023d392a13b8c230fe3e1d70dda7b855766a19 100644 GIT binary patch delta 990 zcmZ8fU1(Eh82;Y#*K?AbG;NxsX`+kDwCR}BwN{H7scVX!uwL{~Hr9@ipVJ!GCfS=f zws{l15C%gn9|b|_g;(BZyBjR@2T_E!^FoaDVu-MMRhXB%*!!JY82dOp?{nVodEOt+ zSwGu4Z~kqX9!94e|FiUV(TwJw0%J?eX2@)?r3@grQ9{X$GRhR?jAALMB!ouEsFsGB z%hgPWrK4^cXjmTfSYGtHc`f6!Of(a0Mw*N-HbNhCo}xD5U|>c&%u~Y9khtw_DyMiHYiOW+@E?fvDoMt*q_es9FZ?GTfL$%_8lzA6ROU9jNB5r15<4J z2(Nd40bTrA_j%~%p5U+jNoX7MmAR~gSiyEDI)%!@f>SO!n9Ws7bgLDedag9je-9oZ z%j@9u>0qu}JzmTocP&{m&k>uXiP}aTa|I`#D}2-T%vNwASI;`%7us^Ij!B)5^&IoM zx|&Yn1h4jl!#QHL7=5oD)?jax)VA{Jt`gx7dN>&TL@0c0TR-{IAKC0pZhk!4I@Aho zew2PzdNGmzVVl1t}%2BvDz*hQQ z9Pp%Nd1dIrSV~?UgwKYxRhO>~!q~93Hl$L1ZA2y4T1qA5x-6%)=9|zG^gC1*X9dg= zBo!PNydXfVgQrDS!UBI7=~u-Jjpjz=FHoyQZ}Z=xJBPm|RujKw0?!e)y>m`Id!6-rCMWdWio zigsYiA;8_4?r@AvrhRcyRH7^BR6HPaWK{tdU zH;mzCK2VCdQH*vnUmMS;HUCE!^X);oPX)$&-o?C_=>-pg7aGzq?#IWw>2`bD#w)=S z(&U@wx1CQ8Xr7&6OU4om{_AGwc$Tm7F_lNrDyK6bczbISRisO`Tt3-a?qxj3Ps?tx zXKJQZOIsiyTl)?VL*UdlA}`H92TkNwj`oTD|V>mSJ5SaAM z5!5e^+uY=lUzPK+>W)=R)0*fUDyE@+5Ki~8dQX#m;iAy%1BFC!pWX;SF%)Q+TQc&sV~5nq`XUy zGuv>5?q_qnEPa)pW@`s7ONEOH!xEd3tMj<9isjjrxp`cbnFn+)SAZP7&ZX#UZX71* zR7cJ~ry5*^F$J{=)s9Vlab*qF^ky^enI0T2uU@*gJU@!-vPAt!66#H7)HA~vKOBE}}0(hkj%vc=ifNE2QM zBk_V{;2u-Anl5sNa2ijm_qeH zz_s#nmSfRfq-V?lcs^k9@wBd^cqV>8uncJXFM}iq*uuG*kw|FpMo6AaXR#hjsZ;3$>c1Hp&ea|S#=eSvGUbm0KRwKpEAzlhQIsoyM``R1AAaSR&gvN5lenFEtgU*1XiZA^8^u-q^(l z;l=PPZ^x#+^S9BtY44)O@Z#|OaEX)wa~6II;7Xzepv4==FbE}s_DjZYA}uaSE>4VN z`gLm7Uof{Bn>%;S3~}w|2;0o$u9nqR_9T|n#gv}8D#*lsE;M+{ zfV`$_WyE%RiTPRRs$kfy=i%_i%2@(Y@QjxIN#$aiFTH1fW!H zxvGjba{ky0n)BilSZy{rL$$b(fMK2pON>oVcafG(Xi4laQ_hxo`iCuNN;5J@H`EC- z7N;?z$5o^!H64}vh-+v)eIur{o&xNpdYQ1}A{lu$g)ZS9;-jrGmWd!NAlw4}kKpt> zFqQ{n+n{k9oG5ZY^b`bNUhowJe_rsfnO~gM9mLJ>1?YJVJ&$?|-nP8AZEa=)p50~a a&|9(rrl&}?-3s7tG3^!24j-&8bNC4^zULtT delta 460 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 UU(Nn)lNYV0Yf%XCH*06qKh{9M-T(jq delta 815 zcmZXSO=uHA6vy}NZZ^p#X+AceO|nUvG-<1?v8MK94<2X5g9CzgB-jYjQV^yW!9xlb z53Pc6X$8LyJ&52%84yGeFA5?SZ)y=lyeM9*If$N|oh7NzIlcFO@9Y1VN1Mu>O(oO~ zg>;F(nb?>4?M^5IbDdhTtzy86^GotyuvSq(NbOtq>ZZ z11LiBO(G*J4G|JFSQ6g}n;jH04`^`1IO|nzq zx-^GJuuk$gK+J}UgM-q7x&X9*L!?Ly4^I+wfRuPfk(f@T;lp7kj}DoVDdABZ=@A?y zvHvP#q>Ou&2~iou2Cr;8BPuvfOy0E2$0kI(Vd2R*DZDC9@wIl>2#|b3!)d{4dsvyX zj9?>s*eGX%f{nSX-PaZ%4$KO;59j&|vGmnaY;lb_!Y)P zwIgYW#IZc?<(KPe&kOB3E<4#=`jG>;!Vk5Z=nl^F!w!pvb#a?&zmcoGCfGrCL*6l< z!d8;q9CX;lLw~BUYSYu-V2#bre)PbyJ$3d6JY=Q0-x^G_%>30XJZ1M+76WjM8P^v9 zX4rD)yrNxFBx$K?Z*633ZT$mWwm+|bhc)~4#$T|xU0`2t9+%-Zo4i$5;ECP3`wL#O zllQuQc*oF#XFiBA?QuN}N7?j?D;gYT&tIL<^vP{+vw7}9tJ!1|Z&xAriGMZcw=K0~ WN&2Y(z>XXRwOf@S%-(OElK%lA3B8&C diff --git a/backend/app/engine/recommender.py b/backend/app/engine/recommender.py index c90bdc9e..74020cb9 100644 --- a/backend/app/engine/recommender.py +++ b/backend/app/engine/recommender.py @@ -39,7 +39,7 @@ async def refresh_recommendations(trade_date: str = None, scan_session: str = "m rec.scan_session = scan_session rec.created_at = datetime.now() - # 持久化到数据库 + # 持久化到数据库(这是 async 操作,需要在主线程中执行) await _save_to_db(result) # 更新历史推荐跟踪(检查之前推荐的后续表现) @@ -392,73 +392,79 @@ async def _save_to_db(result: dict): "temp": mt.temperature, }) - # 保存板块热度(先清除同一 trade_date 的旧数据,避免重复) + # 保存板块热度(先清除同一 trade_date 的旧数据,再批量插入) trade_date_val = mt.trade_date if mt else "" if trade_date_val: await db.execute( text("DELETE FROM sector_heat WHERE trade_date = :td"), {"td": trade_date_val}, ) - for sector in result.get("hot_sectors", []): - stmt = tables.sector_heat_table.insert().values( - sector_code=sector.sector_code, - sector_name=sector.sector_name, - pct_change=sector.pct_change, - capital_inflow=sector.capital_inflow, - limit_up_count=sector.limit_up_count, - heat_score=sector.heat_score, - stage=sector.stage, - days_continuous=sector.days_continuous, - member_count=sector.member_count, - leading_stocks=json.dumps(sector.leading_stocks, ensure_ascii=False), - pct_trend=json.dumps(sector.pct_trend, ensure_ascii=False), - turnover_avg=sector.turnover_avg, - main_force_ratio=sector.main_force_ratio, - trade_date=trade_date_val, - ) - await db.execute(stmt) + sector_values = [ + { + "sector_code": sector.sector_code, + "sector_name": sector.sector_name, + "pct_change": sector.pct_change, + "capital_inflow": sector.capital_inflow, + "limit_up_count": sector.limit_up_count, + "heat_score": sector.heat_score, + "stage": sector.stage, + "days_continuous": sector.days_continuous, + "member_count": sector.member_count, + "leading_stocks": json.dumps(sector.leading_stocks, ensure_ascii=False), + "pct_trend": json.dumps(sector.pct_trend, ensure_ascii=False), + "turnover_avg": sector.turnover_avg, + "main_force_ratio": sector.main_force_ratio, + "trade_date": trade_date_val, + } + for sector in result.get("hot_sectors", []) + ] + if sector_values: + await db.execute(tables.sector_heat_table.insert(), sector_values) - # 保存推荐(按 ts_code 清除当日旧记录,避免同一天多次扫描产生重复) + # 保存推荐:先批量清除当日旧记录,再批量插入 today_str = datetime.now().strftime("%Y-%m-%d") now_dt = datetime.now() - saved_count = 0 - for rec in result.get("recommendations", []): - if rec.score < 60: - continue + qualified_recs = [rec for rec in result.get("recommendations", []) if rec.score >= 60] + if qualified_recs: + # 批量删除当日同一 ts_code 的旧记录 + codes = [rec.ts_code for rec in qualified_recs] await db.execute( - text("DELETE FROM recommendations WHERE date(created_at) = :today AND ts_code = :code"), - {"today": today_str, "code": rec.ts_code}, + text("DELETE FROM recommendations WHERE date(created_at) = :today AND ts_code IN :codes"), + {"today": today_str, "codes": tuple(codes)}, ) - stmt = tables.recommendations_table.insert().values( - ts_code=rec.ts_code, - name=rec.name, - sector=rec.sector, - score=rec.score, - market_temp_score=rec.market_temp_score, - sector_score=rec.sector_score, - capital_score=rec.capital_score, - technical_score=rec.technical_score, - supply_demand_score=rec.supply_demand_score, - price_action_score=rec.price_action_score, - position_score=rec.position_score, - valuation_score=rec.valuation_score, - signal=rec.signal, - entry_price=rec.entry_price, - target_price=rec.target_price, - stop_loss=rec.stop_loss, - reasons=json.dumps(rec.reasons, ensure_ascii=False), - llm_analysis=rec.llm_analysis, - strategy=rec.strategy, - entry_signal_type=rec.entry_signal_type, - llm_score=rec.llm_score, - scan_session=rec.scan_session, - created_at=now_dt, - ) - await db.execute(stmt) - saved_count += 1 + # 批量插入新记录 + rec_values = [ + { + "ts_code": rec.ts_code, + "name": rec.name, + "sector": rec.sector, + "score": rec.score, + "market_temp_score": rec.market_temp_score, + "sector_score": rec.sector_score, + "capital_score": rec.capital_score, + "technical_score": rec.technical_score, + "supply_demand_score": rec.supply_demand_score, + "price_action_score": rec.price_action_score, + "position_score": rec.position_score, + "valuation_score": rec.valuation_score, + "signal": rec.signal, + "entry_price": rec.entry_price, + "target_price": rec.target_price, + "stop_loss": rec.stop_loss, + "reasons": json.dumps(rec.reasons, ensure_ascii=False), + "llm_analysis": rec.llm_analysis, + "strategy": rec.strategy, + "entry_signal_type": rec.entry_signal_type, + "llm_score": rec.llm_score, + "scan_session": rec.scan_session, + "created_at": now_dt, + } + for rec in qualified_recs + ] + await db.execute(tables.recommendations_table.insert(), rec_values) await db.commit() - logger.info(f"已保存 {saved_count} 条推荐到数据库(共 {len(result.get('recommendations', []))} 条,过滤掉 <60 分)") + logger.info(f"已保存 {len(qualified_recs)} 条推荐到数据库(共 {len(result.get('recommendations', []))} 条,过滤掉 <60 分)") except Exception as e: logger.error(f"保存推荐到数据库失败: {e}") from app.db.error_logger import log_error diff --git a/backend/app/engine/screener.py b/backend/app/engine/screener.py index 07a674e5..4574617e 100644 --- a/backend/app/engine/screener.py +++ b/backend/app/engine/screener.py @@ -17,6 +17,7 @@ 止损止盈:基于市场结构(阻力位/支撑MA/近期低点),而非固定百分比。 """ +import asyncio import logging import traceback diff --git a/backend/astock.db b/backend/astock.db index 7540a625b4afd8c3065ecbfef28bbe98b906e60e..e1b0e525962f0e3898fb281cbab82a9262757557 100644 GIT binary patch delta 226104 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 delta 35593 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 @@ -29,6 +31,7 @@ export default function DashboardPage() { const [indices, setIndices] = useState([]); const [dailyReview, setDailyReview] = useState(null); const [generatingReview, setGeneratingReview] = useState(false); + const scanTimeoutRef = useRef | null>(null); const loadData = useCallback(async () => { try { @@ -55,12 +58,21 @@ export default function DashboardPage() { } }, []); + // 清除扫描超时计时器 + const clearScanTimeout = useCallback(() => { + if (scanTimeoutRef.current) { + clearTimeout(scanTimeoutRef.current); + scanTimeoutRef.current = null; + } + }, []); + useEffect(() => { loadData(); }, [loadData]); useWebSocket( useCallback((msg: { type: string; count?: number; scan_mode?: string; message?: string }) => { + clearScanTimeout(); if (msg.type === "scan_update") { const modeLabel = msg.scan_mode === "intraday" ? "盘中实时" : "盘后"; setRefreshResult(`${modeLabel}扫描完成,发现 ${msg.count ?? 0} 只股票`); @@ -75,7 +87,7 @@ export default function DashboardPage() { // 其他消息类型(如 llm_analysis_ready),刷新数据 loadData(); } - }, [loadData]), + }, [loadData, clearScanTimeout]), ["scan_update", "scan_error", "llm_analysis_ready", "sector_scan_ready", "scan_complete"] ); @@ -96,6 +108,14 @@ export default function DashboardPage() { setRefreshResult("扫描已启动,完成后自动刷新..."); // 保持 refreshing,等待 WS 推送 } + + // 设置超时:如果 120 秒内没收到 WebSocket 消息,自动停止加载状态并刷新数据 + scanTimeoutRef.current = setTimeout(() => { + setRefreshResult("扫描超时,已自动刷新数据"); + setRefreshing(false); + loadData(); + setTimeout(() => setRefreshResult(null), 5000); + }, SCAN_TIMEOUT_MS); } catch (e) { console.error("触发扫描失败:", e); setRefreshResult("触发扫描失败,请重试"); @@ -104,6 +124,11 @@ export default function DashboardPage() { } }; + // 清理超时计时器 + useEffect(() => { + return () => clearScanTimeout(); + }, [clearScanTimeout]); + if (loading) { return (
diff --git a/frontend/src/app/(auth)/recommendations/page.tsx b/frontend/src/app/(auth)/recommendations/page.tsx index f4e0cb2c..3ae6c260 100644 --- a/frontend/src/app/(auth)/recommendations/page.tsx +++ b/frontend/src/app/(auth)/recommendations/page.tsx @@ -1,10 +1,9 @@ "use client"; import { useEffect, useState, useCallback } from "react"; -import { fetchAPI, postAPI } from "@/lib/api"; +import { fetchAPI } from "@/lib/api"; import type { DayGroup, PerformanceStats } from "@/lib/api"; import StockCard from "@/components/stock-card"; -import { useWebSocket } from "@/hooks/use-websocket"; function formatDate(dateStr: string): string { const d = new Date(dateStr); @@ -23,20 +22,15 @@ export default function RecommendationsPage() { const [dayGroups, setDayGroups] = useState([]); const [expandedDays, setExpandedDays] = useState>(new Set()); const [filter, setFilter] = useState("all"); - const [llmEnabled, setLlmEnabled] = useState(false); - const [refreshing, setRefreshing] = useState(false); - const [refreshResult, setRefreshResult] = useState(null); const [performance, setPerformance] = useState(null); const loadData = useCallback(async () => { try { - const [history, health, perf] = await Promise.all([ + const [history, perf] = await Promise.all([ fetchAPI("/api/recommendations/history?days=14"), - fetchAPI<{ llm_enabled: boolean }>("/api/health"), fetchAPI("/api/recommendations/performance").catch(() => null), ]); setDayGroups(history); - setLlmEnabled(health.llm_enabled); setPerformance(perf); // 默认展开最近一天 @@ -56,50 +50,6 @@ export default function RecommendationsPage() { loadData(); }, [loadData]); - // WebSocket 监听扫描结果 - useWebSocket( - useCallback((data: { type: string; session?: string; count?: number; temperature?: number; scan_mode?: string; message?: string }) => { - if (data.type === "scan_update") { - const modeLabel = data.scan_mode === "intraday" ? "盘中实时" : "盘后"; - setRefreshResult(`${modeLabel}扫描完成,发现 ${data.count ?? 0} 只股票`); - setRefreshing(false); - loadData(); - setTimeout(() => setRefreshResult(null), 5000); - } else if (data.type === "scan_error") { - setRefreshResult("扫描失败,请重试"); - setRefreshing(false); - setTimeout(() => setRefreshResult(null), 5000); - } - }, [loadData]), - ["scan_update", "scan_error"] - ); - - const handleRefresh = async () => { - setRefreshing(true); - setRefreshResult(null); - try { - const res = await postAPI<{ - status: string; - message?: string; - is_trading: boolean; - }>("/api/recommendations/refresh?scan_session=manual"); - - if (res.status === "already_running") { - setRefreshResult(res.message || "扫描正在执行中,请稍候"); - setTimeout(() => setRefreshResult(null), 5000); - // 不关闭 refreshing,等待 WS 推送完成通知 - } else if (res.status === "scanning") { - setRefreshResult("扫描已启动,完成后自动刷新..."); - // 保持 refreshing 状态,等待 WS 推送 - } - } catch (e) { - console.error("触发扫描失败:", e); - setRefreshResult("触发扫描失败,请重试"); - setRefreshing(false); - setTimeout(() => setRefreshResult(null), 5000); - } - }; - const toggleDay = (date: string) => { setExpandedDays((prev) => { const next = new Set(prev); @@ -135,30 +85,8 @@ export default function RecommendationsPage() { {dayGroups.length} 天记录

- - {/* Scan result toast */} - {refreshResult && ( -
- - {refreshResult} -
- )} - {/* Performance Stats */} {performance && performance.total_recommendations > 0 && (
@@ -316,7 +244,7 @@ export default function RecommendationsPage() { className="animate-fade-in-up" style={{ animationDelay: `${i * 40}ms` }} > - +
))}