Metadata-Version: 2.4
Name: etf-flow
Version: 0.1.3
Summary: ETF tracking, quantitative analysis and opportunity radar tool
Requires-Python: <3.13,>=3.12
Description-Content-Type: text/markdown
Requires-Dist: fastapi>=0.110.0
Requires-Dist: kdata-quant>=1.3.7
Requires-Dist: mootdx2>=1.5.4
Requires-Dist: rich>=13.0.0
Requires-Dist: uvicorn>=0.28.0

# ETF Flow - Python API 接口与模块函数调用手册

本文档是 `etf-flow` 量化库的完整 Python 开发调用指南，详细阐述所有公开导出模块、函数签名、传参规范、返回数据模型与量化实战调用样例。

---

## 1. 顶层导入与包结构

所有核心量化功能均已通过 `src/etf_flow/__init__.py` 统一暴露于包顶层（同时保留 `etf_tracker` 兼容导出）。开发者无需深入子模块路径，直接按标准 Python 习惯导入即可：

```python
import etf_flow as etf  # 亦兼容 import etf_tracker as etf

print(etf.__version__)  # "2.1.0"
print(len(etf.__all__)) # 55 个导出符号
```

或者显式导入所需组件：

```python
from etf_flow import (
    scan_and_recommend_stocks,
    build_full_pcf_index,
    get_settled_premium_history,
    analyze_settled_arbitrage_flow,
    calculate_stock_liquidity_impact,
    get_stock_free_float_cap_wan,
    get_stock_liquidity_profile,
    predict_index_rebalance,
    EventStudyEngine,
    detect_liquidity_trap,
)
```
---

## 2. 版本升级履历 (Changelog)

### v0.1.2 (2026-11-04) - 核心量化模型升级与工程强化
- **🌊 引入非线性平方根价格冲击模型 (Square-Root Law)**：
  - 落地机构级非线性冲击模型：$\Delta P/P = \text{sign}(Q) \cdot Y \cdot \sigma_{20d} \cdot \sqrt{|Q| / ADV_{20d}}$，解决传统线性 ADV 占比指标对小票高估、对大票低估问题；
  - 自动基于真实日K（`kdata.get_any_ohlc`）计算标的过去 20 日日收益率标准差 $\sigma_{20d}$；
  - `StockImpactMetrics` 与 `StockRecommendation` 新增 `sqrt_impact_bp`（基点推升/打压 bp）与 `sigma_20d_pct`（日波动率 %）字段；
  - 导出新 API：`get_stock_liquidity_profile(stock_code)`。
- **🏛️ 真实自由流通市值接入与硬编码废除**：
  - 彻底废除 `ADV×100`（固定假定 1% 换手率）的估算逻辑；
  - 优先调用 `kdata.get_quote` 获取官方实时流通市值，次优通过 `mootdx2` 底层财务数据 `liutong_guben` 结合定盘价折算，并附带 $\ge 0.08\text{s}$ 防封节流保护；
  - 导出新 API：`get_stock_free_float_cap_wan(stock_code)`。
- **🎯 选股推荐引擎多因子评分连续化与仲裁升级**：
  - 移除原 5 档硬编码阶梯跳变（96/88/80/72/60），将 $S_{Impact}$ 与 $S_{Elasticity}$ 重构为连续平滑函数，彻底消除分档断崖；
  - 同分第二仲裁中枢由原粗放金额升级为**预期价格冲击幅度（`sqrt_impact_bp ↓`）**。
- **🛠️ 工程与工具链增强**：
  - `Makefile` 新增语义化版本管理指令：`make version`、`make bump-patch`、`make bump-minor`、`make bump-major` 并自动同步 `uv.lock`；
  - 新增 `system/scripts/bump_version.py` 语义化版本管理工具；
  - 企微与飞书通知卡片同步展示自适应预期冲击 `+{bp}bp` 标签。

### v0.1.1 (2026-11-03) - 命名规范与 PyPI 独立文档
- 重命名项目包名为 `etf-flow`，解决 PyPI 发布名称冲突，保持 `etf_tracker` 双模块向后兼容导出；
- 配置 PyPI 发布使用独立的 `docs/API.md` 作为长文档说明。

