← 文档库
📄 文档learn/截面选基-理解手册/06-仓位满仓化与择时联动方案.md
🌱 创建于2026-08-07 23:29
✏️ 修改于2026-08-07 23:29
👁️ 浏览量—
🔗 短链接/~learn/s/9c191a0c
🔐 可见性

仓位满仓化与择时联动方案(v3)

> 日期:2026-07-15(v3 根据 review 反馈修订:术语修正+执行摘要) > 状态:方案设计(待你确认以下8个决策点后即可开始实施)

---

📋 执行摘要(先看这里)

一句话问题

A股择时冰点时,你的择时策略已经把A股仓位压下来了,但系统固定选Top10、不会往后找替补ETF,导致大量资金变成现金躺着。

一句话方案

废弃全局exposure_cap(沪深300一刀切),把"引擎选Top10 → 推送阶段乘择时/趋势/溢价系数"两段割裂流程合并为一个"全池评分排序 → 五关过滤 → 动态递补到95%满仓"的一体化分配器。 任何一只ETF被择时缩仓、被溢价归零、被同质化剔除,资金自动向后递补下一个合格候选,直到打满95%仓位。

新方案做3件事

需要你拍板的8个决策(默认值已给出,无异议即可直接按默认值实施)

# 决策项 默认值 你的选择
----------------------------
1 最低评分阈值(低于此分数宁可持现金不递补) 0.35(sigmoid后分数)
2 单只ETF仓位上限 15%(代理锚定10%)
3 总仓位目标(保留多少现金) 95%(5%现金缓冲)
4 同质化相关阈值(同子类别内超过此值只留评分最高的) 0.90(不同子类别不互斥,QQQ/SPY可共存)
5 置信度计算窗口(ETF↔anchor收益率相关的天数) 60日(约一个季度)
6 代理锚定ETF单只上限(未建策略池的市场用代理锚定) 10%
7 置信度现在只展示不参与权重缩放? 是(先观察分布再决定)
8 周中溢价飙升是否触发换仓? 否(统一周五再平衡,初版保持简单)

待办事项(不需要你决策,我会按优先级推进)

预期效果

场景 现状资金利用率 新方案资金利用率
----------------------------------
A股熊市、海外分化(当前) ~20-40% ~80-90%
A股熊市+QDII高溢价 ~15-25% ~60-80%(溢价品种自动跳过递补)
A股震荡、海外强势 ~50-60% ~90-95%
全球熊市 ~15-30% ~30-50%(择时全面冰点时仍持现金)

---

一、问题诊断:为什么资金会空置?

你的择时策略一直都在跑、在乘权重,并不是"悬空未用"。经过对全项目代码的逐行梳理,问题的真正根源是:择时系数乘完之后仓位缩小了,但缩小后腾出来的资金没有"递补机制"去填补,导致现金闲置。

具体来说,当前系统存在四个结构性缺陷:

1.1 缺陷一:全局 exposure_cap(沪深300独家决定)还在额外一刀切

虽然每个ETF在 show_marker.py 推送阶段已经乘以了各自锚定指数的 timing_coef,但在 selection/engine.py 的 _compute_portfolio_weights() 中,还额外存在一个由沪深300单基准决定的全局 exposure_cap(0.15~1.0),在 timing 乘法之前就先把所有ETF等比例压缩了。

# 现行 engine.py 逻辑:先全局砍一刀
top_rows['缩减后权重'] = top_rows['建议权重'] * exposure_cap  # 沪深300决定
# 然后 show_marker.py 再逐只乘 timing_coef(各锚定的择时策略仓位)
actual_pos = adj_weight * timing_coef * trend_ratio * prem_coef

这意味着:即使美股择时策略说仓位 100%,如果沪深300判定BEAR(cap=0.3),美股ETF也只能拿到 10% × 0.3 × 1.0 = 3% 的权重,而不是应有的 10%。这个全局 cap 是多余的、与分市场择时重复且矛盾的。

1.2 缺陷二:择时缩仓后没有递补,腾出来的资金直接变现金

