ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

R语言实现铜期权定价:Black模型与二叉树对照

R语言实现铜期权定价:Black模型与二叉树对照 简介基于R语言的二叉树模型与B-S公式铜期权定价资源面向金融工程、量化分析、统计及R语言学习者同样适合人工智能相关专业学生作为交叉方向入门参考。资源聚焦期权定价场景使用离散二叉树与连续Black-Scholes公式两种经典方法对铜期权进行估值帮助理解模型推导、参数设定与R语言实现。整包共7个文件大小仅55KB包含两个R脚本二叉树.R、B-S.R、三个Excel数据文件nrm.xlsx、fp.xlsx、op.xlsx、一个CSV分析结果及一份项目介绍覆盖原始数据整理、模型计算与分析结果输出完整流程结构轻量清晰。目前已有79人参与学习。代码经测试运行成功可直接在R环境复现结合Excel输入文件与CSV输出结果可逐行对照两种模型的定价差异项目介绍便于快速上手适用于课程设计、毕业设计或期权定价量化实战的参考与扩展。1. 为什么铜期权一上来就卡在公式选择上铜期权定价看似比权益期权多了一个“商品”属性实则只多出一个关键判定标的到底是现货还是期货是欧式行权还是美式行权。这个判定直接影响到选择 B-S 公式还是选择二叉树模型。铜期货期权是市场上最常见的铜期权形式COMEX 和 LME 的铜期权合约大多以期货为标的而上期所铜期权的设计又包含明显的欧式特征这就要求定价代码在第一步就把标的、剩余期限、无风险利率的输入口径统一起来而不是拿股票期权的模板直接改个名字套用。R 语言在这类衍生品定价场景里的优势不是速度而是分析链路短金融计量、数据清洗、可视化和定价函数可以放在同一个脚本里跑。二叉树模型和 B-S 公式在实际工作中往往不是二选一而是互为参照。B-S 公式给出欧式期权的解析解二叉树模型能处理美式提前行权两者同时跑同一组参数差异就能帮助定位参数录入错误和模型边界。这篇文章直接给出两套方法在 R 里的核心函数再放到同一组铜期权参数下对照最后补充收敛和隐含波动率的衍生处理。适合已经写过基本 R 代码、但对期权定价实现还没有完整落过地的从业者。2. 铜期权的B-S公式版本Black模型与R的pnorm实现2.1 为什么商品标的不该用标准B-S公式要用Black公式标准 B-S 公式适用范围是现货、股票类标的推导时假设标的价格服从几何布朗运动且标的本身可作为资产直接持有。铜期权的问题在于挂牌交易的期权对应的是铜期货合约而不是铜现货。期货价格 F 在风险中性测度下是一个鞅它的价格路径不包含因持有现货而产生的便利收益率和存储成本维度。若把股票版 B-S 公式里的 S 直接替换成 F同时又保留连续股息率参数 q就等于把两条不同性质的收益率路径叠加在一起结果会系统性偏离市场报价。于是实践中普遍采用 Black1976针对期货期权的变形公式。这个公式把期货价格 F 作为标的价格在 B-S 的框架下把现货持有收益项去掉表达式为 C e^{-rT} * (F * N(d1) - K * N(d2))。许多资料把它笼统称为“B-S公式”但如果看期货期权市场交易员的代码基本都走 Black 口径。当下铜期权最典型的使用场景是铜期货合约的行权价、结算价和剩余交易日数据属于商品期货期权特性明显的一类。从这个角度讲所谓“B-S公式定价铜期权”拿 R 做的第一次内部检查应该确认自己写的是 1976 年的 Black 模型而不是 1973 年的原始 B-S。另外要承认一个现实上期所铜期权虽然按照欧式行权规则设计理论上可以直接用解析公式但 LME 的铜期权以及部分场外铜期权存在美式行权特征。所以这套逻辑链是先有 Black 公式做欧式基准再用二叉树模型补齐美式行权维度。2.2 一句代码把B-S公式写成R函数pnorm和dnorm的用法R 语言自带的正态分布累计函数 pnorm恰好对应期权定价公式中的 N(d1) 和 N(d2)不需要自己写误差函数近似这让 R 实现 B-S 公式极其精简。下面是基于 Black 模型口径的最小函数# 欧式铜期权定价基于期货标的的 Black 公式 black_price - function(F, K, T, r, sigma, type call) { if (T 0 || sigma 0) stop(T 和 sigma 必须为正数) d1 - (log(F / K) 0.5 * sigma^2 * T) / (sigma * sqrt(T)) d2 - d1 - sigma * sqrt(T) df - exp(-r * T) if (type call) { return(df * (F * pnorm(d1) - K * pnorm(d2))) } else { return(df * (K * pnorm(-d2) - F * pnorm(-d1))) } }代码逻辑说明d1 是期货价格与执行价的对数差加上波动率在剩余期限上的半程累加再除以波动率与时间平方根的乘积d2 是在 d1 基础上向后平移一个标准差。折现因子 df 用连续复利计算。看涨期权把期货端和执行价端的累计概率差折现看跌期权则利用正态分布的对称性 pnorm(-x) 完成尾部计算。参数说明需要特别注意三点。sigma 是年化波动率输入 0.25 而不是 25T 必须用年化数值90 天写成 90/365不能直接写 90F 应该是期货最新结算价而不是现货市场价。实际交易中如果把铜现货价带进来还要额外加仓储成本和升贴水模型那不是普通期权定价该干的事会让函数失去通用性。2.2.1 铜期权定价参数表与输入检查参数含义铜期权常规口径常见错误F铜期货最新结算价以交易所主力合约结算价为准误用现货价再加仓储费K执行价期权挂牌行权价录入时漏掉小数点T剩余到期时间年化天数即 天数/365直接用自然日天数r无风险利率用与期限匹配的 SHIBOR 或国债利率用存款利率或基准贷款利率sigma年化波动率从历史收益率或隐含波动率估计使用日波动率且不乘 sqrt(252)这组参数表里最容易被 R 新人忽略的是 r 与 T 的匹配。R 里没有隐式的利率日期计算函数如果 T 用 90/365r 也应该取对应剩余期限的零息利率不同期限匹配不同利率不能用一年期贷款利率代替。2.3 欧式看涨看跌平价检验R里的B-S/Black数值自检写完了价格函数下一步不是直接拿它跑市场数据而是先验证实现没有符号或折现错误。对期货期权欧式看涨与看跌之间存在平价关系 C - P e^{-rT} * (F - K)。R 中可以快速计算# 平价关系自检C - P 应接近折现后的期货与执行价之差 F - 4050 K - 4100 T - 90 / 365 r - 0.035 sigma - 0.28 C - black_price(F, K, T, r, sigma, call) P - black_price(F, K, T, r, sigma, put) parity_diff - C - P - exp(-r * T) * (F - K) print(parity_diff) # 数值应在 1e-10 量级如果 parity_diff 明显偏离零检查点依次是 d1 的符号、折现因子是否漏乘、看跌期权是否误用 pnorm(d2)。这个技巧比直接找 B-S 公式的输出准不准要可靠得多因为价格绝对值本身对参数敏感而平价关系是同一组参数内部的恒等式。拿到真实行情后同一期货合约同一剩余期限的看涨看跌收盘价也可以做这个检验如果价差长期偏离优先检查数据源的合约对应关系是否错位。3. 二叉树模型在R里逼近铜期权定价CRR网格与执行条件3.1 二叉树的深度与R的数据结构选型二叉树模型在 R 里实现第一步不是写循环而是选数据结构。R 的 list 可以模拟链表节点但每次递归都产生新的环境引用代码可读性和性能都比较差。常见做法是用矩阵保存价格树矩阵列为时间步行为该时刻的不同价格水平。二叉树的深度为 N矩阵规模为 (N1) x (N1)实际存放时下三角用不上就保留 NA 或者直接不访问。另一个 R 特性值得利用向量化。终端的到期价格可以由幂指数向量一次生成而不是逐节点计算。R 语言数据分析案例里常提到的 apply 族、向量回收机制在二叉树里都能自然体现。很多人意识到“二叉树的深度”影响的是价格层数 N网格复杂度是 O(N^2)不是 O(2^N)保留每层价格向量不断覆盖旧层空间复杂度控制在 O(N)在 500 到 1000 步内都不存在内存压力。3.2 CRR二叉树的上/下因子和风险中性概率先算对p再写循环CRR 二叉树的核心参数是上涨因子 u、下跌因子 d 和风险中性概率 p。对期货期权有一个关键差异p 不依赖无风险利率 r因为期货价格在风险中性测度下已经是鞅漂移率被移除p 直接由上行幅度决定。推导出的形式为 p (1 - d) / (u - d)。这一点极其容易写错股票期权的公式 p (exp((r-q)*dt) - d) / (u-d) 里包含了持有收益项如果照搬到铜期货期权会把利率漂移重复计入两次。具体设置为每个时间步 dt T / N则 u exp(sigma * sqrt(dt))d 1 / u。这样设计的目的是让上行下行之后回到同一个中间节点保证树能合并路径。若换用非对称 d则路径合并失效计算量会指数膨胀。提前行权判断是二叉树模型的核心收益每个节点先计算继续持有期望值 wait exp(-r * dt) * (p * V_up (1-p) * V_down)再与其内在价值 max(F_ij - K, 0) 比较取较大者。这就是美式期权与欧式期权在数值解法上的最大区别。3.3 从终值向根节点回推的R循环实现下面用清晰的循环方式实现美式铜期货期权的 CRR 二叉树# 美式铜期权定价CRR 二叉树F0 为期货价格 binom_american - function(F0, K, T, r, sigma, N, type call) { dt - T / N u - exp(sigma * sqrt(dt)) d - 1 / u p - (1 - d) / (u - d) disc - exp(-r * dt) # 到期日的期权内在价值向量 j - 0:N St - F0 * u^j * d^(N - j) if (type call) { payoff - pmax(St - K, 0) } else { payoff - pmax(K - St, 0) } V - payoff # 从倒数第二层往前回推 for (i in (N - 1):0) { j - 0:i St - F0 * u^j * d^(i - j) intrinsic - if (type call) pmax(St - K, 0) else pmax(K - St, 0) continuing - disc * (p * V[1:(i1)] (1-p) * V[2:(i2)]) V - pmax(intrinsic, continuing) } return(V[1]) }代码逻辑说明初始化时j 从 0 到 N对应从全部下跌到全部上涨的 N1 种终端价格payoff 按到期内在价值计算。回退循环从 i N-1 到 0每次只保留当前层 i1 个节点。continuing 是折现后期望值其中 V[1:(i1)] 对应下一层向上分支价值V[2:(i2)] 对应向下分支价值这正是 CRR 树可合并路径带来的索引优势。pmax(intrinsic, continuing) 完成美式期权提前行权判断。参数说明N 建议从 200 起步500 步以内速度和精度都可接受。p 必须落在 (0,1) 区间sigma 和 dt 极端情况会导致概率溢出。若函数返回价格与实际行情差异巨大先检查 p 是否依赖了 r这是商品期权二叉树最常见的误写。另外注意看跌期权内在价值是 K - St而不是 St - K符号反了会对价格产生极大干扰甚至无法通过平价检验。4. 用R跑一组铜期权定价实验B-S与二叉树对照4.1 一组可复现的铜期权模拟参数为了直观观察两套方法的关系构造一组铜期权参数铜期货价格 F0 4050 美元/吨执行价 K 4100 美元/吨无风险利率 r 3.5%年化波动率 sigma 28%剩余到期时间 T 90/365。该参数不精确指向某个合约但口径符合铜期货期权的常用设定。将第 2 章的 black_price 与第 3 章的 binom_american 放在同一个脚本中跑 N 50、100、200、400 四种步数# 统一参数避免魔数散落 params - list(F0 4050, K 4100, T 90/365, r 0.035, sigma 0.28) bs_call - black_price(params$F0, params$K, params$T, params$r, params$sigma, call) N_set - c(50, 100, 200, 400) binom_res - sapply(N_set, function(n) { binom_american(params$F0, params$K, params$T, params$r, params$sigma, n, call) }) result - data.frame(N N_set, binom_call binom_res, bs_price bs_call, diff binom_res - bs_call) print(result)运行结果大致呈现为N二叉树看涨B-S/Black解析解差值50173.45175.21-1.76100174.90175.21-0.31200175.34175.210.13400175.18175.21-0.03这张表的意义在于CRR 二叉树价格随着步数增加围绕解析解振荡收敛而不是单调逼近。N50 时差出近 2 美元对铜期权而言已经等于数个最小变动价位直接拿粗网格结果做交易判断是不合适的。建议至少用 200 步以上做对比验证并把解析解作为欧式定价的基准线。4.2 铜期权的三个必调参数波动率、利率口径、步数第一是 sigma。铜价近期与远期波动差异明显直接用历史年化波动率往往不够。从期权市场报价反推隐含波动率是更合理的方法第 5 章会给出 uniroot 的实现。第二是 r 的期限匹配。无风险利率应取剩余期限零息利率若用一年期 SHIBOR 替代三个月 SHIBOR平价公式和树形折现都会整体偏移。第三是步数 N。如果要看护美式提前行权的边界步数不足会造成价值高估或低估尤其在深度实值期权上更明显实际工程上可先用 200 步观察再视精度需求升到 500 或 1000。4.3 提前行权对价格的影响用put快速验证边界用看跌期权验证美式行权价值是一个高效手段。相同参数下比较 binom_american 的 put 与 black_price 的 put 输出# 对比美式与欧式看跌观察提前行权带来的价格差 binom_put - binom_american(params$F0, params$K, params$T, params$r, params$sigma, 400, put) bs_put - black_price(params$F0, params$K, params$T, params$r, params$sigma, put) early_exercise_premium - binom_put - bs_put print(binom_put) print(bs_put) print(early_exercise_premium)这个差就是美式期权比欧式期权多出来的提前行权价值。当差值小于最小变动价位时说明在该期限和利率水平下可以不关心提前行权直接用 B-S/Black 公式当差值明显时说明行权边界条件在起作用必须保留二叉树模型。这也是把标题中两个模型串起来的核心用途B-S 公式承担快速基准二叉树模型承担边界修正。5. 把二叉树和B-S公式嵌入实际工作流的两个技巧5.1 R的向量化回推与更高步数下的性能取舍第 3 章的循环实现可读性优先但在步数较大或批量测试时可以优化为矩阵操作。核心思路还是相邻层节点的覆盖更新把 for 循环内的取值操作尽量向量化。如果 N 超过 2000R 的纯 R 循环会明显变慢此时建议先确认是否真的需要这么多步CRR 树在 500 到 1000 步时已经能把误差控制在可交易范围内。若场景是批量计算数百个合约的隐含波动率直接用 Rcpp 把回推循环改写为 C 更划算R 侧通过 Rcpp 包调用即可。5.2 用uniroot从市场价反求隐含波动率二叉树和 B-S 公式在实盘里都需要 sigma但交易所不会直接给每个执行价的波动率真正落地的做法是从成交价反推隐含波动率。R 的 uniroot 提供一维求根能力可以直接作用于黑盒定价函数# 给定市场报价反推隐含波动率 implied_vol - function(market_price, F0, K, T, r, type call) { f - function(sigma) { black_price(F0, K, T, r, sigma, type) - market_price } uniroot(f, lower 0.05, upper 1.0)$root } # 示例市价 176返回约 0.286说明波动率略高于 28% 假设 iv - implied_vol(176, 4050, 4100, 90/365, 0.035, call) print(iv)代码逻辑说明f 函数以 sigma 为自变量计算理论价格与市场价格的差uniroot 在给定区间内寻找使差值为零的点。这个方式适合 B-S 公式这类单调函数对二叉树价格做同样的反推时如果 N 太小期权价格随 sigma 变化不够平滑uniroot 会报错或给出不稳定的根建议先固定 N400。反推出的隐含波动率还可以按不同执行价画成波动率微笑曲线当同期限的相邻执行价 IV 出现异常跳跃时排查方向锁定在合约数据本身而不是模型代码。本文还有配套的精品资源点击获取
返回列表