### v0.1.0 (2026-11-02) - 初始发布
- 首次发布：集成双所官方日频份额对账、每日 PCF 100% 成分股穿透、日K定盘折溢价套利沉淀及事件研究回测引擎。

---

## 3. 核心量化模块与函数详解

### 2.1 选股推荐与多因子评分引擎 (`recommender.py`)

穿透全市场 ETF 资金流动与权重变动，计算成分股被动买盘，输出符合五大黄金场景的推荐结果与多因子综合评分。

#### 函数：`scan_and_recommend_stocks`
```python
def scan_and_recommend_stocks(
    min_elasticity: float = 300.0,
    top_n: int = 10,
    category_filter: str = "all",
    scenario_filter: Optional[int] = None,
    use_pcf: bool = True,
) -> List[StockRecommendation]:
```
- **参数说明**：
  - `min_elasticity` (`float`): 最小单亿申购弹性门槛（万元/亿元，默认 300.0 万元，过滤低于此值的被动钝化标的）。
  - `top_n` (`int`): 返回最优推荐股票数量（默认 10）。
  - `category_filter` (`str`): ETF 类别筛选，`"all"` (全部) | `"broad"` (仅大宽基) | `"sector"` (仅行业赛道)。
  - `scenario_filter` (`Optional[int]`): 黄金场景过滤，`None` (全场景) 或 `1 ~ 5`（分别对应 SC-01 至 SC-05）。
  - `use_pcf` (`bool`): 是否优先使用当日 100% PCF 清单提取权重（默认 `True`，离线或无清单时自动优雅回退至法定季报）。
- **返回值**：`List[StockRecommendation]`，按综合评分 `composite_score`、1日买盘、弹性降序排列。

#### 数据模型：`StockRecommendation`
```python
@dataclass
class StockRecommendation:
    stock_code: str                     # 6位股票代码 (如 "300750")
    stock_name: str                     # 股票简称 (如 "宁德时代")
    star_rating: str                    # 星级评定: "★★★" | "★★" | "★"
    composite_score: float              # 多因子综合得分 (0.0 ~ 100.0)
    scenario_code: str                  # 场景代码: "SC-01" ~ "SC-05"
    primary_scenario: str               # 场景中文名 (如 "场景一：调样新纳入/权重跳升")
    scenario_desc: str                  # 场景量化依据与定量描述
    strategy_advice: str                # 实战买点SOP与生命周期窗口
    passive_flow_1d_wan: float          # 1日理论被动买盘注入额 (万元)
    passive_flow_5d_wan: float          # 5日理论被动买盘注入额 (万元)
    elasticity_per_100m_wan: float      # 单亿申购弹性 (万元/亿元)
    passive_vol_ratio_pct: float        # 单日被动买盘占全天成交额比重 (%)
    current_price: float                # 定盘收盘价
    change_1d_pct: float                # 单日涨跌幅 (%)
    stock_turnover_wan: float           # 个股成交额 (万元)
    time_window: str                    # 变动区间 (如 "26Q3 → 11-03(PCF)")
    weight_transition: str              # 权重跃升轨迹 (如 "17.32% → 20.10% (+2.78%)")
    disclosure_date: str                # 披露确认日 (如 "2026-11-03 (官方每日PCF清单)")
    timing_status: str                  # 时效状态说明
    calendar_countdown: str             # 下次调样倒计时 (如 "距11-30调样公告剩 27 天")
    linked_etfs_summary: List[Dict]     # 核心挂钩 ETF 明细
    adv_20_wan: float                   # 20日日均成交额 (万元)
    impact_ratio_pct: float             # 1日买盘占 20日 ADV 比例 (%)
    days_to_cover: float                # 承接消化天数 (Days to Cover)
    impact_rating: str                  # 冲击度评级: "🔴 极度过载" | "🟡 强托底" | "🟢 自然吸收"
    capital_attribution: str            # 资金归因画像 (如 "🏛️ 国家队/险资逆向托底")
    trap_risk_level: str                # 踩踏风险级别: "NONE" | "MEDIUM" | "HIGH"
    risk_warnings: List[str]            # 风险告警标签列表
    factor_scores: Dict[str, float]     # 细分因子得分明细 {"impact", "elasticity", "momentum", "smart_money"}
    sqrt_impact_bp: float               # 平方根冲击预期价格推升 (基点 bp)
    sigma_20d_pct: float                # 过去 20 日日收益率波动率 (%)

#### 函数：`render_recommendations_markdown`
```python
def render_recommendations_markdown(recs: List[StockRecommendation]) -> str:
    """渲染为标准化、排版优雅的 Markdown 研报字符串."""