当前流程是:

关键断点:第4步乘法之后,某些ETF(尤其是A股锚定的)权重被压到非常小(甚至被prem_coef压到0),但系统不会回头去候选池里找第11、12、13名递补。结果:

简单说:选谁(Top10)是一锤子买卖,后面不管timing/溢价怎么压,都不再扩充候选,空位就是现金。

1.3 缺陷三:锚定指数映射粒度过粗,部分市场没有独立锚定

engine.py 和 show_marker.py 中的锚定映射:

日股ETF、印度ETF、欧洲ETF、原油ETF都没有独立的锚定指数,它们共用QQQ/GLD的择时信号,无法做到"日股可投就加仓日股、日股择时差就跳过"的精细控制。

1.4 缺陷四:QDII溢价归零时没有递补

现有代码中 prem_coef 已经实现了溢价加权逻辑(show_marker.py:L2646):溢价太高的QDII仓位会被压到接近0(如溢价>7%时仓位≈0)。但这同样没有触发递补——某只ETF因为溢价被砍掉的仓位,不会自动分给下一个候选。

---

二、现有资金分配流程(现状)

周五收盘截面引擎 (selection/engine.py):
  ① 5因子打分 → sigmoid锐化 → 全池排名
  ② 沪深300单基准判定 regime → 全局 exposure_cap(0.15~1.0)
  ③ 取Top10 → 等权或评分加权 → 建议权重
  ④ 所有建议权重 × exposure_cap(一刀砍)
  ⑤ 区域上限再平衡(A股≤40%×cap、港股≤30%×cap 等)
  ⑥ 溢出权重在当前Top10内其他区域按评分分配(不扩充Top10)
  ⑦ 查timing_positions写入展示列
  ⑧ 输出缩减后权重组合 → 现金 = 1 - sum(缩减后权重)

周五推送阶段 (chart_test/show_marker.py):
  ⑨ 对每只ETF取锚定指数的择时策略仓位 → timing_coef
  ⑩ 计算趋势强度比 trend_ratio = ETF趋势/锚定趋势 → 乘上去
  ⑪ 计算QDII溢价系数 prem_coef → 乘上去
  ⑫ actual_pos = adj_weight × timing_coef × trend_ratio × prem_coef
  ⑬ 输出"建议仓位"文字 → 但不改变Top10组合构成
  ⑭ 现金 = 1 - sum(actual_pos) ← 这一步才是真正大量现金的来源!

周一开盘:
  ⑮ 按推送的建议仓位买入/调仓,剩余现金空置

核心一句话:固定Top10选出后,timing/趋势/溢价三重系数把部分ETF压到很小仓位,但系统不会向后递补候选,资金空置。

---

三、方案设计:全链路一体化满仓配置

核心思想

把"截面选基 → 择时缩仓 → 趋势比调整 → 溢价过滤"从现在的两段割裂流程(引擎选Top10 + show_marker后处理乘系数),合并为一个一体化的递补分配流程:

---

3.1 五层过滤 + 动态递补算法

算法伪代码:

1. 对全池所有ETF计算5因子综合评分,排序得到 ranked_list
2. 预先计算每只ETF的:
   - anchor(锚定指数)
   - region(资产区域)
   - timing_coef = timing_positions[anchor].today / 100  (择时策略仓位,已存在)
   - trend_ratio = clamp((1+etf_trend)/(1+anchor_trend), 0.3, 2.5)  (已存在)
   - prem_coef = 溢价系数计算(已存在,溢价>7%→0,>3%→0.5 等)
   - confidence = corr(ETF近60日收益率, anchor近60日收益率)  【新增:锚定置信度】
   - final_score = factor_score  (5因子综合评分)
