From 6ccb121764400206ba6aa1609a53f704fe431e54 Mon Sep 17 00:00:00 2001 From: aszerW Date: Sat, 16 May 2026 01:23:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(strategy):=20=E4=BF=AE=E5=A4=8D=E6=94=B6?= =?UTF-8?q?=E7=9B=8A=E7=8E=87=E8=AE=A1=E7=AE=97=E4=BA=A4=E6=98=93=E6=97=A5?= =?UTF-8?q?=E4=B8=8D=E5=AF=B9=E9=BD=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: 指数数据使用各市场原始交易日,直接pct_change导致大量NaN 修复: 先在原始交易日历计算收益率,再用ffill对齐到A股日历 效果: 收益从44.55%恢复到11961.88%(年化15.7%,26年周期) --- strategies/rotation/strategy.py | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/strategies/rotation/strategy.py b/strategies/rotation/strategy.py index 310457b..a2c2fec 100644 --- a/strategies/rotation/strategy.py +++ b/strategies/rotation/strategy.py @@ -406,25 +406,25 @@ class RotationStrategy(StrategyBase): # 4. 执行回测 print("\n执行回测...") - # 获取指数收盘价数据(用于收益计算) - index_close = data.get('index_close') + # 获取A股交易日历(从因子数据索引) + a_share_dates = signals.index - # 计算日收益率(使用指数数据,可从2000年开始) - # ETF数据仅用于报告显示溢价率,不参与收益计算 - if index_close is not None and not index_close.empty: - returns_df = index_close.pct_change() - returns_df.columns = [f'日收益率_{col}' for col in returns_df.columns] - else: - # 回退:从index_data提取收盘价 - returns_data = {} - for code in valid_codes: - if code in index_data: - df = index_data[code] - returns_data[f'日收益率_{code}'] = df['close'].pct_change(fill_method=None) - returns_df = pd.DataFrame(returns_data) - if valid_codes: - first_code = valid_codes[0] - returns_df.index = index_data[first_code].index + # 计算日收益率:先在原始交易日历计算,再对齐到A股日历 + # 关键:与因子计算逻辑一致,避免交易日不对齐导致收益率NaN + returns_data = {} + for code in valid_codes: + if code in index_data: + df = index_data[code] + # 提取原始收盘价序列 + if 'close' in df.columns: + close_series = df['close'].dropna() + # 先在原始交易日历计算收益率 + returns_series = close_series.pct_change(fill_method=None) + # 然后对齐到A股交易日历(用ffill填充非共同交易日) + returns_aligned = returns_series.reindex(a_share_dates, method='ffill') + returns_data[f'日收益率_{code}'] = returns_aligned + + returns_df = pd.DataFrame(returns_data) # 确保信号和收益率数据日期对齐 common_dates = signals.index.intersection(returns_df.index)