```

---

### 2.2 PCF 100% 全成分股高频穿透模块 (`pcf.py`)

突破季报仅披露前十大重仓股的严重局限，支持沪深交易所每日盘前发布的申购赎回清单无损解析与持久化。

#### 函数列表：
```python
def fetch_and_cache_etf_pcf(
    etf_code: str,
    target_date: Optional[str] = None,
    use_cache: bool = True,
    force_refresh: bool = False,
) -> pd.DataFrame:
    """拉取单只 ETF 的 PCF 并持久化至本地 Parquet 缓存 (~/.cache/etf_flow/pcf/)."""

def get_pcf_stock_weights(
    etf_code: str,
    target_date: Optional[str] = None,
) -> Dict[str, Dict[str, Any]]:
    """获取单只 ETF 的全部 100% 成分股权重字典: {stock_code: {name, weight_pct, shares, cash_flag_desc}}."""

def build_full_pcf_index(
    etf_codes: Optional[List[str]] = None,
    target_date: Optional[str] = None,
) -> Dict[str, List[Dict[str, Any]]]:
    """构建以“个股代码”为 Key 的全市场 ETF 100% PCF 挂钩穿透倒排索引."""
```

#### 数据模型：`PCFConstituent`
```python
@dataclass
class PCFConstituent:
    stock_code: str             # 成分股代码 (如 "600519")
    stock_name: str             # 成分股简称
    shares: float               # 申赎单位成分股数量 (股)
    cash_flag: int              # 现金替代标志: 0=禁止, 1=可以, 2=必须
    cash_flag_desc: str         # "禁止现金替代" | "允许现金替代" | "必须现金替代"
    cash_ratio: float           # 现金替代溢价比例 (如 0.10 表示 10%)
    fixed_cash: float           # 固定替代金额 (元)
    weight_pct: float           # 测算权重占一篮子净值比例 (%)
```

---

### 2.3 日K定盘折溢价时序与一二级套利沉淀引擎 (`arbitrage.py`)

严格立足每日 18:30 官方定盘日K收盘价与基金公司日终披露的权威 NAV，彻底剔除盘中 15 分钟实时 IOPV 假信号。

#### 函数列表：
```python
def get_settled_etf_nav_and_close(etf_code: str) -> Dict[str, float]:
    """获取指定 ETF 最新官方定盘收盘价与权威 NAV (返回: {'close_price', 'nav', 'premium_rate_pct'})."""

def fetch_official_etf_nav_history(
    etf_code: str,
    use_cache: bool = True,
) -> pd.DataFrame:
    """拉取权威历史日终 NAV 序列并持久化至本地 Parquet (~/.cache/etf_flow/nav/)."""

def get_settled_premium_history(
    etf_code: str,
    days: int = 5,
    reference_date: Optional[str] = None,
) -> List[SettledDailyPremium]:
    """获取目标 ETF 最近 N 个交易日的真实定盘收盘价、NAV 与已结算折溢价率时序."""

def analyze_settled_arbitrage_flow(
    etf_code: str,
    history_days: int = 5,
    etf_name: Optional[str] = None,
    share_delta_wan: Optional[float] = None,
) -> ArbitrageSettlementSignal:
    """定量分析一二级市场申赎套利动能对成分股的刚性买入推升或持续抛压."""

def scan_market_arbitrage_settlement(
    etf_codes: Optional[List[str]] = None,
) -> List[ArbitrageSettlementSignal]:
    """全市场批量扫描具有显著连续折溢价与套利沉淀压迫力的标的."""
