bust_probability / goal_probability
前者是模拟路径中跌破 bust 阈值的比例,后者是达到 goal 阈值的比例。它们反映的是「在历史收益分布假设下」的风险暴露,不是对未来的确定性预言;分布一旦变化,结果可能明显偏移。
依据官方 README Monte Carlo Simulations 段落;参数默认值以官方实现为准。
| 参数 / 属性 | 含义 | 如何取值 | 注意点 |
|---|---|---|---|
| returns | 收益序列(输入) | qs.utils.download_returns('META') 或自备 pandas Series | 需日/周/月收益序列,非原始价格 |
| sims | 模拟路径次数 | 官方示例 1000;次数越大越稳定 | 次数越大耗时越长,需权衡精度与时间 |
| bust | 破产阈值(亏损比例) | 官方示例 -0.20;按可承受亏损设负数 | 阈值越接近 0 越容易触发「破产」 |
| goal | 目标阈值(盈利比例) | 官方示例 0.50;按目标收益设正数 | 阈值越高越难达到,概率越低 |
| mc.bust_probability | 破产概率(输出) | 直接读属性,返回 0~1 或百分比 | 模拟路径中跌破 bust 阈值的比例 |
| mc.goal_probability / mc.plot() | 目标概率 / 分布绘图 | 读属性 + 调 mc.plot() 可视化 | plot() 生成模拟分布图,辅助直观判断 |
| 随机种子(不显式出现在签名里) | 决定随机抽样序列,影响结果能否复现 | 在数据侧固定,如先执行 numpy 的 seed 设定 | 不固定时同一份数据两次运行的概率会有小幅波动,忽高忽低不代表模型变了 |
1. 导入库:import quantstats as qs —— 引入 stats/plots/reports 三模块。
2. 取收益序列:stock = qs.utils.download_returns('META') —— 得到 Meta 的日收益序列,也可换自备 Series。
3. 运行模拟:mc = qs.stats.montecarlo(stock, sims=1000, bust=-0.20, goal=0.50) —— 生成 1000 条模拟路径,破产阈值 -20%、目标阈值 +50%。
4. 查看结果:mc.bust_probability、mc.goal_probability 返回两个百分比;mc.plot() 绘制模拟分布。
5. 预期输出核对:bust_probability / goal_probability 是两个 0~1 之间的比例,二者不会同时很高;若两个都是 0 或都是 1,先检查序列是不是收益率、阈值正负号是不是写反。
6. 换一组阈值再跑一次:把 bust 从 -0.20 放宽到 -0.30、goal 从 0.50 下调到 0.30,预期破产概率下降、目标概率上升——这是判断阈值是否设得过严的快捷办法,也是 QuantStats 风险画像里最常用的一次对照实验。
7. 落到同一份记录里:把 sims、bust、goal、样本区间四项和两个概率写在一起,否则过几周回看时无法判断差异来自参数还是来自随机波动。
除主方法外,stats 与 plots 还提供按指标拆分的蒙特卡洛方法。
| 方法 | 用途 | 适用场景 |
|---|---|---|
| montecarlo(主方法) | 模拟破产/目标概率 | 整体风险画像,看「爆仓 vs 达标」概率 |
| montecarlo_cagr | 模拟 CAGR(年化复合增长率)分布 | 看长期收益的不确定区间 |
| montecarlo_drawdown | 模拟最大回撤分布 | 看未来可能遭遇多深的回撤 |
| montecarlo_sharpe | 模拟夏普比率分布 | 看风险调整收益的稳定性 |
| montecarlo_distribution(plots) | 绘制模拟分布图 | 直观展示模拟结果分布形态 |
| risk_of_ruin(相关指标,非模拟) | 按收益分布解析估算破产风险 | 赶时间、只想拿一个破产风险点估计时;注意它与蒙特卡洛的破产概率口径不同,不能直接比大小 |
前者是模拟路径中跌破 bust 阈值的比例,后者是达到 goal 阈值的比例。它们反映的是「在历史收益分布假设下」的风险暴露,不是对未来的确定性预言;分布一旦变化,结果可能明显偏移。
sims 越大,模拟结果越稳定(方差越小),但耗时线性上升。官方示例取 1000;对长收益序列或需要更精细尾部概率时,可适当提高,但要接受更长计算时间。
bust_probability 低不代表策略安全——如果 goal_probability 同样很低,说明多数模拟路径既不破产也到不了目标,策略更像「原地打转」。QuantStats 给的是两端概率,中间那段「什么都没发生」的区域要靠分布图或 montecarlo_cagr 才能看清。
同一份策略收益,截取 2020 年与截取 2023 年做 QuantStats 蒙特卡洛,得到的破产概率可能完全不同。原因不是方法不稳定,而是重采样完全继承样本的涨跌结构;因此汇报时必须写明样本起止与频率,否则数字无法被复核。
两类指标回答不同的问题:确定性指标描述「历史发生了什么」,蒙特卡洛描述「在假设分布下未来可能发生什么」。
| 维度 | 确定性指标(历史最大回撤等) | 蒙特卡洛模拟 |
|---|---|---|
| 回答的问题 | 历史最大回撤是多少 | 未来回撤超过某阈值的概率多大 |
| 输出形态 | 单一数值(点估计) | 概率分布 / 百分比 |
| 依赖假设 | 仅历史数据 | 历史收益分布 + 随机模拟 |
| 适用场景 | 复盘历史、对比策略 | 前瞻风险画像、仓位压力测试 |
| 计算成本 | 遍历一次收益序列,基本瞬间返回 | 与 sims 成正比,sims 越大越慢 |
| 可复现性 | 同一份数据结果完全一致 | 未固定随机种子时会有小幅波动,需固定种子才能逐位复现 |
下面这些坑官方 README 不会写,但几乎每个第一次拿蒙特卡洛数字去汇报的人都会踩。逐条对照一遍,比换更复杂的模型有用。
| 误用方式 | 典型表征 | 会得出什么错结论 | 怎么改 |
|---|---|---|---|
| 把 bust_probability 当真实破产概率 | 报告里直接写「本策略破产概率 3%」 | 读者以为这是客观概率,据此做仓位决策 | 改成「在历史收益分布重采样下,3% 的模拟路径跌破阈值」,并附样本区间 |
| sims 太小就下结论 | 同一份数据反复跑,概率在两个值之间来回跳 | 把一次抽样的结果当成稳定结论写进材料 | 先小 sims 试跑,再放大并固定种子,两档结果差到能接受为止 |
| 收益序列太短 | 只拿几十个交易日的数据就做模拟 | 分布被少数极端日主导,尾部概率虚高或虚低 | 尽量覆盖完整涨跌周期(数年以上日频),并在结论里注明样本长度 |
| 忽略收益序列的频率 | 月频序列却按日频理解 -0.20 的含义 | 阈值的时间尺度被放大或缩小,概率解释全错 | 先确认序列频率,阈值与频率一起说明:月频阈值就按月理解 |
| 忽略资金流与复利假设 | 模拟结果与真实账户曲线对不上 | 判定「模型算错了」,转而怀疑代码 | 明确模拟是否按固定比例复利、是否假设无出入金;真实账户有加减仓时不可直接套用 |
| goal 设成不可能达成的值 | goal_probability 长期为 0,就断言策略没用 | 错误否定一个本身正常的策略 | 先看历史年化收益的量级再设 goal,或改读 montecarlo_cagr 的分布区间 |
| 只看概率不看分布 | 材料里只有一个破产概率数字 | 忽略「亏多少」的量级差异:同样是 5%,亏两成和亏一半完全不同 | 配 mc.plot() 看分布形态,并与 montecarlo_drawdown 一起读 |
| 拿模拟概率直接反推仓位 | 按 5% 破产概率倒推出一个仓位上限 | 把假设当成已知风险,分布一旦漂移仓位就不再安全 | 把概率当输入而非结论,同时保留止损或最大回撤上限这类硬约束 |
| 把一次模拟当成压力测试 | 只跑一个阈值就宣称「已做压力测试」 | 极端行情下的连续亏损根本没被覆盖 | 至少同时看两档阈值与回撤分布,针对历史最差区间单独复跑 |
sims 每加一个量级,结果更稳、时间更长;下面按量级给出用途与代价,用来排序而不是当承诺——实际耗时取决于收益序列长度与本机性能。
| sims 量级 | 适合的用途 | 代价与表现 | 建议 |
|---|---|---|---|
| 100~500 | 试探阈值是否合理、排查代码是否跑通 | 概率跳动明显,只能看数量级 | 只用于起草,结论不要写进汇报材料 |
| 1000 | 日常风险画像(官方示例量级) | 通常秒级到十几秒量级 | 单策略汇报的默认选择 |
| 5000 | 需要更稳的尾部概率(例如 1% 附近) | 耗时约为 1000 档的数倍 | 先与 1000 档对比波动,稳定后再采用 |
| 10000 及以上 | 精细尾部估计、多阈值扫描 | 耗时明显上升,单机串行较慢 | 先锁定种子与阈值,只放大这一次 |
| 多策略批量 | 组合层面的风险横向对比 | 总耗时 = 策略数 × 单次耗时 | 先小 sims 粗筛,再对入围策略放大 |
| 参数搜索循环内 | 把风险约束加进调参 | 大部分时间会被模拟吃掉 | 把模拟放到筛选之后一步,不要放进每轮迭代 |
1. 先小规模试跑:mc = qs.stats.montecarlo(stock, sims=200, bust=-0.20, goal=0.50) —— 确认参数能被接受(阈值正负号、序列是收益率而非价格)。预期秒级返回两个概率,而不是报错或全 0。
2. 固定随机种子再放大:import numpy as np; np.random.seed(42) 之后重跑 sims=5000 —— 预期同样输入两次运行得到一致结果,便于把数字写进材料后能被复核。
3. 对比两档 sims 的稳定性 —— 记录 1000 与 5000 两档的 bust_probability / goal_probability,当两者差距小于你的汇报精度时即可停止放大,继续加次数只涨耗时。
4. 出图确认分布:mc.plot() —— 预期得到模拟结果的分布图;如果出现异常长尾或几乎所有路径同向,先回头检查样本区间是否只覆盖了单边行情。
QuantStats 本身不做数据抓取,也不内置 A 股数据源:无论指标、模拟还是报告,吃到的都是「收益率序列」这一层。所以第一步是先解决「序列从哪来」。
| 数据来源 | 覆盖市场 | 前置条件 | 拿到后怎么用 |
|---|---|---|---|
| qs.utils 内置取数 | 美股等海外行情 | 能访问外网行情源 | 直接得到收益率序列,示例写法 download_returns('META') |
| yfinance(独立安装) | 美股行情、历史K线 | 外网可达;通常无需密钥 | 自取收盘价后算收益率序列,再喂给 QuantStats |
| akshare | A 股、期货、期权、基金、指数等公开数据 | 能访问公开财经站点 | A 股研究常见取数路线,取价后同样先转收益率序列 |
| tushare | A 股、港股、美股等接口 | 需要 Tushare Token | 适合批量、可重复的取数场景 |
| 自有数据导出的 CSV | 取决于数据源本身 | 整理成「日期 + 收益」两列 | 用 pandas 读入并设日期索引,再交给 QuantStats |
| 组合权重与再平衡记录 | 多标的组合 | 先算组合层收益 | 做组合风险模拟前先确认权重口径与再平衡假设 |
| 券商客户端导出 | 自己的真实持仓或历史成交 | 导出后需清洗为收益序列 | 适合复盘自己的账户,但要注意分红送股与手续费是否已计入 |
1. 取 A 股日线:df = ak.stock_zh_a_hist(symbol="600519", period="daily", adjust="qfq") —— 预期返回含日期与收盘价的表;接口名与列名会随 akshare 版本变化,以官方文档为准。
2. 转成收益率序列:r = df.set_index("日期")["收盘"].pct_change().dropna() —— 预期得到一条日频 Series,首行 NaN 已剔除,可直接喂给 QuantStats。
3. 跑模拟:mc = qs.stats.montecarlo(r, sims=1000, bust=-0.20, goal=0.50) —— 预期返回破产/目标两个概率;若取数失败,先排查网络与数据源可用性,再考虑换源。
按收益序列的历史分布随机生成大量路径,估算达到破产/目标阈值的概率,做概率化风险分析。具体算法与默认参数以官方 README/实现为准。
官方示例用 sims=1000;次数越多越稳定但越慢,需权衡精度与耗时,以官方文档为准。
按你的风险偏好设 bust(亏损比例,负数)与 goal(盈利比例,正数),官方示例用 -0.20 / 0.50;阈值设定会直接影响概率结果。
不能。它基于历史收益分布模拟,隐含「未来分布与历史相似」的假设,不构成收益保证或投资建议。
蒙特卡洛是随机抽样:未固定随机种子时,每次模拟走的是不同的路径集合,概率会有小幅波动,sims 越小波动越明显。要复现结果就固定种子,并在记录里同时写下 sims、bust、goal 与样本区间。具体随机数处理以 QuantStats 官方实现为准。
QuantStats 与 EasyClaw 无已证实集成,两者是相互独立的路线:本机已核验的 quant-analyst 技能也涉及回测与风险指标,但实现方式、参数暴露程度与输出形式都不同,适合的场合也不同,选择前以各自官方说明为准。