3. 初始化:selected = [], region_used = {各区域:0}, cash_remaining = 1.0
4. 目标总仓位 = 0.95(5%现金缓冲)
5. candidate_ptr = 0
6. WHILE cash_remaining > 0.02 AND candidate_ptr < len(ranked_list):
     etf = ranked_list[candidate_ptr]
     region = etf.region
     anchor = etf.anchor

     // ---- 五层过滤 ----

     a) 区域硬上限:
        region_cap = ASSET_REGION_CAPS[region]  // A股40%、港股30% 等
        if region_used[region] >= region_cap:
            candidate_ptr += 1; continue

     b) 择时仓位过滤:
        timing_cap = etf.timing_coef  // 0~1 来自择时策略
        if timing_cap < 0.05:  // 择时策略说空仓/极低仓位 → 跳过
            candidate_ptr += 1; continue

     c) 溢价过滤:
        if etf.prem_coef < 0.05:  // 溢价过高(如>7%)→ 仓位归零,跳过
            candidate_ptr += 1; continue

     d) 同质化相关性过滤:
        // 不是"高相关就互斥",而是"同质化品种才互斥"
        // 判定标准:同一子类别(sub_category)内 + 相关系数 > 0.90 → 只留评分最高的
        // 不同子类别/不同区域/不同资产类型之间,即使相关也保留
        // 例:QQQ(纳指)和SPY(标普) → 不同子类别(科技vs大盘),两者夏普都高,可共存
        // 例:创业板50和创业板100 → 同子类别同指数,相关>0.95,剔除重复的
        if is_homogeneous_duplicate(etf, selected):
            candidate_ptr += 1; continue

     e) 最低评分阈值:
        if etf.final_score < MIN_SCORE_THRESHOLD:  // 建议0.35
            break  // 后面的评分更低,不用继续了

     // ---- 决定该ETF的实际仓位 ----
     base_weight = calc_score_weight(etf.final_score, selected, ranked_list)  // 评分加权
     adjusted_weight = base_weight * timing_cap * etf.trend_ratio * etf.prem_coef

     available_for_region = region_cap - region_used[region]
     available_from_cash = cash_remaining - 0.05
     single_cap = SINGLE_POSITION_CAP  // 15%

     actual_weight = min(adjusted_weight, available_for_region,
                        available_from_cash, single_cap)
     actual_weight = max(0, actual_weight)

     if actual_weight > 0.01:
        selected.append({
            'code', 'name', 'weight', 'factor_score',
            'timing_coef', 'trend_ratio', 'prem_coef',
            'confidence', 'region', 'anchor',
        })
        region_used[region] += actual_weight
        cash_remaining -= actual_weight

     candidate_ptr += 1

7. 输出 selected(动态8~15只)+ cash_remaining

3.2 关键设计细节

3.2.1 择时信号源:完全复用现有择时策略池

不需要新建任何择时模型。直接使用现有的择时信号链路:

backtest/strategy/ 下30+策略 → StrategyAllocationManager加权融合
  → market_data_processer.calculate_average_holding_ratio() → df['position']
  → MarketAnalysis.load_mult_market_strategy() 取末三行
  → timing_positions[anchor] = {today, yesterday, predicted}

这套链路对主要锚定指数(沪深300、创业板指、创业综指、HSI恒生、QQQ纳指、GLD黄金、红利、REITs)已经回测并在运行。

废弃全局 exposure_cap:去掉 SimpleRegimeDetector 用沪深300单基准决定的全局cap,改为完全依赖每个锚定指数的择时策略输出 timing_coef。这才是真正的"分市场独立择时"。

3.2.2 同质化过滤(相关性逻辑修正)

旧逻辑的问题:用相关系数>0.65全局替换,会把QQQ/SPY这种"相关但不同质、都是高夏普优质资产"的组合错误剔除。

新逻辑:同质化判定(homogeneous duplicate),只有同时满足以下条件才判定为重复:

以下情况不剔除,即使相关较高:

3.2.3 溢价系数的递归递补

溢价系数参考表(复用现有逻辑):

溢价率 prem_coef 含义
-------------------------
< -1%(折价) 1.1~1.3 折价时略加仓
-1% ~ 1.5% 1.0 正常区间
1.5% ~ 3% 0.8 轻微溢价,略减
3% ~ 5% 0.5 中等溢价,减半
5% ~ 7% 0.2 高溢价,大幅减
> 7% 0.0 溢价过高,归零→递补

