- 金融科技
- 科学计算
【免费下载链接】tf-quant-finance
High-performance TensorFlow library for quantitative finance.
导读
本文围绕 tf-quant-finance 中tf_quant_finance.experimental.lsm_algorithm模块展开,系统讲解基于 Longstaff & Schwartz(2001)回归法的最小二乘蒙特卡洛(LSM)美式期权定价实现:从 API 概览、least_square_mc与least_square_mc_v2两代定价入口的参数语义,到多项式基函数、篮子看跌期权 payoff 构造,再到与仓库源码、测试用例对照的算法原理纵深。读完本文,你将能够用该模块完成"模拟标的路径 → 构造 payoff 与基函数 → 回归求最优停时 → 折现均值"的完整美式期权定价流程,并理解 v2 版本为 XLA 兼容与批量估值所做的工程取舍。
模块定位与整体 API 结构
lsm_algorithm模块位于tf_quant_finance/experimental/下,模块 docstring 概括为"LSM algorithm methods"(LSM 算法方法集)。模块级索引文档 api_docs/tf_quant_finance/experimental/lsm_algorithm.md 列出了全部 5 个公开符号,定义于 tf_quant_finance/experimental/lsm_algorithm/init.py:
| 公开 API | 来源文件 | 作用 |
|---|---|---|
least_square_mc | lsm.py | 用 LSM 算法为美式期权定价(基础版) |
least_square_mc_v2 | lsm_v2.py | 用 LSM 算法为美式期权定价(XLA 兼容、支持 batch 与样本校准划分) |
make_basket_put_payoff | payoff.py | 从样本构造简单篮子看跌期权的 payoff 可调用对象 |
make_polynomial_basis | lsm.py | 构造用于回归的多项式基函数(v1 版) |
make_polynomial_basis_v2 | lsm_v2.py | 构造用于回归的多项式基函数(v2 版,带时间索引参数) |
模块级导入后可通过tff.experimental.lsm_algorithm.least_square_mc等形式调用(tff.experimental.__init__.py第 20 行将lsm_algorithm纳入公开子模块)。在 Bazel 构建体系中,BUILD 将其拆分为lsm、lsm_v2、payoff三个py_library,并配套lsm_test、lsm_v2_test、payoff_test三个py_test目标。
LSM 算法原理回顾
least_square_mc的 docstring 对算法思想作了如下概括(与 lsm.py 一致):
最小二乘蒙特卡洛(LSM)算法是一种估值美式期权的蒙特卡洛方法。利用标的资产的样本路径和用户提供的 payoff 函数,它尝试为每条样本路径找到最优行权点;在已知最优行权点后,期权价值被定义为"假设最优行权"下的平均 payoff 并折现到现值。
这一思想源自文献:Longstaff, F.A. and Schwartz, E.S., 2001.Valuing American options by simulation: a simple least-squares approach. The review of financial studies, 14(1), pp.113–147。与普通蒙特卡洛只模拟到期 payoff 不同,美式期权允许在到期前的任意可行时点行权,因此核心难点在于估计每个时刻"继续持有"的期望价值(continuation value)。LSM 的巧妙之处在于:从后往前在每个可行行权时点,用该时点"实值路径"的样本做横截面回归(以当前标的价格的函数为解释变量,以未来已折现最优现金流为响应变量),得到条件期望函数的近似,再逐条路径比较"立即行权收益"与"继续持有期望",从而回溯出最优停时。
least_square_mc:基础版定价入口
函数签名与参数语义
tf_quant_finance.experimental.lsm_algorithm.least_square_mc( sample_paths, exercise_times, payoff_fn, basis_fn, discount_factors=None, dtype=None, name=None )各参数含义(详见 least_square_mc.md):
sample_paths:形状为[num_samples, num_times, dim]的Tensor,即底层 Ito 过程在num_times个时间点上的dim维样本路径。exercise_times:形状为[num_exercise_times]的int32Tensor,元素必须是[0, ..., num_times - 1]的子集,表示期权可行权的时点 tick。payoff_fn:可调用对象,输入形状[num_samples, num_times, dim]的样本与一个表示当前时间索引的整数标量,输出形状[num_samples, payoff_dim]的Tensor(dtype 与样本一致),表示在该时点立即行权的支付。payoff_dim允许在同一标的资产(samples)上并行估值多个期权。basis_fn:可调用对象,输入形状[num_samples, dim]的样本,输出形状[basis_size, num_samples]的Tensor,即用于回归持有价值的设计矩阵。discount_factors:形状[num_exercise_times]或[num_samples, num_exercise_times]的Tensor,第 k 个元素表示时间 tick k 处的折现因子。默认None,映射为与样本同 dtype、形状[num_exercise_times]的全 1Tensor。dtype:可选tf.float32或tf.float64,指定输入输出Tensor的 dtype;默认None时由 TensorFlow 推断。name:Pythonstr,为函数创建的 Op 添加前缀;默认None映射为'least_square_mc'。
返回值:形状[num_samples, payoff_dim]、与samples同 dtype 的Tensor。
源码级执行流程
从 lsm.py 的实现可以看到以下关键步骤:
- 输入规整:
sample_paths、exercise_times、discount_factors统一转为Tensor;若discount_factors缺省则构造全 1 折现向量;若其 rank 为 1,则扩展为[1, num_exercise_times](第 204-205 行),并在末尾concat一个值为 1 的前缀元素,使discount_factors[0] == 1代表 0 时刻的折现因子(第 207-209 行)。 - 现金流初始化:取最后一个可行权 tick,调用
payoff_fn得到到期 payoff(形状[num_samples, payoff_dim]),并在其后拼接num_times - 1个 0,构成形状[num_samples, payoff_dim, num_exercise]的cashflow张量(第 212-221 行)。 - 倒推循环:通过
tf.while_loop以LsmLoopVars(exercise_index, cashflow)为循环变量,从num_times - 1递减到 0(循环条件exercise_index > 0,见lsm_loop_cond第 236-239 行)。循环体_lsm_loop_body(第 354-380 行)每个迭代执行:- 计算当前 tick 的即时行权价值
exercise_value = payoff_fn(sample_paths, tick); - 用
continuation_value_fn将当前索引右侧的现金流折现到当前时点,得到"继续持有"的现值(第 242-269 行,折现比例由discount_factors[..., exercise_index + 1:] / discount_factors[..., exercise_index]给出); - 取
sample_paths[:, tick, :]调用basis_fn构造回归设计矩阵; - 调用
expected_exercise_fn做最小二乘回归,得到每条路径期望持有价值(详见下文); - 调用
_updated_cashflow(第 318-351 行)更新现金流:当exercise_value > expected_continuation时判定该路径应提前行权,写入新的现金流并将之后的现金流置零。
- 计算当前 tick 的即时行权价值
- 定价输出:循环结束后用
continuation_value_fn(loop_value.cashflow, discount_factors, 0)将现金流折现到 0 时刻,再对样本维度做reduce_mean(第 231-233 行),即得平均最优行权 payoff 的现值。
回归核心:expected_exercise_fn
回归的数学本质在 lsm.py 的注释中交代得很清楚:对于设计矩阵 X 与响应 y,最优线性无偏估计系数 β 满足正规方程X'X β = X'y。实现细节包括:
- 仅在实值路径上回归:
mask = cast(exercise_value > 0, ...)将非实值路径的设计矩阵行清零(第 297-300 行),因为"永远不会在该时点行权"的样本不影响回归系数;注释同时指出,同一组样本路径在不同 payoff 下实值集合不同,因此batch_design通过broadcast_to为每个 payoff 维复制一份设计矩阵。 - 伪逆保证数值稳定:
lhs = matmul(masked, masked, transpose_a=True)后用tf.linalg.pinv(lhs)计算伪逆(第 305-308 行),避免病态矩阵导致的数值不稳定。 - 结果截断:最终返回
tf.maximum(continuation, 0.0)(第 315 行),即期望持有价值不小于 0——这与"继续持有期权不会带来负的期望价值"的金融直觉一致。
论文示例的测试验证
lsm_test.py 直接复现了 Longstaff & Schwartz 论文 Section 1 的经典 8 条路径、3 个行权时刻算例:
samples = [[1.0, 1.09, 1.08, 1.34], [1.0, 1.16, 1.26, 1.54], [1.0, 1.22, 1.07, 1.03], [1.0, 0.93, 0.97, 0.92], [1.0, 1.11, 1.56, 1.52], [1.0, 0.76, 0.77, 0.90], [1.0, 0.92, 0.84, 1.01], [1.0, 0.88, 1.22, 1.34]] # 每两期之间的利率为 0.06,对应折现因子 interest_rates = [0.06, 0.06, 0.06] discount_factors = np.exp(-np.cumsum(interest_rates))test_american_option_put(lsm_test.py)用make_polynomial_basis(2)与make_basket_put_payoff([1.1]),在exercise_times=[1, 2, 3]下得到美式看跌价格0.1144;test_european_option_put仅在exercise_times=[3]行权,得到欧式价格0.0564,与论文手算结果吻合。这组测试同时验证了算法在tf.float32/tf.float64两种精度下都稳定。
make_basket_put_payoff:篮子看跌 payoff 构造器
tf_quant_finance.experimental.lsm_algorithm.make_basket_put_payoff( strike_price, dtype=None, name=None )strike_price:与样本 dtype 一致的Tensor,形状[num_samples, num_strikes],可同时为多个行权价构造 payoff。dtype/name:语义同前,name默认'put_valuer'。- 返回:一个可调用对象,输入形状
[num_samples, num_exercise_times, dim]的样本与当前时间标量,输出形状[num_samples, num_strikes]的 payoff。
底层实现在 payoff.py 的_put_valuer中:取出time_index处的切片样本,对最后一维(篮子成分维度dim)求平均average = reduce_mean(slice_sample_paths, axis=-1),再返回tf.nn.relu(strike_price - average),即篮子平均价格低于行权价的差额(不为负)。它通过functools.partial把strike_price绑定进闭包形成可调用对象。值得注意,该实现天然兼容 batch 输入:rank 为 3 时自动expand_dims到[num_samples, 1, num_times, dim],rank 为 4 时转置为[num_samples, batch_size, num_times, dim](第 79-84 行)。
payoff_test.py 给出了可直接对拍的手算期望:对 strike[1.1, 1.2]、末时刻样本,第 3 条路径(1.03)的 payoff 为[0.07, 0.17],第 4 条路径(0.92)为[0.18, 0.28],第 6 条路径(0.90)为[0.2, 0.3]等。
make_polynomial_basis:回归用的多项式基函数
tf_quant_finance.experimental.lsm_algorithm.make_polynomial_basis(degree)degree:int32标量,期望的多项式次数;若小于 0,tf.debugging.assert_greater_equal会抛出断言(docstring 声明为ValueError,见 lsm.py)。- 返回:输入
[num_samples, dim]、输出[degree * dim, num_samples]的可调用对象。
核心逻辑(lsm.py):先做中心化Y = X - mean(X, axis=0),再构造次数从 0 到degree的完整单项式网格并做reduce_prod,最后转置。docstring 中的示例(degree=2, dim=2)说明其展开包含1, X, X**2, Y, Y**2, X*Y, X**2*Y, X*Y**2等项。附带的数值示例:
basis = make_polynomial_basis(2) x = [1.0, 2.0, 3.0, 4.0] x = tf.expand_dims(x, -1) basis(x) # Expected result: # [[ 1.0, 1.0, 1.0, 1.0], [-1.5, -0.5, 0.5, 1.5]]第一行是常数项 1,第二行是中心化后的X - mean(X)(均值为 2.5,故为-1.5, -0.5, 0.5, 1.5)。注意此处输出形状为[degree * dim, num_samples],与 v2 版本存在差异(见下)。
least_square_mc_v2:XLA 兼容的升级版
签名差异
tf_quant_finance.experimental.lsm_algorithm.least_square_mc_v2( sample_paths, exercise_times, payoff_fn, basis_fn, discount_factors=None, num_calibration_samples=None, dtype=None, name=None )与 v1 相比,v2(lsm_v2.py)的核心变化体现在:
- 支持 batch 维度:
sample_paths可为[num_samples, num_times, dim]或[batch_size, num_samples, num_times, dim],batch_size允许并行估值多个期权(通过 payoff 的"多个标的"或"多组样本路径"两种方式,见 lsm_v2_test.py 中test_american_option_put_batch_samples与test_american_option_put_batch_payoff)。相应地payoff_fn输出形状变为[num_samples, batch_size],basis_fn需接收完整样本路径与时间索引两个参数,输出[batch_size, basis_size, num_samples]。 - 新增
num_calibration_samples:可选整数,不超过num_samples,指定用于 LSM 回归步骤的路径条数;注意定价时只用最后num_samples - num_calibration_samples条路径(第 284-286 行),即"回归用前 N 条、定价用后 M 条",以降低用同一批样本既做回归又做定价带来的偏差。默认None表示所有样本同时用于回归与定价。 - 静态形状与 XLA 兼容:文件头部 docstring(第 15-26 行)明确说明,v2 是为XLA 兼容而设计——
_continuation_value_fn、_expected_exercise_fn、_updated_cashflow内部所有张量均为静态形状(用tf.where+ 固定形状掩码替代 v1 中的动态拼接),代价是内存占用上升,且"某些情况下可能比不做 XLA 编译的旧版慢"。make_polynomial_basis_v2输出的函数额外带time_index参数(内部用tf.slice按索引切片,避免动态形状张量),这也是它与 v1 基函数的主要区别。 - 折现因子 rank 3 支持:
discount_factors可为[num_exercise_times]或与[num_samples, batch_size, num_exercise_times]兼容的 rank 3 张量(第 243-249 行用tf.pad前置 1)。 - 回归细节:
_expected_exercise_fn(第 331-386 行)在 v1 的"实值掩码 + 伪逆"基础上增加calibration_indices的tf.gather子采样;输出用tf.nn.relu截断非负。
v2 的回归基函数:make_polynomial_basis_v2
tf_quant_finance.experimental.lsm_algorithm.make_polynomial_basis_v2(degree)与 v1 的差异在于返回的可调用对象接收(sample_paths, time_index)两个参数:内部先按time_index切片出当前时点的样本,再中心化并做幂网格展开(lsm_v2.py)。输出形状为[batch_size, (degree + 1)**dim, num_samples]——注意 v2 是完整的(degree + 1)**dim个单项式(含所有交叉项与常数项),而 v1 docstring 写作[degree * dim, num_samples]并宣称展开含X*Y等交叉项,两者展开的项数规则并不相同,选用时需按形状断言核对。文档自带示例:
basis = tff.experimental.lsm_algorithm.make_polynomial_basis_v2(2) x = [[1.0], [2.0], [3.0], [4.0]] x = tf.expand_dims(x, axis=-1) basis(x, tf.constant(0, dtype=np.int32)) # Expected result: # [[ 1. , 1. , 1. , 1. ], [-1.5 , -0.5 , 0.5 , 1.5 ], # [ 2.25, 0.25, 0.25, 2.25]]即[常数项 1, 中心化一次项 X-2.5, 中心化二次项 (X-2.5)**2]。
端到端实战:欧式/美式看跌期权定价对照
主文档least_square_mc与least_square_mc_v2均附有同一份完整示例(lsm.py、lsm_v2.py),下面给出修正笔误后的可运行版本(原文档中lsm_price(...)应为least_square_mc(...),strikes应为strike):
import numpy as np import tensorflow as tf import tf_quant_finance as tff from tf_quant_finance.experimental.lsm_algorithm import ( least_square_mc, make_basket_put_payoff, make_polynomial_basis) # 标的为 Black-Scholes 过程:dS_t / S_t = rate dt + sigma**2 dW_t,S_0 = 1.0 # 其中 rate = 0.1,波动率 sigma = 1.0。先定义 log(S_t) 的漂移与波动函数 rate = 0.1 def drift_fn(_, x): return rate - tf.ones_like(x) / 2. def vol_fn(_, x): return tf.expand_dims(tf.ones_like(x), -1) # 用 Euler 格式将 100000 条路径向前推进 1 年 times = np.linspace(0., 1, num=50) num_samples = 100000 log_paths = tf.function(tff.models.euler_sampling.sample)( dim=1, drift_fn=drift_fn, volatility_fn=vol_fn, random_type=tff.math.random.RandomType.PSEUDO_ANTITHETIC, times=times, num_samples=num_samples, seed=42, time_step=0.01) # 取指数还原 S_t 样本 paths = tf.math.exp(log_paths) # 行权价 1.1、期限 1 年的美式看跌期权 strike = [1.1] exercise_times = tf.range(times.shape[-1]) discount_factors = tf.exp(-rate * times) payoff_fn = make_basket_put_payoff(strike) basis_fn = make_polynomial_basis(10) american_price = least_square_mc(paths, exercise_times, payoff_fn, basis_fn, discount_factors=discount_factors) # 期望结果:约 [0.397] # 对照:同一标的的欧式看跌期权(仅到期行权) european_price = tff.black_scholes.option_price( volatilities=[1], strikes=strike, expiries=[1], spots=[1.], discount_factors=discount_factors[-1], is_call_options=False, dtype=tf.float64) # 期望结果:约 [0.379]该示例要点:
- 路径模拟复用 euler_sampling.sample,随机数采用
PSEUDO_ANTITHETIC(对偶变量)降低方差,seed=42保证可复现; - 每条路径在 50 个时间点采样,
exercise_times = tf.range(50)表示每个采样点都可行权; - 美式价格(约 0.397)高于欧式价格(约 0.379),差值即为"提前行权权利"的价值——这是检验 LSM 定价合理性的直观判据。
选型建议与注意事项
- v1 与 v2 的取舍:v2 是为 XLA 编译设计的静态形状实现(lsm_v2.py),更契合
tf.function/ XLA 加速场景;v1 动态拼接在某些非 XLA 场景下可能更快、内存占用更低。若需并行估值多个期权或使用num_calibration_samples防过拟合,应选 v2。 - 基函数与 degree 选择:
degree过小(如 1~2)回归精度不足,过大则设计矩阵膨胀、过拟合风险上升。论文示例与测试用degree=2即可在 8 条路径上精确复现;蒙特卡洛大样本场景常用 10 阶(主文档示例),但仍需结合标的维度权衡(degree+1)**dim的爆炸式增长。 - 仅实值路径参与回归:
expected_exercise_fn用exercise_value > 0掩码(lsm.py),实值判定的直觉是"虚值路径在当期必不行权",这与 Longstaff-Schwartz 原始论文一致。 - dtype 一致性:
discount_factors、strike_price需与sample_pathsdtype 一致;定价对精度敏感时建议显式传入tf.float64。 - 回归稳定性:实现使用
tf.linalg.pinv伪逆求解正规方程(v1/v2 相同),对病态设计矩阵具有较好的容错性。
与稳定版models.longstaff_schwartz的关系
experimental.lsm_algorithm与 models/longstaff_schwartz 是同一算法在仓库中的两条演进线:稳定版tff.models.longstaff_schwartz提供了least_square_mc、make_polynomial_basis、make_basket_put_payoff三个同名 API,其签名(含num_calibration_samples与 batch 支持)与 experimental 下的 v2 版本一致,实现在 models/longstaff_schwartz/lsm.py 中。从源码结构看,experimental 版本更贴近算法原型与研究用途,稳定版则对类型标注、docstring 与 API 规范做了收尾。生产环境建议优先使用models.longstaff_schwartz,研究原型或需要对照两代实现差异时可参考experimental.lsm_algorithm的源码与测试(lsm_test.py、lsm_v2_test.py)。
- 金融科技
- 科学计算
【免费下载链接】tf-quant-finance
High-performance TensorFlow library for quantitative finance.
相关推荐
tf-quant-finance 中 Longstaff-Schwartz 最小二乘蒙特卡洛(LSM)美式期权定价:least_square_mc 的用法、源码原理与测试验证
tf quant finance 中 Longstaff Schwartz 最小二乘蒙特卡洛(LSM)美式期权定价:least_square_mc 的用法、源码
金融科技科学计算tf-quant-finance 中最小二乘蒙特卡洛(LSM)算法实战:向量化定价美式期权
tf quant finance 中最小二乘蒙特卡洛(LSM)算法实战:向量化定价美式期权 本文围绕 tf_quant_finance.models.longs
金融科技科学计算终极指南:如何使用 TensorFlow 量化金融库实现最小二乘蒙特卡洛算法
终极指南:如何使用 TensorFlow 量化金融库实现最小二乘蒙特卡洛算法 最小二乘蒙特卡洛算法(LSM)是金融工程中用于美式期权定价的核心技术之一。tf q
金融科技科学计算
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考