diff --git a/backend/services/tencent.py b/backend/services/tencent.py index 9266b09..098424e 100644 --- a/backend/services/tencent.py +++ b/backend/services/tencent.py @@ -142,10 +142,11 @@ async def fetch_quote(code: str) -> Optional[dict]: return None text = resp.content.decode("gbk", errors="replace") parts = parse_tencent_data(text) - if not parts or len(parts) < 38: + if not parts or len(parts) < 46: return None - # 字段索引(1-based):1=名称, 3=当前价, 4=昨收, 5=今开, 6=成交量(手) + # 字段索引:1=名称, 3=当前价, 4=昨收, 5=今开, 6=成交量(手) # 7=外盘, 8=内盘, 31=涨跌额, 32=涨跌幅%, 33=最高, 34=最低, 37=成交额(万) + # 38=换手率%, 39=市盈率, 43=总市值, 44=流通市值, 45=市净率 name = parts[1] or "" current_price = float(parts[3]) if parts[3] else 0 yesterday_close = float(parts[4]) if parts[4] else 0 @@ -158,6 +159,11 @@ async def fetch_quote(code: str) -> Optional[dict]: change_pct = float(parts[32]) if parts[32] else 0 outer_disk = float(parts[7]) if parts[7] else 0 inner_disk = float(parts[8]) if parts[8] else 0 + turnover_rate = float(parts[38]) if parts[38] else 0 # 换手率% + pe = float(parts[39]) if parts[39] else 0 # 市盈率 + total_market_cap = float(parts[43]) if parts[43] else 0 # 总市值 + circulating_market_cap = float(parts[44]) if parts[44] else 0 # 流通市值 + pb = float(parts[45]) if parts[45] else 0 # 市净率 if not name or current_price == 0: return None @@ -186,6 +192,11 @@ async def fetch_quote(code: str) -> Optional[dict]: "time": now.strftime("%H:%M:%S"), "change": round(change, 2), "changePercent": round(change_percent, 2), + "turnoverRate": round(turnover_rate, 2), + "pe": round(pe, 2) if pe else 0, + "pb": round(pb, 2) if pb else 0, + "totalMarketCap": round(total_market_cap, 2), + "circulatingMarketCap": round(circulating_market_cap, 2), } except Exception: return None diff --git a/src/lib/stock-api.ts b/src/lib/stock-api.ts index 710f364..52d124f 100755 --- a/src/lib/stock-api.ts +++ b/src/lib/stock-api.ts @@ -18,6 +18,11 @@ export interface StockQuote { time: string; change: number; changePercent: number; + turnoverRate: number; // 换手率% + pe: number; // 市盈率 + pb: number; // 市净率 + totalMarketCap: number; // 总市值 + circulatingMarketCap: number; // 流通市值 } export interface KLineData { diff --git a/src/routes/stock.$code.tsx b/src/routes/stock.$code.tsx index 7d8a7b4..17756ba 100755 --- a/src/routes/stock.$code.tsx +++ b/src/routes/stock.$code.tsx @@ -63,8 +63,14 @@ interface StockInfo { addedPrice: number | null; outerDisk: number; // 外盘(手) innerDisk: number; // 内盘(手) + volume: number; // 成交量(股) amount: number; // 成交额(元) quoteDate: string; // 行情日期 YYYY-MM-DD + turnoverRate: number; // 换手率% + pe: number; // 市盈率 + pb: number; // 市净率 + totalMarketCap: number; // 总市值 + circulatingMarketCap: number; // 流通市值 } function StockDetail() { @@ -155,6 +161,12 @@ function StockDetail() { innerDisk: quote.innerDisk || 0, amount: (quote.amount || 0) * 10000, quoteDate: quote.date, + volume: quote.volume || 0, + turnoverRate: quote.turnoverRate ?? 0, + pe: quote.pe ?? 0, + pb: quote.pb ?? 0, + totalMarketCap: quote.totalMarketCap ?? 0, + circulatingMarketCap: quote.circulatingMarketCap ?? 0, }); // 基础信息已就绪,结束主loading,先渲染页面框架 @@ -267,6 +279,14 @@ function StockDetail() { negativeDays: negative, }; }, [fundFlowSlice]); + + // 从财务数据中提取最新ROE(加权净资产收益率) + const latestROE = useMemo(() => { + if (!financialData?.data?.length) return null; + const latest = financialData.data[0]; + const roe = latest.indicators["加权净资产收益率"]; + return typeof roe === "number" ? roe : null; + }, [financialData]); if (loading) { return (
@@ -653,6 +673,53 @@ function StockDetail() {
+ {/* 行情指标:PE / PB / ROE / 换手率 / 总手 / 成交额 / 市值 */} + + + 行情指标 + + +
+
+

市盈率(PE)

+

{stockInfo.pe > 0 ? stockInfo.pe.toFixed(2) : '-'}

+
+
+

市净率(PB)

+

{stockInfo.pb > 0 ? stockInfo.pb.toFixed(2) : '-'}

+
+
+

ROE(加权净资产收益率)

+

0 ? 'text-red-500' : 'text-green-500') : ''}`}> + {latestROE !== null ? `${latestROE.toFixed(2)}%` : '加载中...'} +

+
+
+

换手率

+

{stockInfo.turnoverRate > 0 ? `${stockInfo.turnoverRate}%` : '-'}

+
+
+

总手

+

+ {stockInfo.volume > 0 ? `${(stockInfo.volume / 100).toLocaleString()}手` : '-'} +

+
+
+

成交额

+

{formatMoney(stockInfo.amount)}

+
+
+

总市值

+

{stockInfo.totalMarketCap > 0 ? formatMoney(stockInfo.totalMarketCap) : '-'}

+
+
+

流通市值

+

{stockInfo.circulatingMarketCap > 0 ? formatMoney(stockInfo.circulatingMarketCap) : '-'}

+
+
+
+
+ {/* Daily Data Table - Independent from fund flow */} {chartData.length > 0 && (