Files
etf/framework_v2/DATA_FLOW_DEMO.md
aszerW 5f08e508ac docs(framework_v2): 完善文档体系 + 修复 .gitignore
## 文档体系(5 个文档,互相关联)
- README.md - 框架总览 + 文档索引
- DATA_ARCHITECTURE.md - 数据架构方案(Schema、验证、性能优化)
- ALIGNMENT_GUIDE.md - CrossMarketAligner 使用指南
- DATA_FLOW_DEMO.md - 从 OHLCV 到最终收益的 7 个阶段推演
- ALIGNMENT_SCHEMA_INTEGRATION.md - Aligner + Schema 整合方案

## 文档特色
- 大量代码示例( 正确 vs  错误对比)
- 数据流可视化(ASCII 图)
- 表格总结(问题、严重度、解决方案)
- 实际场景推演(2024-01-01 ~ 2024-01-31)
- 文档互链(形成知识网络)

## 修复
- .gitignore: 添加 !framework_v2/shared/data/ 例外
- 允许提交对齐器相关文件
2026-05-24 10:29:20 +08:00

781 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 跨市场数据流完整推演
## 📋 场景设定
### 标的池
| 标的 | 市场 | 年交易日 | 特点 |
|------|------|----------|------|
| ^GSPC标普500 | 美股 | 252 天 | 美国假日(马丁路德金日、感恩节) |
| ^HSI恒生指数 | 港股 | 250 天 | 香港假日(佛诞日、圣诞节) |
| 000300.SH沪深300 | A 股 | 244 天 | 中国假日(春节、国庆) |
**目标日历**A 股交易日244 天)
### 假日差异示例2024 年 1 月)
| 日期 | 美股 | 港股 | A 股 | 说明 |
|------|------|------|------|------|
| 2024-01-01 | 休市 | 休市 | 休市 | 元旦(共同假日) |
| 2024-01-02 | 交易 | 交易 | 交易 | - |
| 2024-01-15 | 休市 | 交易 | 交易 | 马丁路德金日(仅美股休市) |
| 2024-02-10 | 交易 | 交易 | 休市 | 春节(仅 A 股休市) |
---
## 🎬 完整数据流推演7 个阶段)
### 阶段 0原始数据不同日历
```python
# 从数据源获取原始 OHLCV 数据
index_data = {
'^GSPC': DataFrame(252 rows, US calendar), # 美股
'^HSI': DataFrame(250 rows, HK calendar), # 港股
'000300.SH': DataFrame(244 rows, CN calendar) # A 股
}
# 示例2024 年 1 月第一周
^GSPC (美股):
日期 close
2024-01-01 4770.0 元旦美股休市无数据或从 yfinance 获取
2024-01-02 4780.0
2024-01-03 4790.0
2024-01-04 4785.0
2024-01-05 4800.0
...
^HSI (港股):
日期 close
2024-01-01 17050.0 元旦港股休市
2024-01-02 17100.0
2024-01-03 17150.0
2024-01-04 17120.0
2024-01-05 17200.0
...
000300.SH (A ):
日期 close
2024-01-01 3500.0 元旦A 股休市
2024-01-02 3510.0
2024-01-03 3520.0
2024-01-04 3515.0
2024-01-05 3530.0
...
```
**关键问题**
- ❌ 三个市场的交易日历不同
- ❌ 直接合并会导致大量 NaN
- ❌ 无法直接计算因子和收益
---
### 阶段 1因子计算在原始日历
```python
from framework_v2.shared.factors import MomentumFactor
factor = MomentumFactor(n_days=25, weighted=True, crash_filter=True)
# ✅ 关键:在原始交易日历计算因子(不 ffill
factor_raw = {}
for code, df in index_data.items():
factor_raw[code] = factor.compute(df)
# 结果:每个标的在各自的交易日历上有因子值
^GSPC 因子美股日历 252 :
日期 factor
2024-01-01 NaN 25 天数据不足
...
2024-01-26 0.15 26 天开始有因子值
2024-01-29 0.16
2024-01-30 0.17
...
^HSI 因子港股日历 250 :
日期 factor
2024-01-02 NaN
...
2024-01-26 0.14
2024-01-29 0.15
2024-01-30 0.16
...
000300.SH 因子A 股日历 244 :
日期 factor
2024-01-02 NaN
...
2024-01-29 0.13
2024-01-30 0.14
...
```
**为什么在原始日历计算?**
1. ✅ rolling window 使用**真实交易日**25 天)
2. ✅ 线性回归权重基于真实数据分布
3. ❌ 如果先 ffill窗口会包含重复值影响因子精度
---
### 阶段 2对齐因子到 A 股日历
```python
from framework_v2.shared.data.alignment import CrossMarketAligner
# 创建对齐器(目标日历 = A 股)
aligner = CrossMarketAligner(target_calendar=a_share_dates) # 244 天
# 对齐每个标的的因子值
factor_aligned = {}
for code, factor_series in factor_raw.items():
aligned = aligner.align_factor(
factor_series,
source_calendar=index_data[code].index, # 原始日历
code=code
)
factor_aligned[code] = aligned['value'] # 提取因子值列
# 结果:所有因子值对齐到 A 股日历244 天)
^GSPC 因子A 股日历 244 :
日期 factor is_filled
2024-01-01 NaN False A 股休市元旦
2024-01-02 NaN False 数据不足 25
...
2024-01-26 0.15 False 真实值
2024-01-29 0.16 False 真实值
2024-01-30 0.16 True ffill美股休市填充前一天的因子值
2024-01-31 0.17 False 真实值
...
^HSI 因子A 股日历 244 :
日期 factor is_filled
2024-01-01 NaN False A 股休市
2024-01-02 0.14 False 真实值
...
2024-01-29 0.15 False 真实值
2024-01-30 0.15 True ffill港股休市
...
000300.SH 因子A 股日历 244 :
日期 factor is_filled
2024-01-01 NaN False A 股休市
2024-01-02 0.13 False 真实值
...
2024-01-29 0.14 False 真实值
2024-01-30 0.14 False 真实值A 股正常交易
...
```
**CrossMarketAligner 的作用**
```python
def align_factor(self, factor_series, source_calendar, code):
# 1. reindex + ffill
aligned = factor_series.reindex(self.target_calendar, method='ffill')
# 2. 标记填充值(不在 source_calendar 中的日期)
is_filled = ~aligned.index.isin(source_calendar)
# 3. 验证
self._validate_factor_alignment(aligned, is_filled, code)
return pd.DataFrame({
'value': aligned,
'is_filled': is_filled
})
```
**验证逻辑**
```python
def _validate_factor_alignment(self, aligned, is_filled, code):
# 1. 检查 NaN 比例
nan_ratio = aligned.isna().sum() / len(aligned)
if nan_ratio > 0.1: # > 10%
warnings.warn(f"{code}: 因子 NaN 比例过高 ({nan_ratio:.1%})")
# 2. 检查填充比例
fill_ratio = is_filled.sum() / len(is_filled)
if fill_ratio > 0.3: # > 30%
warnings.warn(f"{code}: 因子填充比例过高 ({fill_ratio:.1%})")
```
---
### 阶段 3生成信号
```python
from framework_v2.shared.signals import TopNSelector
selector = TopNSelector(select_num=3, min_score=0.0)
# 合并所有因子为 DataFrame
factor_df = pd.DataFrame(factor_aligned)
# 索引A 股日历244 天)
# 列:['^GSPC', '^HSI', '000300.SH']
# 生成信号
signals = selector.generate(factor_df)
# 结果:
signals DataFrameA 股日历 244 :
日期 signal
2024-01-01 '' 因子全 NaN空信号
2024-01-02 '' 因子全 NaN
...
2024-01-29 '^GSPC,^HSI,000300.SH' Top 3
2024-01-30 '^GSPC,^HSI,000300.SH' 调仓控制保持上次信号
2024-01-31 '^GSPC,000300.SH' ^HSI 动量下降被替换
...
```
---
### 阶段 4对齐收益率到 A 股日历(⭐ 关键步骤)
```python
# 对每个标的计算收益率
returns_aligned = {}
for code, df in index_data.items():
close_series = df['close']
# ✅ 使用 aligner 对齐收益率
returns = aligner.align_returns(
close_series,
code=code
)
returns_aligned[code] = returns
# 结果:
^GSPC 收益率A 股日历 244 :
日期 close(ffill) returns
2024-01-01 4770.0 0.0000 首日
2024-01-02 4780.0 0.0021 +0.21%
2024-01-03 4790.0 0.0021 +0.21%
2024-01-04 4785.0 -0.0010 -0.10%
...
2024-01-30 4810.0 ffill美股休市 0.0000 0%价格不变)✓
2024-01-31 4820.0 0.0021 +0.21%
^HSI 收益率A 股日历 244 :
日期 close(ffill) returns
2024-01-01 17050.0 0.0000 首日ffill
2024-01-02 17100.0 0.0029 +0.29%
...
2024-01-30 17200.0 ffill港股休市 0.0000 0%
000300.SH 收益率A 股日历 244 :
日期 close returns
2024-01-01 3500.0 0.0000 首日
2024-01-02 3510.0 0.0029 +0.29%
...
2024-01-30 3540.0 0.0028 +0.28%A 股正常交易
```
**CrossMarketAligner 的核心逻辑**
```python
def align_returns(self, close_series, code):
# ✅ 步骤 1价格先对齐到 A 股日历
close_aligned = close_series.reindex(
self.target_calendar,
method='ffill'
)
# 休市日价格不变ffill 填充前一天的价格)
# 例2024-01-30 美股休市close_aligned['2024-01-30'] = 4800前一日价格
# ✅ 步骤 2计算收益率
returns = close_aligned.pct_change(fill_method=None)
# 休市日:(今日价格 - 昨日价格) / 昨日价格
# = (4800 - 4800) / 4800 = 0%
# 因为 ffill 后,今日价格 = 昨日价格
# ✅ 步骤 3填充首日 NaN
returns.iloc[0] = 0.0 # 首日无前一日,收益率 = 0
# ✅ 步骤 4填充剩余 NaN如果有
returns = returns.fillna(0.0) # 用 0 填充(表示"无数据,收益率为 0"
# ✅ 步骤 5验证
self._validate_returns(returns, code)
return returns
```
**为什么这样正确?**
| 日期 | 美股状态 | 价格ffill | 收益率计算 | 结果 |
|------|----------|---------------|------------|------|
| 2024-01-29 | 正常交易 | 4800 | (4800 - 4790) / 4790 | +0.21% |
| 2024-01-30 | **休市** | 4800 (ffill) | (4800 - 4800) / 4800 | **0%** ✓ |
| 2024-01-31 | 正常交易 | 4820 | (4820 - 4800) / 4800 | +0.42% |
**对比错误做法**
```python
# ❌ 错误:先计算收益率,再 ffill
returns_wrong = close.pct_change() # 美股日历
returns_aligned = returns_wrong.reindex(a_share_dates, method='ffill')
日期 收益率美股 A股日历 对齐后收益率
2024-01-29 +0.21% 2024-01-29 +0.21%
2024-01-30 休市 2024-01-30 +0.21% 错误复制了前一天的收益率
2024-01-31 +0.42% 2024-01-31 +0.42%
# 问题A 股交易日"继承"了美股休市前一天的收益率
# 结果:净值被高估(多算了 0.21%
```
**验证逻辑**
```python
def _validate_returns(self, returns, code):
# 1. 检查 NaN 比例
nan_ratio = returns.isna().sum() / len(returns)
if nan_ratio > 0.1: # > 10%
raise ValueError(f"{code}: 收益率 NaN 比例过高 ({nan_ratio:.1%})")
# 2. 检查异常值
max_return = returns.abs().max()
if max_return > 0.5: # 单日涨跌 > 50%
warnings.warn(f"{code}: 发现异常收益率 ({max_return:.1%})")
# 3. 检查索引是否匹配目标日历
if not returns.index.equals(self.target_calendar):
raise ValueError(f"{code}: 收益率索引与目标日历不匹配")
```
---
### 阶段 5合并多标的收益率
```python
# 合并为 DataFrame
returns_df = pd.DataFrame(returns_aligned)
# 结果:
returns_dfA 股日历 244 × 3 :
日期 ^GSPC ^HSI 000300.SH
2024-01-01 0.0000 0.0000 0.0000
2024-01-02 0.0021 0.0029 0.0029
2024-01-03 0.0021 0.0029 0.0028
2024-01-04 -0.0010 -0.0018 -0.0014
...
2024-01-30 0.0000 0.0000 0.0028 美股/港股休市0%A 股正常
2024-01-31 0.0021 0.0025 0.0030
# ✅ 验证:无 NaN
assert not returns_df.isna().any().any()
```
**CrossMarketAligner 的作用**
```python
def align_multi_asset(self, close_dict):
returns_dict = {}
for code, close_series in close_dict.items():
try:
# 对每个标的调用 align_returns
returns_dict[code] = self.align_returns(close_series, code)
except Exception as e:
# 如果失败,填充全 0
warnings.warn(f"{code}: 收益率对齐失败 - {e}")
returns_dict[code] = pd.Series(0.0, index=self.target_calendar)
returns_df = pd.DataFrame(returns_dict)
# 最终验证:不能有 NaN
if returns_df.isna().any().any():
raise ValueError("收益率 DataFrame 包含 NaN这不应该发生")
return returns_df
```
---
### 阶段 6验证信号与收益率对齐
```python
# 验证
aligned_signals, aligned_returns = aligner.validate_alignment(
signals,
returns_df
)
# 内部逻辑:
def validate_alignment(self, signals, returns_df):
# 1. 找共同日期
common_dates = signals.index.intersection(returns_df.index)
# 2. 检查丢失的日期
lost_signals = len(signals) - len(common_dates)
lost_returns = len(returns_df) - len(common_dates)
if lost_signals > 0 or lost_returns > 0:
warnings.warn(
f"信号与收益率对齐丢失日期\n"
f"信号: {len(signals)}{len(common_dates)} (丢失 {lost_signals})\n"
f"收益: {len(returns_df)}{len(common_dates)} (丢失 {lost_returns})"
)
# 3. 检查对齐后日期是否太少
if len(common_dates) < 10:
raise ValueError(f"对齐后日期太少: {len(common_dates)} 天")
# 4. 裁剪到共同日期
aligned_signals = signals.loc[common_dates]
aligned_returns = returns_df.loc[common_dates]
return aligned_signals, aligned_returns
```
---
### 阶段 7计算组合收益
```python
from framework_v2.execution import BacktestExecutor
executor = BacktestExecutor(
initial_capital=100000,
trade_cost=0.001, # 0.1% 交易成本
select_num=3
)
# 执行回测
portfolio = executor.execute(aligned_signals, aligned_returns)
# 内部逻辑:
def execute(self, signals, returns_df):
nav = [self.initial_capital] # 初始净值
for date, row in signals.iterrows():
signal = row['signal'] # '^GSPC,^HSI,000300.SH'
if not signal or signal == '':
# 空信号,持有现金
daily_return = 0.0
else:
# 解析信号
codes = signal.split(',')
# 获取当日收益率
daily_returns = [
returns_df.loc[date, code]
for code in codes
]
# 等权平均
daily_return = np.mean(daily_returns)
# 扣除交易成本
daily_return -= self.trade_cost
# 更新净值
new_nav = nav[-1] * (1 + daily_return)
nav.append(new_nav)
return pd.DataFrame({
'nav': nav[1:],
'daily_return': ...
})
```
**示例计算**
```
日期 signal 收益率计算 净值
2024-01-29 ^GSPC,^HSI,000300.SH (0.16+0.15+0.14)/3-0.001 100,000 → 100,048
2024-01-30 ^GSPC,^HSI,000300.SH (0.00+0.00+0.28)/3-0.001 100,048 → 100,047
↑ 美股/港股休市0%
2024-01-31 ^GSPC,000300.SH (0.21+0.30)/2-0.001 100,047 → 100,072
↑ 只持有 2 只标的
```
---
## 📊 完整数据流图
```
原始 OHLCV不同日历
├─ ^GSPC (252 天,美股日历)
├─ ^HSI (250 天,港股日历)
└─ 000300.SH (244 天A 股日历)
├──────────────────────────────────────────────┐
│ 阶段 1因子计算原始日历
│ factor.compute(df) │
│ → 在各自日历计算 rolling(25) │
│ → 使用真实交易日25 天) │
└──────────────────────────────────────────────┘
├─ ^GSPC 因子 (252 天,美股日历)
├─ ^HSI 因子 (250 天,港股日历)
└─ 000300.SH 因子 (244 天A 股日历)
├──────────────────────────────────────────────┐
│ 阶段 2CrossMarketAligner.align_factor() │
│ → reindex(a_share_dates, method='ffill') │
│ → 标记 is_filled哪些是填充值
│ → 验证 NaN 比例(> 10% 警告) │
│ → 验证填充比例(> 30% 警告) │
└──────────────────────────────────────────────┘
├─ ^GSPC 因子 (244 天A 股日历)
├─ ^HSI 因子 (244 天A 股日历)
└─ 000300.SH 因子 (244 天A 股日历)
┌─ 合并为 factor_df (244 天 × 3 列)
├──────────────────────────────────────────────┐
│ 阶段 3信号生成 │
│ selector.generate(factor_df) │
│ → Top 3 选股(跳过 NaN
│ → 调仓控制(每 N 天调仓) │
└──────────────────────────────────────────────┘
└─ signals DataFrame (244 天)
signal逗号分隔的标的代码
├──────────────────────────────────────────────┐
│ 阶段 4CrossMarketAligner.align_returns() │
│ → close.reindex(a_share_dates, ffill) │
│ → pct_change(fill_method=None) │
│ → 休市日收益率 = 0%(价格不变) │
│ → 验证 NaN 比例(> 10% 报错) │
│ → 验证异常值(> 50% 警告) │
│ → 验证索引一致性 │
└──────────────────────────────────────────────┘
├─ ^GSPC 收益率 (244 天A 股日历)
├─ ^HSI 收益率 (244 天A 股日历)
└─ 000300.SH 收益率 (244 天A 股日历)
┌─ 合并为 returns_df (244 天 × 3 列)
├──────────────────────────────────────────────┐
│ 阶段 5CrossMarketAligner.validate_alignment()│
│ → intersection(共同日期) │
│ → 裁剪到共同日期 │
│ → 验证日期一致性(丢失 > 0 警告) │
│ → 验证最小日期数(< 10 报错) │
└──────────────────────────────────────────────┘
├─ aligned_signals (N 天N ≤ 244)
└─ aligned_returns (N 天)
├──────────────────────────────────────────────┐
│ 阶段 6执行回测 │
│ executor.execute(signals, returns) │
│ → 解析信号(逗号分隔 → 列表) │
│ → 等权组合np.mean
│ → 扣除交易成本 │
│ → 计算净值曲线 │
└──────────────────────────────────────────────┘
└─ 最终结果
├─ 净值曲线DataFrame
├─ 日收益率Series
└─ 绩效指标(年化收益、夏普、最大回撤)
```
---
## 🎯 CrossMarketAligner 的核心价值
### 解决的问题
| 问题 | 严重度 | 表现 | Aligner 的解决方案 |
|------|--------|------|-------------------|
| **跨市场日历不同** | 🔴 严重 | 因子/收益无法直接合并 | align_factor() reindex + ffill |
| **ffill 收益率陷阱** | 🔴 严重 | 休市日复制非零收益率 | align_returns() 先对齐价格 |
| **NaN 传播** | 🔴 严重 | 组合收益变 NaN | fillna(0.0) + 严格验证 |
| **信号与收益不对齐** | 🟡 中等 | 回测丢失日期 | validate_alignment() 裁剪 |
| **异常值未检测** | 🟡 中等 | 单日涨跌 > 50% | max_return 验证 |
| **填充值未知** | 🟢 轻微 | 无法评估数据质量 | is_filled 标记 |
### 关键设计决策
#### 1. 为什么因子在原始日历计算?
```python
# ✅ 正确:在原始日历计算
factor = close.rolling(25).apply(weighted_momentum) # 25 个真实交易日
aligned = factor.reindex(a_share_dates, method='ffill')
# ❌ 错误:先对齐再计算
close_aligned = close.reindex(a_share_dates, method='ffill')
factor = close_aligned.rolling(25).apply(...) # 包含 2-3 个重复值!
```
**原因**
- rolling window 需要**真实交易日**25 天)
- ffill 会引入重复值,影响线性回归权重
- 对齐的是**因子值**,不是价格
#### 2. 为什么收益率要先对齐价格?
```python
# ✅ 正确:先对齐价格,再计算收益率
close_aligned = close.reindex(a_share_dates, method='ffill')
returns = close_aligned.pct_change() # 休市日 = 0%
# ❌ 错误:先计算收益率,再对齐
returns = close.pct_change()
returns_aligned = returns.reindex(a_share_dates, method='ffill') # 复制非零收益率!
```
**原因**
- 休市日价格不变 → 收益率 = 0%
- 如果先计算收益率ffill 会复制前一天的非零收益率
- 导致净值高估/低估
#### 3. 为什么标记 is_filled
```python
aligned = aligner.align_factor(...)
# aligned['is_filled'] = True/False
```
**用途**
- 分析哪些因子值是"真实计算"的
- 哪些是"ffill 填充"的
- 可以统计填充比例,评估数据质量
- 后续可用于加权(真实值权重更高)
---
## 📈 验证测试
### 测试覆盖
```
✓ 测试 1: 因子对齐 - 填充值正确标记
✓ 测试 2: 收益率对齐 - 休市日收益率 = 0%
✓ 测试 3: 多标的对齐 - 无 NaN索引一致
✓ 测试 4: 信号与收益对齐 - 日期裁剪验证
✓ 测试 5: ffill 陷阱对比 - 错误 vs 正确做法
总计: 5/5 通过
```
### 关键验证点
```python
# 1. 休市日收益率 = 0%
assert returns['2024-01-30'] == 0.0 # 美股休市
# 2. 无 NaN
assert not returns_df.isna().any().any()
# 3. 索引一致
assert aligned_signals.index.equals(aligned_returns.index)
# 4. 填充值标记
assert aligned.loc['2024-01-30', 'is_filled'] == True # 美股休市
# 5. NaN 比例 < 10%
nan_ratio = factor_df.isna().sum() / len(factor_df)
assert (nan_ratio < 0.1).all()
```
---
## 🔧 使用示例
### 完整代码
```python
from framework_v2.shared.data.alignment import CrossMarketAligner
from framework_v2.shared.factors import MomentumFactor
from framework_v2.shared.signals import TopNSelector
from framework_v2.execution import BacktestExecutor
# 1. 获取数据
index_data = {
'^GSPC': df_sp500, # 美股日历
'^HSI': df_hsi, # 港股日历
'000300.SH': df_hs300 # A 股日历
}
a_share_dates = pd.date_range('2020-01-01', '2024-01-01', freq='B') # 示例
# 2. 创建对齐器
aligner = CrossMarketAligner(target_calendar=a_share_dates)
# 3. 计算因子(原始日历)
factor = MomentumFactor(n_days=25, weighted=True, crash_filter=True)
factor_raw = {
code: factor.compute(df)
for code, df in index_data.items()
}
# 4. 对齐因子到 A 股日历
factor_aligned = {
code: aligner.align_factor(
factor_raw[code],
source_calendar=index_data[code].index,
code=code
)['value']
for code in index_data.keys()
}
# 5. 生成信号
factor_df = pd.DataFrame(factor_aligned)
selector = TopNSelector(select_num=3, min_score=0.0)
signals = selector.generate(factor_df)
# 6. 对齐收益率到 A 股日历
returns_df = aligner.align_multi_asset({
code: df['close']
for code, df in index_data.items()
})
# 7. 验证信号与收益率对齐
aligned_signals, aligned_returns = aligner.validate_alignment(
signals,
returns_df
)
# 8. 执行回测
executor = BacktestExecutor(
initial_capital=100000,
trade_cost=0.001,
select_num=3
)
portfolio = executor.execute(aligned_signals, aligned_returns)
# 9. 查看结果
print(f"最终净值: {portfolio['nav'].iloc[-1]:,.2f}")
print(f"年化收益: {portfolio['annual_return']:.2%}")
print(f"夏普比率: {portfolio['sharpe_ratio']:.2f}")
print(f"最大回撤: {portfolio['max_drawdown']:.2%}")
```
---
## 📝 注意事项
1. **填充值标记**`is_filled` 列标记哪些是 ffill 填充的,可用于后续分析
2. **NaN 处理**:收益率对齐后自动填充为 0表示"无数据,收益率为 0"
3. **异常检测**:单日收益率 > 50% 会发出警告
4. **索引验证**:对齐后严格验证索引是否匹配目标日历
5. **统计信息**:通过 `aligner.get_stats()` 获取对齐统计
6. **性能优化**:避免在循环中多次 reindex批量处理更高效
---
## 🔗 相关文档
- **[数据架构方案](DATA_ARCHITECTURE.md)** - 完整的数据架构设计Schema、验证、性能优化
- **[跨市场对齐方案](ALIGNMENT_GUIDE.md)** - CrossMarketAligner 使用指南
- **[框架 V2 README](README.md)** - 框架总览
---
*创建日期: 2026-05-06*
*版本: 1.0.0*