#!/usr/bin/env python3 """ 验证 ETF 数据获取修复 测试点: 1. 指数数据使用 adj='raw' 2. ETF 数据使用 adj='hfq' 3. 数据字典中同时包含指数和 ETF """ import sys from pathlib import Path # 添加项目根目录到路径 project_root = Path(__file__).parent.parent.parent sys.path.insert(0, str(project_root)) from framework_v2.config import load_config from framework_v2.strategies.rotation.rotation import GlobalRotationStrategy def main(): print("=" * 70) print(" 验证 ETF 数据获取修复") print("=" * 70) # 加载配置 config_path = project_root / 'framework_v2' / 'config' / 'rotation_global.yaml' print(f"\n加载配置: {config_path}") config = load_config(str(config_path)) # 初始化策略 strategy = GlobalRotationStrategy(config) # 获取数据 print("\n" + "=" * 70) print("获取数据...") print("=" * 70) data = strategy.get_data() # 分析数据结构 print("\n" + "=" * 70) print("数据结构分析") print("=" * 70) # 获取映射关系 signal_to_trade = config.asset_pools.get_signal_to_trade_mapping() signal_codes = config.asset_pools.get_signal_codes() trade_codes = set(signal_to_trade.values()) print(f"\n信号标的(指数): {len(signal_codes)} 只") for code in sorted(signal_codes): if code in data: df = data[code] has_hfq = 'close_hfq' in df.columns if 'close' in df.columns else False print(f" ✓ {code}: {len(df)} 条, 有 close_hfq: {has_hfq}") else: print(f" ✗ {code}: 数据缺失") print(f"\n交易标的(ETF): {len(trade_codes)} 只") for code in sorted(trade_codes): if code in data: df = data[code] has_nav = 'nav' in df.attrs has_premium = 'premium_series' in df.attrs print(f" ✓ {code}: {len(df)} 条") print(f" close (最新): {df['close'].iloc[-1]:.4f}") print(f" 有 nav: {has_nav}") print(f" 有 premium: {has_premium}") else: print(f" ✗ {code}: 数据缺失") # 验证关键指标 print("\n" + "=" * 70) print("验证结果") print("=" * 70) # 检查指数数据 index_ok = all(code in data for code in signal_codes) print(f"\n指数数据完整性: {'✓ 全部获取' if index_ok else '✗ 部分缺失'}") # 检查 ETF 数据 etf_ok = all(code in data for code in trade_codes) print(f"ETF 数据完整性: {'✓ 全部获取' if etf_ok else '✗ 部分缺失'}") # 检查 ETF 是否使用 hfq(对比 raw 和 hfq 的价格差异) print("\n验证 ETF 是否使用 hfq(抽样检查)...") from framework_v2.shared.data import FlaskAPIFetcher fetcher = FlaskAPIFetcher() etf_hfq_verified = 0 sample_codes = list(trade_codes)[:3] # 抽样前3个 # 获取日期范围 from datetime import date start = config.backtest.start_date end = config.backtest.end_date if end is None: end = date.today().strftime('%Y-%m-%d') for code in sample_codes: if code in data: hfq_close = data[code]['close'].iloc[-1] # 获取 raw 数据对比 raw_df = fetcher._source.fetch(code, start, end, adj='raw', asset_type='china_etf') if raw_df is not None: raw_close = raw_df['close'].iloc[-1] ratio = hfq_close / raw_close if raw_close > 0 else 1 if ratio > 1.01: # 差异超过1%说明使用了 hfq print(f" ✓ {code}: raw={raw_close:.4f}, hfq={hfq_close:.4f}, 倍数={ratio:.4f} (正确)") etf_hfq_verified += 1 else: print(f" ✗ {code}: raw={raw_close:.4f}, hfq={hfq_close:.4f}, 倍数={ratio:.4f} (错误)") print(f"ETF 使用 hfq: {etf_hfq_verified}/{len(sample_codes)} {'✓ 正确' if etf_hfq_verified == len(sample_codes) else '✗ 错误'}") # 总结 print("\n" + "=" * 70) if index_ok and etf_ok and etf_hfq_verified == len(sample_codes): print("✓ 验证通过:数据获取逻辑正确") print(" - 指数使用 raw(原始价格)") print(" - ETF 使用 hfq(后复权价格)") else: print("✗ 验证失败:数据获取存在问题") print("=" * 70) if __name__ == '__main__': main()