""" 资金流向监控系统 功能: 1. 北向资金每日流向监控 2. 北向资金板块流向统计 3. 主力资金流向监控 4. 资金流量化因子构建 5. 资金背离信号预警(指数涨资金跌/指数跌资金涨) Author: 关羽(云长) Date: 2026-03-27 """ from dataclasses import dataclass from typing import List, Dict, Optional, Tuple import pandas as pd import numpy as np @dataclass class CapitalFlowData: """单日资金流向数据""" date: str # 北向资金 northbound_total: float # 当日北向净流入(亿) northbound_5d_avg: float # 5日平均净流入 northbound_20d_avg: float # 20日平均净流入 # 主力资金 main_force_net: float # 当日主力净流入(亿) main_force_5d_avg: float main_force_20d_avg: float # 板块数据 sector_northbound_flow: Dict[str, float] # 板块北向净流入 sector_main_flow: Dict[str, float] # 板块主力净流入 @dataclass class CapitalFlowStock: """个股资金流向""" code: str name: str sector: str # 资金数据 northbound_hold_change: float # 北向持仓变化(周%) main_force_flow_5d: float # 5日主力净流入(亿) main_force_flow_20d: float # 20日主力净流入 turnover_rate: float # 换手率 # 价格数据 pct_change_5d: float # 5日涨跌幅% class CapitalFlowConfig: """资金监控参数配置""" def __init__(self, northbound_bull_threshold: float = 20.0, # 单日北向净流入超20亿算强势 northbound_bear_threshold: float = -20.0, # 单日净流出超20亿算弱势 consecutive_bull_days: int = 3, # 连续3天净流入算趋势转强 consecutive_bear_days: int = 3, # 连续3天净流出算趋势转弱 main_flow_deviation_threshold: float = -0.5, # 资金背离阈值:价涨资金跌 hot_sector_flow_pct_threshold: float = 0.3): # 板块资金占比超30%算热点 self.northbound_bull_threshold = northbound_bull_threshold self.northbound_bear_threshold = northbound_bear_threshold self.consecutive_bull_days = consecutive_bull_days self.consecutive_bear_days = consecutive_bear_days self.main_flow_deviation_threshold = main_flow_deviation_threshold self.hot_sector_flow_pct_threshold = hot_sector_flow_pct_threshold default_config = CapitalFlowConfig() class NorthboundMonitor: """北向资金监控""" def __init__(self, config: CapitalFlowConfig = None): self.config = config or default_config self.history: List[CapitalFlowData] = [] def add_daily_data(self, data: CapitalFlowData): """添加每日数据""" self.history.append(data) # 按日期排序 self.history.sort(key=lambda x: x.date) def get_trend(self) -> str: """判断北向资金整体趋势""" if len(self.history) < self.config.consecutive_bull_days: return "neutral" recent = self.history[-self.config.consecutive_bull_days:] bull_days = sum(1 for d in recent if d.northbound_total > self.config.northbound_bull_threshold) bear_days = sum(1 for d in recent if d.northbound_total < self.config.northbound_bear_threshold) if bull_days >= self.config.consecutive_bull_days: return "strong_bull" elif bear_days >= self.config.consecutive_bear_days: return "strong_bear" elif np.mean([d.northbound_total for d in recent]) > 0: return "weak_bull" else: return "weak_bear" def get_sector_rank(self) -> List[Tuple[str, float]]: """获取板块北向资金流入排名""" if not self.history: return [] latest = self.history[-1] sectors = latest.sector_northbound_flow sorted_sectors = sorted(sectors.items(), key=lambda x: x[1], reverse=True) return sorted_sectors def get_hot_sectors(self) -> List[str]: """获取当前热点板块(北向资金集中流入)""" ranked = self.get_sector_rank() if not ranked: return [] total_inflow = sum(s[1] for s in ranked if s[1] > 0) if total_inflow <= 0: return [] hot = [] cumulative = 0 for name, flow in ranked: if flow <= 0: break pct = flow / total_inflow cumulative += pct hot.append(name) if cumulative >= self.config.hot_sector_flow_pct_threshold: break return hot def get_trend_signal(self) -> Tuple[str, str]: """获取趋势信号和说明""" trend = self.get_trend() signal_map = { "strong_bull": ("🔼 强烈看多", "北向连续三日净流入超20亿,趋势转强"), "weak_bull": ("▶️ 偏多", "北向整体净流入,趋势偏多"), "neutral": ("➖ 中性", "北向资金没有明确趋势"), "weak_bear": ("◀️ 偏空", "北向整体净流出,趋势偏空"), "strong_bear": ("🔽 强烈看空", "北向连续三日净流出超20亿,趋势转弱") } return signal_map[trend] class MainForceMonitor: """主力资金监控""" def __init__(self, config: CapitalFlowConfig = None): self.config = config or default_config def check_deviation(self, index_pct_5d: float, main_flow_5d: float) -> bool: """ 检查资金背离 指数涨但主力资金净流出 → 顶背离,风险预警 """ if index_pct_5d > 5 and main_flow_5d < self.config.main_flow_deviation_threshold * abs(index_pct_5d): return True # 背离,预警 return False def rank_stocks_by_main_flow(self, stocks: List[CapitalFlowStock]) -> Tuple[List[str], List[str]]: """对个股按主力资金流排名,返回强流入和强流出列表""" sorted_stocks = sorted(stocks, key=lambda x: x.main_force_flow_5d, reverse=True) # 前20%强流入 top_count = max(len(sorted_stocks) // 5, 1) top_codes = [s.code for s in sorted_stocks[:top_count]] # 后20%强流出 bottom_codes = [s.code for s in sorted_stocks[-top_count:]] return top_codes, bottom_codes def check_sector_main_trend(self, flow_data: Dict[str, float]) -> List[Tuple[str, str]]: """检查板块主力资金趋势""" result = [] for sector, flow in flow_data.items(): if flow > 10: result.append((sector, "bull")) elif flow < -10: result.append((sector, "bear")) return result class CapitalFlowFactorBuilder: """资金流量化因子构建""" @staticmethod def build_northbound_factor(stock: CapitalFlowStock) -> float: """ 北向资金因子 周度北向持仓变化,归一化到 0~1,越高越好 """ change = stock.northbound_hold_change # 归一化:-5% → 0,+5% → 1 factor = (change + 5.0) / 10.0 return max(0.0, min(1.0, factor)) @staticmethod def build_main_force_factor(stock: CapitalFlowStock) -> float: """ 主力资金因子 5日主力净流入/流通市值,归一化到 0~1 """ # 假设流通市值大概100亿,5日净流入超5亿算满分 flow = stock.main_force_flow_5d factor = (flow + 5.0) / 10.0 return max(0.0, min(1.0, factor)) @staticmethod def build_turnover_factor(stock: CapitalFlowStock) -> float: """ 换手率因子 换手率适中最好,过低没流动性,过高太疯狂 最优区间:2%~8% """ tr = stock.turnover_rate if tr < 1: return 0.2 + tr * 0.3 # 0 → 0.2,1 → 0.5 elif tr <= 8: return 0.8 - abs(tr - 5) * 0.05 # 5% → 0.8 else: return max(0.2, 1.0 - (tr - 8) * 0.05) @staticmethod def build_combined_factor(stock: CapitalFlowStock) -> float: """综合资金因子""" nf = CapitalFlowFactorBuilder.build_northbound_factor(stock) mf = CapitalFlowFactorBuilder.build_main_force_factor(stock) tf = CapitalFlowFactorBuilder.build_turnover_factor(stock) # 加权:北向40%,主力40%,换手率20% combined = nf * 0.4 + mf * 0.4 + tf * 0.2 return combined class CapitalFlowRiskMonitor: """资金流向风险预警""" def __init__(self, config: CapitalFlowConfig = None): self.config = config or default_config self.northbound_monitor = NorthboundMonitor(config) def check_systemic_risk(self, index_pct_5d: float, total_main_flow_5d: float) -> Tuple[bool, str]: """检查系统性风险""" # 指数涨但主力资金大规模流出 → 风险 if self.northbound_monitor.get_trend() == "strong_bear": return True, "北向资金连续大幅流出,系统性风险上升" # 指数涨主力跌 → 背离 if index_pct_5d > 5 and total_main_flow_5d < 0: return True, f"指数5日涨{index_pct_5d:.1f}%但主力资金净流出,顶背离风险" return False, "" class CapitalFlowMonitor: """总资金流向监控器""" def __init__(self, config: CapitalFlowConfig = None): self.config = config or default_config self.northbound = NorthboundMonitor(config) self.main_force = MainForceMonitor(config) self.risk = CapitalFlowRiskMonitor(config) self.factor_builder = CapitalFlowFactorBuilder() def get_daily_report(self, data: CapitalFlowData, stocks: List[CapitalFlowStock], index_pct_5d: float) -> str: """生成每日资金流向报告""" self.northbound.add_daily_data(data) lines = [] lines.append("=" * 60) lines.append("资金流向监控日报") lines.append("=" * 60) # 北向趋势 trend, desc = self.northbound.get_trend_signal() lines.append(f"北向资金趋势: {trend} → {desc}") lines.append(f"最近一日净流入: {data.northbound_total:.1f}亿") lines.append(f"5日均: {data.northbound_5d_avg:.1f}亿 20日均: {data.northbound_20d_avg:.1f}亿") lines.append("") # 北向板块排名 hot_sectors = self.northbound.get_hot_sectors() if hot_sectors: lines.append(f"🔼 北向资金集中流入板块: {', '.join(hot_sectors)}") lines.append("") # 主力资金板块 sector_trend = self.main_force.check_sector_main_trend(data.sector_main_flow) bull_sectors = [s[0] for s in sector_trend if s[1] == "bull"] bear_sectors = [s[0] for s in sector_trend if s[1] == "bear"] if bull_sectors: lines.append(f"✅ 主力资金净流入板块: {', '.join(bull_sectors)}") if bear_sectors: lines.append(f"⚠️ 主力资金净流出板块: {', '.join(bear_sectors)}") lines.append("") # 风险检查 has_risk, reason = self.risk.check_systemic_risk(index_pct_5d, data.main_force_5d_avg) if has_risk: lines.append(f"⚠️ 风险预警: {reason}") else: lines.append("✅ 无明显系统性风险") # 个股资金因子示例 if stocks: top_stocks = sorted(stocks, key=lambda x: self.factor_builder.build_combined_factor(x), reverse=True)[:5] lines.append("") lines.append("💯 综合资金因子前五名:") for s in top_stocks: f = self.factor_builder.build_combined_factor(s) lines.append(f" {s.code} {s.name} 因子得分: {f:.2f}") lines.append("=" * 60) return "\n".join(lines) if __name__ == "__main__": print("=== 测试资金流向监控模块 ===\n") # 测试北向监控 from datetime import datetime, timedelta monitor = CapitalFlowMonitor() # 添加最近几天数据 dates = ["2026-03-23", "2026-03-24", "2026-03-25", "2026-03-26", "2026-03-27"] flows = [25, 32, 18, -10, -28] for date, flow in zip(dates, flows): data = CapitalFlowData( date=date, northbound_total=flow, northbound_5d_avg=np.mean(flows[-5:]), northbound_20d_avg=np.mean(flows[-20:]) if len(flows)>=20 else np.mean(flows), main_force_net=flow * 2, main_force_5d_avg=np.mean([f*2 for f in flows[-5:]]), main_force_20d_avg=np.mean([f*2 for f in flows]), sector_northbound_flow={"AI": 45, "新能源": -15, "消费": 8, "金融": -5}, sector_main_flow={"AI": 60, "新能源": -20, "消费": 12} ) monitor.northbound.add_daily_data(data) # 测试个股 stocks = [ CapitalFlowStock( code="600000", name="浦发银行", sector="银行", northbound_hold_change=1.2, main_force_flow_5d=2.5, main_force_flow_20d=8.0, turnover_rate=3.5, pct_change_5d=2.1 ), CapitalFlowStock( code="002XXX", name="AI龙头", sector="AI", northbound_hold_change=3.5, main_force_flow_5d=8.5, main_force_flow_20d=25.0, turnover_rate=5.2, pct_change_5d=8.5 ), CapitalFlowStock( code="601XXX", name="周期股", sector="周期", northbound_hold_change=-2.1, main_force_flow_5d=-5.2, main_force_flow_20d=-15.0, turnover_rate=12.5, pct_change_5d=-6.2 ) ] # 生成报告 print(monitor.get_daily_report(data, stocks, 2.5)) # 测试因子构建 print("\n=== 测试资金因子构建 ===") for s in stocks: f = monitor.factor_builder.build_combined_factor(s) print(f"{s.name}: 综合因子得分 {f:.2f}")