diff --git a/datasource/hybrid_source.py b/datasource/hybrid_source.py index 0be74d0..be411a7 100644 --- a/datasource/hybrid_source.py +++ b/datasource/hybrid_source.py @@ -200,7 +200,7 @@ class HybridDataSource: etf_data_list.append(etf_data[['code', 'close']]) price_count = len(etf_data) - nav_count = len(etf_nav) if etf_nav else 0 + nav_count = len(etf_nav) if etf_nav is not None else 0 print(f"✓ 价格{price_count}条 净值{nav_count}条") else: @@ -214,17 +214,32 @@ class HybridDataSource: index_data = None if index_data_list: index_data = pd.concat(index_data_list) - index_data = index_data.pivot(columns='code', values='close') + if 'code' in index_data.columns and 'close' in index_data.columns: + index_data = index_data.reset_index() + if 'index' in index_data.columns: + index_data = index_data.rename(columns={'index': 'date'}) + index_data['date'] = pd.to_datetime(index_data['date']).dt.normalize() + index_data = index_data.pivot_table(index='date', columns='code', values='close') etf_data = None if etf_data_list: etf_data = pd.concat(etf_data_list) - etf_data = etf_data.pivot(columns='code', values='close') + if 'code' in etf_data.columns and 'close' in etf_data.columns: + etf_data = etf_data.reset_index() + if 'index' in etf_data.columns: + etf_data = etf_data.rename(columns={'index': 'date'}) + etf_data['date'] = pd.to_datetime(etf_data['date']).dt.normalize() + etf_data = etf_data.pivot_table(index='date', columns='code', values='close') etf_nav_data = None if etf_nav_data_list: etf_nav_data = pd.concat(etf_nav_data_list) - etf_nav_data = etf_nav_data.pivot(columns='code', values='nav') + if 'code' in etf_nav_data.columns and 'nav' in etf_nav_data.columns: + etf_nav_data = etf_nav_data.reset_index() + if 'index' in etf_nav_data.columns: + etf_nav_data = etf_nav_data.rename(columns={'index': 'date'}) + etf_nav_data['date'] = pd.to_datetime(etf_nav_data['date']).dt.normalize() + etf_nav_data = etf_nav_data.pivot_table(index='date', columns='code', values='nav') # 基准数据 benchmark_data = self._tushare.fetch_index(benchmark_code, start_date, end_date) diff --git a/datasource/tushare_source.py b/datasource/tushare_source.py index 71551c4..0ba9ce4 100644 --- a/datasource/tushare_source.py +++ b/datasource/tushare_source.py @@ -104,13 +104,14 @@ class TushareSource: original_proxy = self._clear_proxy() try: + import tushare as ts pro = self._get_pro_api() - df = pro.futures_daily( + # 使用 fut_daily 接口 + df = pro.fut_daily( ts_code=code, start_date=start_date.replace("-", ""), - end_date=end_date.replace("-", ""), - exchange='' + end_date=end_date.replace("-", "") ) if df is None or len(df) == 0: diff --git a/strategies/rotation/strategy.py b/strategies/rotation/strategy.py index ad86c44..a475e4e 100644 --- a/strategies/rotation/strategy.py +++ b/strategies/rotation/strategy.py @@ -197,14 +197,33 @@ class RotationStrategy(StrategyBase): # 4. 执行回测 print("\n执行回测...") - returns_data = {} - first_code = valid_codes[0] - for code in valid_codes: - df = index_data[code] - returns_data[f'日收益率_{code}'] = df['close'].pct_change() - returns_df = pd.DataFrame(returns_data) - returns_df.index = index_data[first_code].index + # 使用对齐后的指数收盘价数据获取日期基准 + 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 + + # 确保信号和收益率数据日期对齐 + common_dates = signals.index.intersection(returns_df.index) + signals = signals.loc[common_dates] + returns_df = returns_df.loc[common_dates] + + print(f" 对齐后日期: {len(common_dates)} 天") executor = BacktestExecutor( initial_capital=100000,