```

#### 数据模型：
```python
@dataclass
class SettledDailyPremium:
    date: str                   # 交易日期 (YYYY-MM-DD)
    close_price: float          # 官方定盘收盘价
    nav: float                  # 官方日终单位净值
    premium_rate_pct: float     # 折溢价率 (%) = (close - nav) / nav * 100
    shares_wan: float = 0.0     # 当日流通份额 (万份)
    share_delta_wan: float = 0.0# 1日份额净申赎 (万份)

@dataclass
class ArbitrageSettlementSignal:
    etf_code: str
    etf_name: str
    settled_date: str
    latest_close: float
    latest_nav: float
    latest_premium_rate_pct: float  # 最新定盘折溢价率
    avg_premium_rate_3d: float      # 近 3 日平均折溢价率
    signal_type: str                # "PREMIUM_CREATION_INFLOW" (溢价申购沉淀)
                                    # "DISCOUNT_REDEMPTION_OUTFLOW" (折价赎回抛压)
                                    # "NEUTRAL_PAR" (平价中性)
    signal_desc: str                # 信号说明
    streak_days: int                # 连续溢价/折价交易日数
    arbitrage_pressure_wan: float   # 测算套利沉淀资金规模 (万元)
    constituents_impact_desc: str   # 对成分股次日开盘与波段趋势的影响研判
    risk_level: str                 # "HIGH" | "MEDIUM" | "LOW" | "NONE"
    history: List[SettledDailyPremium]
```

---

### 2.4 流动性冲击与承接天数模型 (`impact.py`)

测算个股流动性深度对被动买卖盘的消化能力与承接天数。

#### 函数列表：
```python
def get_stock_adv20(stock_code: str) -> Tuple[float, float]:
    """获取标的过去 20 个交易日的日均成交额 ADV (万元) 与成交量中位数 (股)."""

def get_stock_liquidity_profile(stock_code: str) -> Tuple[float, float, float]:
    """获取标的过去 20 个交易日的 (日均成交额万元, 成交量中位数股, 20日收益率日波动率sigma)."""

def get_stock_free_float_cap_wan(
    stock_code: str,
    stock_price: float = 0.0,
    fallback_adv: float = 15000.0,
) -> float:
    """获取标的真实自由流通市值 (万元)，优先 kdata.get_quote，其次 mootdx2 finance，最后按 ADV×100 兜底."""

def calculate_stock_liquidity_impact(
    stock_code: str,
    stock_price: float,
    passive_flow_1d_wan: float,
    current_turnover_wan: Optional[float] = None,
    free_float_market_cap_wan: Optional[float] = None,
    impact_coefficient: float = 1.0,
) -> StockImpactMetrics:
    """测算个股被动买盘的流动性冲击度、消化天数、真实自由流通市值吸收率与平方根价格冲击预期 (bp)."""

#### 数据模型：`StockImpactMetrics`
```python
@dataclass
class StockImpactMetrics:
    stock_code: str
    adv_20_amount_wan: float            # 过去 20 日日均成交额 ADV (万元)
    median_volume_20d_shares: float     # 过去 20 日成交量中位数 (股)
    impact_ratio_pct: float             # 1日买盘占 20日 ADV 比例 (%)
    days_to_cover: float                # 承接消化天数 = 被动买盘股数 / 20日成交量中位数
    impact_rating: str                  # "🔴 极度过载" | "🟡 强托底 (温和增量)" | "🟢 自然吸收"
    rating_level: str                   # "extreme" | "strong" | "mild"
    impact_desc: str                    # 定量描述
    absorption_pressure_pct: float      # 被动买盘占自由流通市值比重 (%)
    free_float_market_cap_wan: float    # 真实自由流通市值 (万元)
    sigma_20d: float                    # 过去 20 日收益率日波动率
    sqrt_impact_bp: float               # 平方根冲击预期价格推升 (基点 bp)

---

### 2.5 真实 K 线驱动的事件研究回测引擎 (`backtest.py`)

基于真实历史行情与基准（`sh.000300`），评估被动资金事件与调样套利的累计超额收益 CAR、胜率与策略容量上限。

#### 函数与类：
```python
def calculate_real_event_car(
    stock_symbol: str,
    event_date: str,
    benchmark_symbol: str = "sh.000300",
) -> Tuple[List[float], float, float]:
    """基于真实日K计算事件窗口 T+1, T+3, T+5, T+10, T+20 的真实 CAR、最大回撤 MDD 与 20日 ADV."""

