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:
@@ -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 = []
|
||||
|
||||
Reference in New Issue
Block a user