3.2.4 锚定仓位置信度(新增)

计算方式:confidence = corr(ETF近60日收益率, anchor近60日收益率)(皮尔逊相关系数,值域[0,1])

用途(先展示、后决策):

- 方案A:effective_timing = timing_coef × confidence + 1.0 × (1 - confidence) → 低置信度时timing信号向1.0收缩("不确定就不干预") - 方案B:低置信度ETF递补优先级稍降 - 方案C:仅作风险提示

3.2.5 未建策略池的市场:代理锚定 + 待办清单

原则:宁可少配、不可乱配。绝不使用未经验证的策略。

过渡期:没有独立择时策略池的市场(日股、欧洲、印度、原油等),用最接近的已有锚定做代理锚定,标注 ⚠️,单只上限10%,待策略池回测完成后替换。

择时策略池待办清单(Backlog):

优先级 锚定指数 代表品种 数据情况 状态
-----------------------------------------
✅ 已有 沪深300 (399300) A股大盘 >10年 策略池在运行
✅ 已有 创业板指 (399006) A股成长 >10年 策略池在运行
✅ 已有 创业综指 (399102) A股小盘 >10年 策略池在运行
✅ 已有 恒生指数 (HSI) 港股大盘 >10年 策略池在运行
✅ 已有 纳斯达克 (QQQ) 美股科技 >10年 策略池在运行(暂代非美跨境)
✅ 已有 黄金 (GLD/518880) 贵金属 >10年 策略池在运行
✅ 已有 红利 (510880) 红利策略 >10年 策略池在运行
✅ 已有 REITs (508068) REITs 中等 策略池在运行
P0 日经225 日股 >10年 待回测(暂用QQQ代理)
P0 欧洲Stoxx50/DAX 欧洲 >10年 待回测(暂用QQQ代理)
P1 标普500 (SPY) 美股大盘 >10年 待回测(目前共用QQQ)
P1 印度Nifty 印度 中等 待回测(暂用QQQ代理)
P1 原油 (USO/162411) 原油 >10年 待回测(暂用GLD代理)
P2 恒生科技 (HSTECH) 港股科技 ~2年(短) 先用HSI代理,标注低置信
P2 东南亚/越南 东南亚 短 如有品种先用QQQ代理
P2 美元债/美债 防御 >10年 待评估
P3 豆粕/有色等商品 细分商品 不等 扩充品类时同步构建

策略池准入标准:至少3年日线数据、策略组合夏普>1、最大回撤<20%、评估期望为正。

---

四、权重分配方式

---

五、分阶段实施路线

Phase 1:引擎核心改造(2~3天)

Phase 2:show_marker.py 对齐(1天)

Phase 3:回测验证(2~3天)

Phase 4:周中再平衡适配(1天)

Phase 5:ETF池与策略池扩充(持续)

---

六、数据库与前端改动

新增DB列:confidence、timing_coef、trend_ratio、prem_coef、anchor_proxy、cash_weight

前端新增展示:

---

七、风险点与对策

风险 对策
------------
QDII高溢价→递补到流动性差的ETF 增加日均成交额/规模过滤
汇率风险(满仓海外) 区域硬上限(美股≤40%等)天然分散
代理锚定不准 单只10%上限+⚠️标记+尽快回测替换
换手增加 周频调仓+周中30%日换手限制
递补到低质量ETF 最低评分阈值兜底

▶ 📜 变更历史(1 次提交)

a7a12042026-08-07 23:29fix: 网站稳定性修复 - 守护进程接管已有实例 + 隧道readiness健康检查 + 经验文档沉淀
🍃quant 知识库
by 伊甸园和枫

🔊 播放设置

勾选音源后调节配比,总和自动归一化
已选 0 个 · 合计:0%
合成中...
00:00/00:00
1.0x

分享图片

生成中...