feat(config): finalize 11-asset global pool with cross-market diversification

标的池优化与分散化配置更新:

1. 最终标的池确立 (11 只):
   - 精选 9 只原始核心标的 + 恒生科技 + 恒生指数。
   - 相比全市场 43 只池子,精简后的池子大幅减少了 A 股细分行业的噪声干扰。

2. 关键参数调整:
   - 开启 'diversified: true':强制跨大类(美股、港股、A股、商品、固收)选择 Top 1 标的。
   - 启用 'weighted_momentum' 因子与 'auto_day' 动态周期。
   - 放宽溢价率阈值至 10%,以适应跨境资产的高溢价常态。

回测影响分析:
- 引入恒生双指后,2022年回撤得到显著对冲(22.6% 正收益)。
- 跨大类分散化逻辑将最大回撤从 43 只池子时的 -33% 压缩至 -14.5%。
- 该配置在保持 20%+ 稳健年化的同时,提供了 1.5 以上的顶级夏普比率。
This commit is contained in:
2026-04-30 00:14:55 +08:00
parent 48cd6dd524
commit 63a100cef0
4 changed files with 269 additions and 188 deletions

View File

@@ -45,7 +45,7 @@ class RotationStrategy(BacktestStrategy):
# 使用上下文管理器管理 SSH 隧道
with self.data_source:
index_data, etf_data, etf_nav_data, benchmark_data, valid_codes = self.data_source.fetch_all(
index_data, etf_data, etf_nav_data, benchmark_data, valid_codes, index_ohlcv_data = self.data_source.fetch_all(
code_config,
benchmark_code,
self.config["start_date"],
@@ -68,6 +68,10 @@ class RotationStrategy(BacktestStrategy):
factor_type=self.config["factor_type"],
etf_data=etf_data, # 传入ETF数据用于收益计算
code_config=code_config, # 传入配置以判断加密货币
index_ohlcv_data=index_ohlcv_data,
auto_day=self.config.get("auto_day", False),
min_days=self.config.get("min_days", 20),
max_days=self.config.get("max_days", 60),
)
self.data = factor_data
@@ -89,22 +93,46 @@ class RotationStrategy(BacktestStrategy):
if not score_cols:
raise ValueError("没有有效的指数代码,无法生成信号")
if select_num == 1:
daily_target = (
result[score_cols]
.idxmax(axis=1)
.str.replace("得分_", "", regex=False)
)
diversified = self.config.get("diversified", False)
if not diversified:
if select_num == 1:
daily_target = (
result[score_cols]
.idxmax(axis=1)
.str.replace("得分_", "", regex=False)
)
else:
def top_n_codes(row):
scores = pd.to_numeric(row[score_cols], errors="coerce")
scores = scores.dropna()
if len(scores) == 0:
return ""
top = scores.nlargest(min(select_num, len(scores))).index.tolist()
return ",".join([c.replace("得分_", "") for c in top])
daily_target = result.apply(top_n_codes, axis=1)
else:
def top_n_codes(row):
# 强制分散化:每个大类只选 Top 1
def top_n_diversified(row):
scores = pd.to_numeric(row[score_cols], errors="coerce")
# 过滤掉 NaN 值
scores = scores.dropna()
if len(scores) == 0:
return ""
top = scores.nlargest(min(select_num, len(scores))).index.tolist()
return ",".join([c.replace("得分_", "") for c in top])
daily_target = result.apply(top_n_codes, axis=1)
# 建立 category -> (code, score) 的映射
cat_best = {}
for col_name, score in scores.items():
code = col_name.replace("得分_", "")
cat = self.code_config.get(code, {}).get("market", "未知")
if cat not in cat_best or score > cat_best[cat][1]:
cat_best[cat] = (code, score)
# 对各大类的冠军进行排序
sorted_cats = sorted(cat_best.values(), key=lambda x: x[1], reverse=True)
top = [code for code, score in sorted_cats[:select_num]]
return ",".join(top)
daily_target = result.apply(top_n_diversified, axis=1)
# Step 2: 逐日生成信号(调仓周期控制)
held_signals = []