QuantLib · Options pricing
QuantLib 期权定价:Black-Scholes、Greeks 与四种引擎交叉验证
同一个平值看涨期权(S=K=100、r=5%、vol=20%、一年期),本页用 QuantLib 1.43 在四类定价引擎上分别算出价格与 Greeks,并和手写 Black-Scholes 公式、有限差分 Greeks 逐项对照:解析解 10.4681483852,树引擎误差 200 ppm 上下,有限差分 38 ppm,蒙特卡洛 89 ppm。价格能算出来只是开始,误差有多大、Greeks 从哪来、什么期权没有唯一解才是这一页要回答的问题。
期权定价的四层结构:先选合约(类型与行权方式),再选引擎,引擎给出价格与 Greeks,最后用另一种方法复核。示意图为结构说明,非实盘界面。
QuantLib 支持哪些期权、分别配什么引擎?
先看合约层:不同期权类型能用的引擎并不一样,行权方式选错会直接报错。下表把类型、可用引擎与本站是否实测写在一起,避免「看起来能用」的误判。
| 期权类型 | QuantLib 类 / 构造 | 本页/本站实测过的引擎 | 本站实测的 NPV | 适用场景与注意点 |
|---|---|---|---|---|
| 欧式看涨(基线) | `ql.VanillaOption` + `ql.PlainVanillaPayoff` + `ql.EuropeanExercise` | AnalyticEuropeanEngine / BinomialVanillaEngine / FdBlackScholesVanillaEngine / MCEuropeanEngine | 10.4681483852(解析) | 有解析解,适合当基准;注意 vega 单位是「每 100% 波动率」 |
| 美式看涨 | `ql.AmericanExercise(today, expiry)` | BinomialVanillaEngine(crr/jr, 801) / FdBlackScholesVanillaEngine(200,400) / BaroneAdesiWhaley / BjerksundStensland | 10.47026038(CRR 801) | 只能用树、有限差分或近似式;配 AnalyticEuropeanEngine 会报 `RuntimeError: not an European option` |
| 算术平均亚式 | `ql.DiscreteAveragingAsianOption(ql.Average.Arithmetic, 0.0, 0, fixingDates, …)` | MCDiscreteArithmeticAPEngine / FdBlackScholesAsianEngine | 6.1646871(MC 20 万路径 seed=42) | 路径依赖,没有通用解析解;要额外给定平均价观察日 |
| 几何平均亚式 | 同上,改用 `ql.Average.Geometric` | AnalyticDiscreteGeometricAveragePriceAsianEngine | 5.945642 | 有解析解,可用来给算术版做量级校验(几何平均 ≤ 算术平均) |
| 敲出 / 敲入障碍 | `ql.BarrierOption(ql.Barrier.UpOut, level, rebate, payoff, exercise)` | AnalyticBarrierEngine | up-out@130 = 3.32633974;down-out@80 = 10.36788009 | 本机实测敲入 + 敲出价格之和 = 对应欧式价格(见下文校验) |
| 二元 / 篮子等其它结构 | 官方 Instruments 模块中的对应类(本页未实测) | 官方文档列出的引擎(未实测) | 未实测 | 本站没有运行结果,只给官方文档入口;不要按本页其它数字类推 |
ql.AnalyticEuropeanEngine,本机直接抛 RuntimeError: not an European option。引擎不做近似降级,也不给警告——这类错误属于「合约与引擎不匹配」,改引擎即可,不需要换参数。第一步:把解析解和手写公式对上,差 1.78e-15
定价链路的起点是一个能对得上的基准。本页用同一组参数在 QuantLib 里建 Black-Scholes 过程、算出欧式看涨理论价,同时用 Python 标准库手写 Black-Scholes 公式,两条路应该得到同一个数。
| 检查项 | 本机实测值 | 说明 |
|---|---|---|
| AnalyticEuropeanEngine NPV | 10.4681483852 | 黑-舒尔斯解析解,作为本页基准 |
| 手写 Black-Scholes 公式 | 10.4681483852 | 用 Python `math` 标准库实现,不依赖 QuantLib |
| 两者绝对差 | 1.7763568394e-15 | 浮点尾差量级,可认为完全一致 |
| T(年) | 1.00273973 | Actual/365 (Fixed) 口径;不是整数 1,会直接影响价格 |
| 隐含波动率反解(K=90/100/110) | 24.99998122% / 24.99999542% / 25.0% | 输入 25% 的波动率,用 `ql.blackFormulaImpliedStdDev` 反解回来,误差 ≤ 2e-5 |
S·e^{rT} = 105.1415116);远期给错就会抛 RuntimeError: negative Put price … No solution exists,这属于「输入口径不一致」,不是公式错了。Greeks 实测值与单位:vega 单位最容易搞错
Greeks 是价格对某个因子的偏导。QuantLib 直接给解析 Greeks,但单位口径需要自己确认:vega 与 rho 是「每 100% 变化」,不是每 1%。下表是本机实测值。
| Greeks | 本机实测值(原始单位) | 换算后的常用口径 | 经济含义 | 什么时候看 |
|---|---|---|---|---|
| delta | 0.6370104227930847 | 0.6370(每 1 元标的价格) | 标的价格涨 1 元,期权价约涨 0.64 元 | 对冲比例、方向敞口 |
| gamma | 0.018733224790154022 | 0.0187(每 1 元价格的 delta 变化) | 标的价格涨 1 元,delta 约涨 0.0187 | 调仓频率、凸性风险 |
| vega | 37.56909738737739 | 0.3756909738737739(每 1% 波动率) | 波动率涨 1 个百分点,期权价约涨 0.376 元 | 波动率风险、波动率交易 |
| theta | -6.408289652737268 | -0.017556957952704844(每天,= theta/365) | 每过一天,期权价约降 0.0176 元 | 持有成本、到期临近 |
| rho | 53.378737439044706 | 0.5337873743904471(每 1% 利率) | 利率涨 1 个百分点,看涨期权价约涨 0.534 元 | 利率敏感型组合 |
vega() 是波动率变化 1.0(即 100 个百分点)对应的价格变化,所以「每 1% 的 vega」= 37.56909738737739 ÷ 100 = 0.3756909738737739。报风险数字前先把这个换算写清,否则会放大 100 倍。theta() 同理是「每年」,除以 365 才是每天。Greeks 怎么自己验:用有限差分对一遍解析值
解析 Greeks 没法直接验,但你可以在 QuantLib 里对参数加一个小扰动、重新定价,用差分结果反推 Greeks。本页对 delta、gamma、vega、rho、theta 各做了一次差分(h=0.01 / 1bp / 1 天),与解析值对比如下。
| Greeks | 解析值 | 差分值 | 绝对差 | 差分设置与说明 |
|---|---|---|---|---|
| delta | 0.6370104227930847 | 0.6370104142069621 | 8.59e-09 | 中心差分:标的价格 ±0.01 |
| gamma | 0.018733224790154022 | 0.018733224500522283 | 2.90e-10 | 二阶中心差分:(P(S+h) − 2P(S) + P(S−h)) / h²,h=0.01 |
| vega(每 1%) | 0.3756909738737739 | 0.37569097081737723 | 3.06e-09 | 波动率 ±1e-4 的中心差分后除以 100 |
| rho(每 1%) | 0.5337873743904471 | 0.5337873666286796 | 7.76e-09 | 利率 ±1e-4 的中心差分后除以 100 |
| theta(每天) | -0.017556957952704844 | -0.017564812993576595 | 7.86e-06 | 把估值日 +1 天后重新定价,取价格差;与 theta/365 的差最大 |
同一个期权,四个引擎的价格差多少(含误差与耗时)
把同一个欧式看涨交给解析、树、有限差分、蒙特卡洛四类引擎,各自报价并计时。基准取解析解 10.46814839,下表把绝对差、相对误差(ppm)与耗时都列出来,方便你判断「差多少才算正常」。
| 引擎与配置 | NPV | 与解析解绝对差 | 相对误差(ppm) | 耗时(秒) | 读法与注意点 |
|---|---|---|---|---|---|
| AnalyticEuropeanEngine | 10.46814839 | 0(基准) | 0 | 0.0002 | 有解析解就用它;本机最快且精确 |
| BinomialVanillaEngine(crr, 801) | 10.47026038 | 0.00211199 | 201.75 | 0.0008 | CRR 树上偏;奇数步与偶数步的收敛路径不同 |
| BinomialVanillaEngine(jr, 801) | 10.47016843 | 0.00202004 | 192.97 | 0.0011 | JR 与 CRR 误差量级接近 |
| BinomialVanillaEngine(lr, 801) | 10.46814783 | 5.6e-07 | 0.05 | 0.0006 | LR 用平滑收敛技巧,本机精度比 CRR 高约 3600 倍 |
| FdBlackScholesVanillaEngine(200, 400) | 10.4685452 | 0.00039681 | 37.91 | 0.0025 | 有限差分精度取决于时间/空间网格,适合可加结构 |
| MCEuropeanEngine(1e6 路径, seed=42) | 10.46907932 | 0.00093093 | 88.93 | 0.2214 | 蒙特卡洛不提供 delta/vega;误差约 1/√N |
| MCEuropeanEngine(低差异序列 65536 点) | 10.46700612 | 0.00114227 | 109.12 | 0.0155 | 低差异序列路径少但更快,误差量级相近 |
亚式与障碍期权实测:平均价怎么取、敲入敲出能不能对上
路径依赖期权没有通用的解析解,构造方式不同结果就会差。本页用「每月一个观察日、共 12 个观察日」构造算术平均亚式,并同时给出几何平均(有解析解)作量级校验;障碍期权则用敲入 + 敲出的互补关系做自检。
| 结构 | 引擎 | 本机实测 NPV | 对照与读法 |
|---|---|---|---|
| 欧式看涨(对照基准) | AnalyticEuropeanEngine | 10.46814839 | 所有奇异结构的锚点 |
| 算术平均亚式(12 个观察日) | MCDiscreteArithmeticAPEngine(20 万路径, seed=42) | 6.1646871 | 平均价压低波动,价格低于同参数的欧式看涨(10.4681) |
| 算术平均亚式(同结构) | FdBlackScholesAsianEngine(100, 100, 50) | 6.18993503 | 与蒙特卡洛差 0.025(约 0.4%),说明两条数值路径彼此接近 |
| 几何平均亚式(同观察日) | AnalyticDiscreteGeometricAveragePriceAsianEngine | 5.945642 | 几何平均 ≤ 算术平均,方向正确;可作为算术版的数量级校验 |
| 向下敲出(障碍 80) | AnalyticBarrierEngine | 10.36788009 | 只在价格未触及 80 时有效,故低于欧式 |
| 向下敲入(障碍 80) | AnalyticBarrierEngine | 0.10026829 | 与同障碍的敲出价之和 = 10.46814838,等于欧式 10.46814839(差 1e-8) |
| 向上敲出(障碍 130) | AnalyticBarrierEngine | 3.32633974 | 涨幅受限,权利金显著变便宜 |
| 向上敲入(障碍 130) | AnalyticBarrierEngine | 7.14180864 | 与向上敲出价之和同样等于欧式价格 |
DiscreteAveragingAsianOption 构造函数的第 2、3 个参数是 runningAccumulator 与 pastFixings,不是「平均价」;本机曾把 12 传进这两个位置,结果几何版直接抛「positive running product required」、算术版静默返回 0.0。提前行权溢价实测:只有分红才会让美式看涨更值钱
美式期权多了「随时行权」的权利,但这份权利值多少钱取决于分红。本页把分红率从 0 调到 6%,比较美式(CRR 801)与欧式(解析)的价格差。
| 分红率 q | 欧式解析价 | 美式价(CRR 801) | 提前行权溢价 | 读法与注意点 |
|---|---|---|---|---|
| 0% | 10.46814839 | 10.47026038 | 0.002112 | 无分红时提前行权不是好选择,溢价几乎只是树的截断误差 |
| 3% | 8.66481186 | 8.66737181 | 0.00255996 | 分红开始压低看涨价值,但行权权仍不值钱 |
| 6% | 7.0834932 | 7.26773057 | 0.18423737 | 分红足够高时提前行权开始划算,溢价跳到 0.18 量级 |
| 近似式引擎(q=0) | 10.46814839 | 10.46814839(BAW / Bjerksund-Stensland) | ≈ 0 | 无分红时近似式退化为欧式解,本机与解析解逐位一致 |
| 引擎选择后果 | — | — | — | 算美式必须用树 / 有限差分 / 近似式;用解析欧式引擎会直接报错 |
价格对不上先查什么:6 步定位顺序
把自己算的价和市场报价、或两个引擎的价对上,是日常最花时间的活。下面 6 步按「先排除低级错误、再怀疑数值方法」排序,每步都给出本页实测过的判据。
1. 先确认合约与引擎是否匹配
美式配欧式引擎会直接抛RuntimeError: not an European option;树引擎与蒙特卡洛引擎**不提供 vega**(RuntimeError: vega not provided),要希腊字母就换解析或有限差分引擎。2. 再核对输入口径(最常错)
估值日、到期日、计息约定三项必须先确认。本页基线 T = 1.00273973 而非 1,就是 Actual/365 (Fixed) 的结果;换成别的计息约定,同一个合约会算出不同的价格。3. 检查远期与折现是否自洽
反解隐含波动率是最快的自检:输入 25% 应能反解回 25%(本机实测 24.999981% ~ 25.0%)。如果反解报错,几乎一定是远期价(S·e^{rT})或折现因子给错了。4. 看差异量级是否在引擎噪声内
本机实测:树 801 步约 200 ppm、有限差分 200×400 约 40 ppm、蒙特卡洛 100 万路径约 90 ppm。差异在几十到两百 ppm 属正常;超过 1% 就继续往下查。5. 用第二种方法复算
解析解对手写公式(差 1.78e-15)、解析 Greeks 对有限差分 Greeks(差 1e-9 ~ 1e-8)、障碍期权用「敲入 + 敲出 = 欧式」自检(实测差 1e-8)。三种复算都比「再跑一遍同一个引擎」有价值。6. 最后才怀疑模型假设
如果前 5 步都对不上,问题通常在波动率曲面、分红或利率曲线的构造上——那属于输入数据与期限结构的范畴,先看期限结构页的曲线自洽性检查。常见问题
为什么我用公式手算的结果和 QuantLib 差一点点?
先看差多少。本站实测:解析引擎对手写 Black-Scholes 公式的差是 1.7763568394e-15,属于浮点尾差;如果你看到的是 0.01 量级的差,通常是计息约定或时间口径不同(本页基线 T = 1.00273973,不是整数 1)。把估值日、到期日、计息约定三项对齐后再比较,具体以实现与官方文档为准。
Greeks 的 vega 单位到底是什么?
QuantLib 的 vega() 返回「波动率变化 1.0(100 个百分点)」对应的价格变化,本机实测 37.56909738737739;业内常报的「每 1%」要除以 100,即 0.3756909738737739。rho() 同理(53.378737439044706 → 每 1% 为 0.5337873743904471),theta() 是每年(-6.408289652737268 → 每天约 -0.017557)。报数字前先写清单位,否则会放大 100 倍。以官方文档为准。
亚式期权为什么没有唯一答案?
因为「平均价」的取法本身要约定:观察日清单、算术还是几何平均、固定还是浮动行权价。本站实测同一组观察日下,算术平均(MC 20 万路径)6.1646871、有限差分 6.18993503、几何平均解析 5.945642。也就是说,不写清构造方式的「亚式期权价格」是不完整的。以合约条款与官方文档为准。
蒙特卡洛和树引擎的结果差多少算正常?
本机实测(同一平值看涨):解析基准 10.46814839,CRR 801 步 10.47026038(201.75 ppm),蒙特卡洛 100 万路径 10.46907932(88.93 ppm),两者相差约 0.0001。在几十到两百 ppm 之内属数值方法噪声;差到 1% 以上就要查输入而不是调步数。以官方文档与你的容差要求为准。
为什么 QuantLib 不给我 vega?
引擎能力不同:本机实测 BinomialVanillaEngine 取 vega() 直接抛 RuntimeError: vega not provided,蒙特卡洛引擎连 delta 都不给。需要希腊字母时用解析引擎(欧式)或有限差分引擎,或者自己对波动率加扰动、重新定价做差分(方法见本页第 4 个板块)。以官方文档中各引擎的能力说明为准。
美式看涨一定比欧式贵吗?
不一定。本站实测:无分红时美式(CRR 801)10.47026038 对欧式 10.46814839,差 0.002112 基本是树的离散误差;分红 6% 时差才扩大到 0.18423737。在无分红的假设下,提前行权不划算,两者理论上相等。真实标的有分红日历,应按合约条款与市场惯例处理。
用 QuantLib 算期权需要在 EasyClaw 里配置什么吗?
不需要,也没有可配置项:QuantLib 是运行在本机的 Python / C++ 库,与 EasyClaw 无已证实集成。另一条路线是本机量化研究类技能(如 quant-analyst 侧重回测与风险指标方法论、akshare-finance 侧重取行情数据),两者各自独立、任务不同;那边给出的结果同样仅供研究,不构成投资建议。
本页的价格能直接拿去做交易决策吗?
不能。本页全部是受控实验:固定波动率 20%、固定利率 5%、虚构标的,目的是让引擎差异可比较、可复现。真实定价需要市场隐含波动率曲面、真实利率与分红、以及你所在市场的合约条款;结果仅供研究与学习参考,不构成投资建议。