diff --git a/scripts/generate_legacy_report.py b/scripts/generate_legacy_report.py index f377c4d..ac4ab67 100644 --- a/scripts/generate_legacy_report.py +++ b/scripts/generate_legacy_report.py @@ -71,17 +71,25 @@ def run_with_legacy_report(): # 1. 基准净值和基准日收益率 benchmark_data = data.get('benchmark_data') - if benchmark_data is not None and not benchmark_data.empty: - # 对齐基准数据到回测日期 - benchmark_close = benchmark_data['close'] if 'close' in benchmark_data.columns else benchmark_data.iloc[:, 0] - benchmark_close_aligned = benchmark_close.reindex(backtest_result.index, method='ffill') + if benchmark_data is not None: + # benchmark_data 已经是 Series(close 价格) + if isinstance(benchmark_data, pd.Series): + benchmark_close = benchmark_data + elif isinstance(benchmark_data, pd.DataFrame): + benchmark_close = benchmark_data['close'] if 'close' in benchmark_data.columns else benchmark_data.iloc[:, 0] + else: + benchmark_close = None - # 计算基准净值 - benchmark_nav = (1 + benchmark_close_aligned.pct_change()).cumprod() - benchmark_nav = benchmark_nav / benchmark_nav.dropna().iloc[0] # 归一化起点为1 - - backtest_result['基准净值'] = benchmark_nav.values - backtest_result['基准日收益率'] = benchmark_close_aligned.pct_change().values + if benchmark_close is not None and len(benchmark_close) > 0: + # 对齐基准数据到回测日期 + benchmark_close_aligned = benchmark_close.reindex(backtest_result.index, method='ffill') + + # 计算基准净值 + benchmark_nav = (1 + benchmark_close_aligned.pct_change()).cumprod() + benchmark_nav = benchmark_nav / benchmark_nav.dropna().iloc[0] # 归一化起点为1 + + backtest_result['基准净值'] = benchmark_nav.values + backtest_result['基准日收益率'] = benchmark_close_aligned.pct_change().values # 2. 各标的净值(指数价格)- 使用index_data而非index_close # index_close可能对齐有问题,直接从index_data获取 @@ -143,14 +151,26 @@ def run_with_legacy_report(): price_aligned = etf_data[etf_code].reindex(backtest_result.index, method='ffill') etf_price_data[idx_code] = price_aligned.values - if etf_nav_data is not None: - # ETF净值数据列名是ETF代码,需要用etf_code_map映射 - # 并对齐到回测日期 + # ETF净值数据现在是字典格式 {etf_code: DataFrame} + etf_nav_data_raw = None + + if etf_nav_data and len(etf_nav_data) > 0: + # etf_nav_data 是字典 {etf_code: DataFrame} etf_nav_data_raw = pd.DataFrame(index=backtest_result.index) for idx_code, etf_code in etf_code_map.items(): - if etf_code in etf_nav_data.columns: + if etf_code in etf_nav_data: + # 从字典中获取净值 DataFrame + nav_df = etf_nav_data[etf_code] + if isinstance(nav_df, pd.DataFrame) and 'nav' in nav_df.columns: + nav_series = nav_df['nav'] + elif isinstance(nav_df, pd.DataFrame): + nav_series = nav_df.iloc[:, 0] + elif isinstance(nav_df, pd.Series): + nav_series = nav_df + else: + continue # 对齐净值数据到回测日期(使用ffill处理日期差异) - nav_aligned = etf_nav_data[etf_code].reindex(backtest_result.index, method='ffill') + nav_aligned = nav_series.reindex(backtest_result.index, method='ffill') etf_nav_data_raw[idx_code] = nav_aligned.values # 生成原引擎格式的报告