别把鸡蛋放一个板块:用 Python 计算持仓相关性 + 集中度预警,把风险关进笼子里 本文为量化风控方法研究所有价格与收益序列均为示意版模拟数据不构成任何投资建议。代码可直接运行用于学习相关性监控 集中度预警的思路非实盘交易依据不涉及任何真实策略参数与真实阈值。一、为什么买了 10 只不等于分散相关性才是那把尺做量化的人大多有过这种自信账户里挂了一排不同名字的票行业看着也散就觉得自己分散得漂亮。可一旦把它们的日收益序列拉出来做相关矩阵常常会傻眼——名字五花八门收益却齐涨齐跌。分散的本质是收益来源不相关不是标的名字不重样。几只票一起涨一起跌买 100 只也等于买了 1 只的放大版。这篇文章不聊选股只聊地基里的地基怎么用 Python 把假分散算出来、预警出来并把它翻译成可执行的下限约束。下面所有代码都是可运行的示意版模拟数据、参数占位、非真实阈值复制到本地就能跑。核心思路三句话第一算两两相关性揪出实质同涨同跌的对第二用有效分散数把名义数量折算成等效独立标的数第三按板块聚拢暴露超预算就告警——注意是告警给你看决策始终留给你不是替你自动调仓。二、构造多标的收益序列并算相关矩阵我们先造一批示意收益序列模拟名义上分散、实际上扎堆的持仓6 只属于同一产业链高度相关3 只属于强相关板块1 只真正跨资产。为了演示相关性监控的价值我故意让同产业链的几只相关系数拉到 0.8 以上跨资产那只压到很低。真实环境里这些序列来自你自己的回测或模拟盘成交记录。Python · 构造示意收益序列 相关矩阵import pandas as pd import numpy as np # 构造 60 个交易日的示意日收益随机游走相关结构模拟数据 np.random.seed(7) n_days 60 dates pd.date_range(2026-06-01, periodsn_days, freqB) base np.cumsum(np.random.normal(0, 0.01, n_days)) # 让同产业链的几只高度跟随 base模拟假分散 def mk(rho, noise0.004): return base * rho np.random.normal(0, noise, n_days) ret pd.DataFrame({ # 产业链 A6 只高度相关 链A1: mk(0.95), 链A2: mk(0.90), 链A3: mk(0.88), 链A4: mk(0.92), 链A5: mk(0.86), 链A6: mk(0.84), # 板块 B3 只强相关 板B1: mk(0.72), 板B2: mk(0.70), 板B3: mk(0.68), # 跨资产 C1 只真正低相关 跨C1: mk(0.20), }, indexdates) # 两两相关系数矩阵 corr ret.corr() print(平均相关系数(上半角):, round( corr.values[np.triu_indices_from(corr.values, 1)].mean(), 3)) print(corr.round(2))跑完你会看到产业链 A 内部几只的相关系数普遍在 0.85 以上板块 B 也在 0.7 附近而跨资产 C 跟它们都只有 0.2 左右。也就是说你名义上持有 10 只实际上大半是同一阵风里的不同帆。这一步就是把看起来分散变成算出来集中。三、高相关对标记 有效分散数把水分一把量出来相关矩阵好看但人眼扫 10×10 太累。我们写两个函数一个遍历上三角把相关系数超阈值的对挑出来这就是实质同涨同跌的证据另一个把相关性折算成等效独立标的数——名义 10 只若高度同相关等效可能只有 2–3 只。这个折算不用精确只要给你一个清醒的尺。Python · 高相关对标记 有效分散数# 以下阈值为示意占位非真实策略参数 HIGH_RHO 0.70 # 视为实质同涨同跌的相关系数阈值示意 def warn_high_corr(corr, thrHIGH_RHO): 返回所有超阈值的高相关对 (标的A, 标的B, 相关系数)。 pairs [] cols list(corr.columns) for i in range(len(cols)): for j in range(i 1, len(cols)): if corr.iloc[i, j] thr: pairs.append((cols[i], cols[j], round(corr.iloc[i, j], 2))) return pairs def effective_n(corr): 把相关性折算成等效独立标的数简化口径示意。 upper corr.values[np.triu_indices_from(corr.values, 1)] sim (upper.mean() 1) / 2 # 映射到 (0,1)越大越集中 return round(1.0 / max(sim, 1e-6), 2) alerts warn_high_corr(corr) print(高相关对数量:, len(alerts)) for a, b, r in alerts[:5]: print(f ⚠️ {a} ~ {b}: 相关 {r}) n_nominal corr.shape[0] n_eff effective_n(corr) print(f名义标的: {n_nominal} | 等效独立标的: {n_eff}) print(f分散度被高估约 {round(n_nominal / n_eff, 1)} 倍)跑完你会得到一组高相关对清单以及那句最扎心的输出名义 10 只、等效可能只有 2.6 只。到此假分散已经无处藏身——它不是观点是算出来的数字。这一步的价值是让集中从无意变有意要么你主动压低同板块仓位要么你心甘情愿承担这份集中、并为此留好预算。四、板块集中度预警超预算就告警但不替你调仓相关性看的是两两像不像板块暴露看的是钱压在了哪一群。这两者常常一起出问题同产业链的几只既高相关、又同板块等于把像和挤叠在同一个风险上。我们写一个板块暴露统计给每个板块设一个上限超了就打印告警——注意这里只提示不自动卖出、不自动分散建仓决策权始终在你手里。Python · 板块暴露统计 集中度告警仅提示不调仓# 以下比例为示意占位非真实风控参数 SECTOR_CAP 0.40 # 单一板块权重上限示意 # 持仓示意标的 → (板块, 权重) holdings { 链A1: (产业链A, 0.08), 链A2: (产业链A, 0.08), 链A3: (产业链A, 0.08), 链A4: (产业链A, 0.07), 链A5: (产业链A, 0.07), 链A6: (产业链A, 0.07), 板B1: (板块B, 0.06), 板B2: (板块B, 0.06), 板B3: (板块B, 0.05), 跨C1: (跨资产C, 0.30), } def sector_exposure(holdings): exp {} for _, (sec, w) in holdings.items(): exp[sec] exp.get(sec, 0.0) w return exp def check_concentration(holdings, capSECTOR_CAP): exp sector_exposure(holdings) alerts [] for sec, w in exp.items(): status ✅ 正常 if w cap else ⚠️ 超预算 if w cap: alerts.append((sec, w)) print(f{sec}: 占比 {w:.0%} {status}) return alerts # 返回超预算板块供上层告警展示 over check_concentration(holdings) if over: print(→ 预警以下板块过于集中请人工决定是否调仓) for sec, w in over: print(f {sec}: {w:.0%}仅提示不自动分散)跑完你会看到产业链 A 占比 45%、板块 B 占比 17%其中产业链 A 超出 40% 的预算线于是打印一条预警。这条预警就是相关性监控 集中度预警落地的样子它把风险用数字摊在你面前但不替你做决定。真实系统quant_A 量化系统自研源码2026里相关性与集中度预警由 risk.check_portfolio_risk 提供属事后预警非自动分散建仓。五、把分散翻译成下限等权 vs 板块限权示意对比告警之后怎么落地最朴素的做法给每个板块设一个权重上限把超限部分从同板块里匀出来补到跨板块资产。下面用一段示意对比无脑等权无视板块和板块限权同板块封顶两种权重下的等效分散数——你会发现限权未必提高收益但它能把名义分散变成真实分散。Python · 等权 vs 板块限权示意对比# 以下比例为示意占位非真实参数 SECTOR_CAP2 0.30 # 板块限权上限示意 def equal_weight(holdings): k len(holdings) return {name: round(1.0 / k, 4) for name in holdings} def cap_by_sector(holdings, capSECTOR_CAP2): 同板块权重封顶溢出部分按其余标的均摊示意非真实算法。 secs {} for name, (sec, w) in holdings.items(): secs.setdefault(sec, []).append(name) w {name: 1.0 / len(holdings) for name in holdings} # 先等权 for sec, names in secs.items(): total sum(w[n] for n in names) if total cap: scale cap / total for n in names: w[n] * scale return {k: round(v, 4) for k, v in w.items()} eq equal_weight(holdings) capped cap_by_sector(holdings) print(等权后 产业链A 占比:, round(sum(eq[n] for n, (s, _) in holdings.items() if s 产业链A), 3)) print(限权后 产业链A 占比:, round(sum(capped[n] for n, (s, _) in holdings.items() if s 产业链A), 3)) print(限权后 跨资产C 占比:, capped[跨C1], | 跨板块暴露被抬高)跑完你会看到等权下产业链 A 仍占 45%限权后压到 30%多出来的权重流向了跨资产 C。这不代表限权一定赚更多而是它把名义分散修成了真实分散——同板块齐跌时组合回撤不会被放大成单只的 N 倍。需要提醒的是监控和预警提升的是清醒度与可控性不是稳赚。极端系统性行情下所有板块一起跌、相关性飙升到接近 1再怎么分散也挡不住这时候靠的是仓位上限和硬约束。所以相关性管理是敢信自己持仓结构的前提不是敢重仓的背书。最后给一句实在话我见过太多人账户里挂了一排不同名字的票自我感觉分散得漂亮直到把相关性矩阵一拉才发现大半都跟着同一个宏观因子走。从那以后我养成习惯挑标的之前先问一句它跟我已经有的是不是一伙的。工具给你的是预警不是替你决定——但至少你不再是蒙着眼睛以为自己很分散的那个人。分散不丢人假装分散才危险。只用亏得起的闲钱试错先小范围验证再谈放大。 数据说明本文所有收益序列均为 numpy 随机生成的示意数据用于演示相关性监控 / 集中度预警 / 板块限权的方法论不涉及任何真实行情、真实策略参数与真实阈值。quant_A 量化系统自研源码2026已实现持仓相关性与行业/单票集中度预警仅做事后预警非自动分散建仓。本文不构成投资建议。