class EventStudyEngine:
    def __init__(self, benchmark_symbol: str = "sh.000300"): ...

    def run_event_study(
        self,
        event_type: str = "A",          # "A" (ETF巨量申购托底)
                                        # "B" (调样名单官方公告日)
                                        # "C" (调样生效前抢跑兑现)
        start_date: str = "2024-01-01",
        end_date: str = "2026-11-03",
    ) -> EventStudyResult:
        """执行事件研究回测并生成评估研报."""
```

#### 数据模型：`EventStudyResult`
```python
@dataclass
class EventStudyResult:
    event_type: str                     # "A" | "B" | "C"
    event_title: str                    # 事件全称
    total_events: int                   # 独立有效事件样本数
    benchmark: str                      # 基准代码 (如 "sh.000300")
    mean_car_t1: float                  # T+1 平均累计超额收益 CAR (%)
    mean_car_t3: float                  # T+3 平均 CAR (%)
    mean_car_t5: float                  # T+5 平均 CAR (%)
    mean_car_t10: float                 # T+10 平均 CAR (%)
    mean_car_t20: float                 # T+20 平均 CAR (%)
    win_rate_pct: float                 # 胜率 (%)
    profit_loss_ratio: float            # 盈亏比
    max_drawdown_pct: float             # 持仓窗口最大回撤 (%)
    samples: List[EventStudySample]     # 逐笔事件明细
    capacity_decay: List[CapacityDecayPoint] # 冲击成本与容量衰减测试点
    summary_desc: str                   # 归因与结论描述
```

---

### 2.6 指数定期调样“前置预判”引擎 (`rebalance.py`)

还原指数官方编制规则（流动性过滤、市值排名、缓冲区规则、权重上限），提前 30–45 天锁定候选名单。

```python
def calculate_rebalance_countdown(today: Optional[date] = None) -> Tuple[int, str, str, str]:
    """计算距下一次定期调样的倒计时天数、调样窗口标签、官方公告日与生效日."""

def predict_index_rebalance(
    index_code: str = "000300",          # "000300" | "000905" | "000852" | "000688"
    reference_date: Optional[date] = None,
) -> IndexRebalanceForecast:
    """预测指定指数的定期调样调入/调出名单与存量重配资金规模."""
```

---

### 2.7 资金性质归因与踩踏反噬哨兵 (`sentinel.py`)

```python
def attribute_etf_capital_flow(
    etf_code: str,
    etf_name: str,
    etf_category: str,
    flow_1d_wan: float,
    flow_5d_wan: float,
    change_1d_pct: float,
) -> CapitalAttribution:
    """依据市场环境与量价流动特征，对 ETF 资金性质进行自动归因 (国家队托底/FOF配置/游资散户追高/中性)."""

def detect_liquidity_trap(
    stock_code: str,
    stock_name: str,
    stock_change_pct: float,
    passive_flow_1d_wan: float,
    passive_vol_ratio: float,
    linked_etf_flows: List[Dict[str, Any]],
    north_money_change_pct: Optional[float] = None,
    etf_free_float_ratio_pct: Optional[float] = None,
    consecutive_redemption_days: Optional[int] = None,
    is_below_ma20: Optional[bool] = None,
) -> LiquidityTrapAlert:
    """排查个股是否存在 PRD F2.4 严格三合一流动性踩踏或高位背离反噬风险."""
```

---

### 2.8 标的池管理与行业赛道归类 (`universe.py`)

```python
def get_tracked_codes(category: str = "all") -> List[str]:
    """获取核心跟踪池 ETF 代码列表 (category: 'all' | 'broad' | 'sector')."""

def get_dynamic_etf_universe(
    min_scale: float = 10.0,
    min_adv_wan: float = 5000.0,
    category: str = "all",
    use_cache: bool = True,
) -> List[ETFMeta]:
    """构建全市场动态 ETF 资金池 (AUM > 10亿，ADV > 5000万，覆盖 >800 只标的)."""

