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)