diff --git a/strategies/rotation/strategy.py b/strategies/rotation/strategy.py index 7b27941..48d8c38 100644 --- a/strategies/rotation/strategy.py +++ b/strategies/rotation/strategy.py @@ -144,28 +144,46 @@ class RotationStrategy(StrategyBase): } def compute_factors(self, data: dict) -> pd.DataFrame: - """计算因子值""" + """计算因子值(匹配原引擎:境外数据对齐到A股交易日历后再计算因子)""" index_data = data['index_data'] valid_codes = data['valid_codes'] + # 获取A股交易日历作为基准(使用已有的对齐后数据索引) + index_close = data.get('index_close') + if index_close is not None: + a_share_dates = index_close.index + else: + # 回退:使用第一个A股标的的索引 + for code in valid_codes: + if code.endswith('.SH') or code.endswith('.SZ') or code.endswith('.CSI'): + a_share_dates = index_data[code].index + break + else: + a_share_dates = index_data[valid_codes[0]].index + factor_values = {} final_valid_codes = [] for code in valid_codes: df = index_data[code] - # 只使用 close 列计算因子(匹配原引擎逻辑:部分指数只有收盘价) + # 只使用 close 列(匹配原引擎逻辑) if 'close' in df.columns: close_series = df['close'].dropna() else: close_series = df.dropna() - # 原引擎剔除逻辑:close 数据需要至少 n_days + 1 条 - if len(close_series) < self.n_days + 1: - print(f" ⚠ 剔除 {code}: 数据不足 ({len(close_series)} < {self.n_days + 1})") + # 关键:对齐到A股交易日历(匹配原引擎逻辑) + # 境外市场的交易日与A股不同,需要前向填充到A股交易日 + close_aligned = close_series.reindex(a_share_dates, method='ffill') + + # 原引擎剔除逻辑:对齐后的数据需要至少 n_days + 1 条有效值 + valid_count = close_aligned.notna().sum() + if valid_count < self.n_days + 1: + print(f" ⚠ 剔除 {code}: 数据不足 ({valid_count} < {self.n_days + 1})") continue - # 只传入 close 列给因子计算器 - close_df = pd.DataFrame({'close': close_series}) + # 在对齐后的数据上计算因子 + close_df = pd.DataFrame({'close': close_aligned}) values = self._factor.compute(close_df) factor_values[code] = values final_valid_codes.append(code)