From 28f3ddcd4ffc52dc0d86f006936eaf6afb02fe83 Mon Sep 17 00:00:00 2001 From: aszerW Date: Sat, 16 May 2026 00:52:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(strategy):=20=E6=94=B6=E7=9B=8A=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E6=94=B9=E4=B8=BA=E4=BD=BF=E7=94=A8=E6=8C=87=E6=95=B0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 原逻辑: 优先使用ETF价格计算收益,导致回测起点被ETF最早日期限制(2011-12-09) - 新逻辑: 使用指数数据计算收益,可从2000年开始回测(8240天) - ETF数据仅用于报告显示溢价率,不参与收益计算 - 注意: 2000-2005年只有7只标的有数据,分散度不足导致净值下跌48% --- strategies/rotation/strategy.py | 44 +++++++++++++-------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/strategies/rotation/strategy.py b/strategies/rotation/strategy.py index b08d7c3..310457b 100644 --- a/strategies/rotation/strategy.py +++ b/strategies/rotation/strategy.py @@ -406,35 +406,25 @@ class RotationStrategy(StrategyBase): # 4. 执行回测 print("\n执行回测...") - # 获取ETF数据和代码映射 - etf_data = data.get('etf_data') - etf_code_map = data.get('etf_code_map', {}) # {指数代码: ETF代码} + # 获取指数收盘价数据(用于收益计算) + index_close = data.get('index_close') - # 计算日收益率(使用ETF价格数据,匹配原引擎逻辑) - if etf_data is not None and not etf_data.empty: - # 使用ETF价格计算收益,列名保持指数代码格式 - returns_data = {} - for idx_code in valid_codes: - etf_code = etf_code_map.get(idx_code, idx_code) - if etf_code in etf_data.columns: - returns_data[f'日收益率_{idx_code}'] = etf_data[etf_code].pct_change(fill_method=None) - returns_df = pd.DataFrame(returns_data) + # 计算日收益率(使用指数数据,可从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_close = data.get('index_close') - 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: - returns_data = {} - for code in valid_codes: - if code in index_data: - df = index_data[code] - returns_data[f'日收益率_{code}'] = df['close'].pct_change() - returns_df = pd.DataFrame(returns_data) - if valid_codes: - first_code = valid_codes[0] - returns_df.index = index_data[first_code].index + # 回退:从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 # 确保信号和收益率数据日期对齐 common_dates = signals.index.intersection(returns_df.index)