def get_sector_etf_mapping(
    universe: Optional[List[ETFMeta]] = None,
) -> Dict[str, List[ETFMeta]]:
    """按 31 个申万/中证一级行业归类行业赛道 ETF 标的池 (用于行业被动大潮共振判定)."""

def classify_etf(name: str, benchmark: str = "") -> Tuple[str, str]:
    """依据 ETF 名称与基准判断分类 ('broad' | 'sector') 及所属一级行业."""
```

---

### 2.9 沪深双交易所官方定盘份额对账 (`scale.py`)

```python
def fetch_sse_etf_shares(query_date: Optional[str] = None) -> pd.DataFrame:
    """拉取上交所 (SSE) 官方定盘日频 ETF 份额."""

def fetch_szse_etf_shares() -> pd.DataFrame:
    """拉取深交所 (SZSE) 官方定盘日频 ETF 份额."""

def get_dual_exchange_etf_shares(
    target_date: Optional[str] = None,
    use_cache: bool = True,
) -> pd.DataFrame:
    """获取沪深双交易所官方日频 ETF 份额合并表 (带定盘时钟防重与离线降级保障)."""

def get_etf_share_deltas(
    etf_codes: Optional[List[str]] = None,
    target_date: Optional[str] = None,
) -> Dict[str, Dict[str, float]]:
    """测算目标 ETF 列表的 1日与 5日份额净变动 (万份)."""
```

---

### 2.10 高速实时盘口与流通份额 (`tencent.py`)

```python
def get_tencent_quotes(symbols: List[str]) -> Dict[str, TencentQuote]:
    """毫秒级批量抓取腾讯盘口、最新价、涨跌幅与总流通份额 (带自动重试与符号适配)."""

def to_tencent_symbol(code: str) -> str:
    """将代码转换为腾讯源格式 (如 '600519' -> 'sh600519', '000001' -> 'sz000001')."""
```

---

## 4. 完整导出清单 (`__all__`)

```python
[
    # Universe (标的池与分类)
    "ETFMeta", "TRACKED_ETFS", "ETF_MAP", "get_tracked_codes",
    "get_dynamic_etf_universe", "get_sector_etf_mapping", "classify_etf",

    # PCF (100%全成分股穿透)
    "PCFConstituent", "fetch_and_cache_etf_pcf", "get_pcf_stock_weights", "build_full_pcf_index",

    # Scale (双所官方份额对账)
    "fetch_sse_etf_shares", "fetch_szse_etf_shares", "get_dual_exchange_etf_shares", "get_etf_share_deltas",

    # Holdings (法定季报持仓穿透)
    "StockHoldingInETF", "StockETFProfile", "fetch_etf_portfolio_holdings", "build_stock_etf_index",

    # Arbitrage (定盘折溢价与套利沉淀)
    "SettledDailyPremium", "ArbitrageSettlementSignal", "get_settled_etf_nav_and_close",
    "fetch_official_etf_nav_history", "get_settled_premium_history", "analyze_settled_arbitrage_flow",
    "scan_market_arbitrage_settlement",

    # Impact (流动性冲击模型)
    "StockImpactMetrics", "get_stock_adv20", "get_stock_liquidity_profile", "get_stock_free_float_cap_wan",
    "calculate_stock_liquidity_impact", "format_kdata_symbol",
    # Rebalance (调样前置预判)
    "RebalanceCandidate", "IndexRebalanceForecast", "calculate_rebalance_countdown",
    "predict_index_rebalance", "render_rebalance_markdown",

    # Sentinel (归因与踩踏哨兵)
    "CapitalAttribution", "LiquidityTrapAlert", "attribute_etf_capital_flow", "detect_liquidity_trap",

    # Recommender (选股推荐与评分)
    "StockRecommendation", "calculate_etf_flow_delta", "scan_and_recommend_stocks", "render_recommendations_markdown",

    # Backtest (事件研究回测)
    "EventStudySample", "CapacityDecayPoint", "EventStudyResult", "EventStudyEngine",
    "calculate_real_event_car", "render_event_study_markdown",

    # Tencent (行情通道)
    "TencentQuote", "get_tencent_quotes", "to_tencent_symbol",
]
```
