Physics-Informed Neural Networks for Options Pricing
將 PINN 應用於衍生品的有趣之處不在於 Black-Scholes。Black-Scholes 有封閉形式;能夠重現它的網路只是合理性檢查,而不是成果。有趣的是那些沒有封閉形式、且有限差分也無法繼續前進的問題:帶有混合偏導數 的 Heston 雙因子 PDE、美式選擇權的自由邊界問題,以及 Merton 的偏積分微分方程,其積分項會把定義域中的每一個點與其他所有點耦合起來。
本文說明如何將上述每一項放入損失函數。具體包括:讓 Black-Scholes PINN 能夠訓練的對數價格殘差、交叉導數由 autograd 自動取得的三輸入 Heston 網路、以懲罰項和雙網路處理提前履約,以及將跳躍積分放入 PDE 殘差的 Gauss-Hermite 求積法。
本文不是基準測試。下文任何看似結果的數字,要麼是目標,要麼是引用,並且會明確標示。測量工作範圍列在文末。
PINN 由 Raissi 等人(2019)提出;本部落格的 Navier-Stokes 問題已介紹其運作方式,其中同樣的自動微分殘差技巧用於在流體方程中尋找奇異點:PDE 變成損失項,自動微分提供網路相對於輸入的精確導數,而且完全不需要建立網格。這裡唯一改變的是放入損失函數的 PDE。
將 Black-Scholes PDE 作為物理約束

Black-Scholes PDE、其終端支付 以及背後的無套利論證,已在 Black-Scholes 公式中介紹——本節假定讀者已了解這些內容,直接進入網路實際可以訓練的形式。
對數價格轉換
直接使用 會帶來問題:定義域是 ,而 PDE 含有變動係數。標準變換 可將其轉為常係數形式:
這是定義於 上的對流—擴散—反應方程。變動係數 和 消失了,這對網路很重要:大小隨 縮放的殘差會由定義域的遠端主導,最佳化器也會把資源花在那裡。
Black-Scholes 的 PINN 損失
令 為網路。在內部取樣 個配置點 ,在邊界取樣 個,在終端時間取樣 個:
每個偏導數都透過 torch.autograd.grad 並設定 create_graph=True 計算,因此反向傳播時梯度會穿過導數計算。這個單一旗標就是整個實作技巧的核心。
PyTorch 實作

以下參數帶有加密貨幣特色,而不是教科書設定: 和 (約 30 天的 BTC 選擇權),而非股票交易台常用的 、。短到期日加上高波動率,是支付函數折點最尖銳、PINN 也最難訓練的情境——這正是重點。
import torch
import torch.nn as nn
import numpy as np
r = 0.05 # risk-free rate
sigma = 0.7 # volatility
K = 1.0 # strike (moneyness-normalized)
T = 0.08 # ~30 days
x_min, x_max = -1.0, 1.0 # log-price domain (S/K in [0.37, 2.72])
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
class BSPINN(nn.Module):
"""Physics-Informed Neural Network for Black-Scholes PDE."""
def __init__(self, hidden_dim=128, num_layers=4):
super().__init__()
layers = [nn.Linear(2, hidden_dim), nn.Tanh()]
for _ in range(num_layers - 1):
layers += [nn.Linear(hidden_dim, hidden_dim), nn.Tanh()]
layers.append(nn.Linear(hidden_dim, 1))
self.net = nn.Sequential(*layers)
def forward(self, x, t):
inputs = torch.cat([x, t], dim=1)
return self.net(inputs)
def compute_pde_residual(model, x, t):
"""Compute Black-Scholes PDE residual using autodiff."""
x.requires_grad_(True)
t.requires_grad_(True)
u = model(x, t)
grads = torch.autograd.grad(u, [x, t], grad_outputs=torch.ones_like(u),
create_graph=True)
u_x, u_t = grads[0], grads[1]
u_xx = torch.autograd.grad(u_x, x, grad_outputs=torch.ones_like(u_x),
create_graph=True)[0]
residual = u_t + 0.5 * sigma**2 * u_xx + (r - 0.5 * sigma**2) * u_x - r * u
return residual
def terminal_condition(x):
"""European call payoff: max(S - K, 0) = max(exp(x) - K, 0)."""
return torch.relu(torch.exp(x) - K)
def train_pinn(epochs=10000, lr=1e-3, n_interior=5000, n_boundary=500, n_terminal=1000):
model = BSPINN().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs)
for epoch in range(epochs):
optimizer.zero_grad()
x_int = (torch.rand(n_interior, 1, device=device)
* (x_max - x_min) + x_min)
t_int = torch.rand(n_interior, 1, device=device) * T
residual = compute_pde_residual(model, x_int, t_int)
loss_pde = (residual ** 2).mean()
x_tc = (torch.rand(n_terminal, 1, device=device)
* (x_max - x_min) + x_min)
t_tc = torch.ones(n_terminal, 1, device=device) * T
u_tc = model(x_tc, t_tc)
loss_ic = ((u_tc - terminal_condition(x_tc)) ** 2).mean()
t_bc = torch.rand(n_boundary, 1, device=device) * T
x_lo = torch.full((n_boundary, 1), x_min, device=device)
loss_bc_lo = (model(x_lo, t_bc) ** 2).mean()
x_hi = torch.full((n_boundary, 1), x_max, device=device)
target_hi = torch.exp(x_hi) - K * torch.exp(-r * (T - t_bc))
loss_bc_hi = ((model(x_hi, t_bc) - target_hi) ** 2).mean()
loss = loss_pde + 10.0 * loss_ic + loss_bc_lo + loss_bc_hi
loss.backward()
optimizer.step()
scheduler.step()
if epoch % 1000 == 0:
print(f"Epoch {epoch:5d} | PDE: {loss_pde:.2e} | "
f"IC: {loss_ic:.2e} | BC: {loss_bc_lo + loss_bc_hi:.2e}")
return model
有兩個結構選擇值得特別指出:
- 終端條件的權重。 支付函數的權重為 10 倍,因為它定義了問題。若不強制執行,網路可以到處輸出零而輕易滿足 PDE——齊次 PDE 有無限多個解,終端條件才是選出其中一個的條件。
- 每個 epoch 重新取樣配置點。 每一步都重新抽取點,對殘差形成隨機正則化。另一種做法是固定點集,這會讓網路在那些精確座標上對殘差過度擬合。
延伸至 Heston 隨機波動率模型

Black-Scholes 使用單一常數 定價,而這正是 GARCH(1,1) 波動率預測所要否定的假設。Heston 將波動率變成第二個隨機因子,即瞬時變異數 :
其中 是均值回歸速度, 是長期變異數, 是波動率的波動率,且 。
定價 PDE 在狀態上是二維的:
這正是無網格方法開始顯得有吸引力的地方。有限差分方法需要在 上建立網格——典型的 就是 個節點。再加入隨機利率等第三個隨機因子,網格就變得不可行。蒙地卡羅在維度增加時擴展性較好,但收斂很慢,尤其是對 Greeks 而言。
Heston 的 PINN 架構
網路接收三個輸入 ,其中 。混合偏導數 ——讓 ADI 方法變得棘手的那一項——只需再呼叫一次 autograd.grad:
class HestonPINN(nn.Module):
def __init__(self, hidden_dim=256, num_layers=5):
super().__init__()
layers = [nn.Linear(3, hidden_dim), nn.Tanh()]
for _ in range(num_layers - 1):
layers += [nn.Linear(hidden_dim, hidden_dim), nn.Tanh()]
layers.append(nn.Linear(hidden_dim, 1))
self.net = nn.Sequential(*layers)
def forward(self, x, v, t):
return self.net(torch.cat([x, v, t], dim=1))
def heston_pde_residual(model, x, v, t, kappa, theta, xi, rho, r):
x.requires_grad_(True)
v.requires_grad_(True)
t.requires_grad_(True)
u = model(x, v, t)
u_x, u_v, u_t = torch.autograd.grad(
u, [x, v, t], torch.ones_like(u), create_graph=True
)
u_xx = torch.autograd.grad(u_x, x, torch.ones_like(u_x), create_graph=True)[0]
u_vv = torch.autograd.grad(u_v, v, torch.ones_like(u_v), create_graph=True)[0]
u_xv = torch.autograd.grad(u_x, v, torch.ones_like(u_x), create_graph=True)[0]
residual = (
u_t
+ 0.5 * v * u_xx
+ rho * xi * v * u_xv
+ 0.5 * xi**2 * v * u_vv
+ (r - 0.5 * v) * u_x
+ kappa * (theta - v) * u_v
- r * u
)
return residual
請注意,u_xv 是對 u_x 關於 v 微分得到的,重用了第一次呼叫建立的計算圖。混合偏導數的對稱性意味著,對 u_v 關於 x 微分應得到相同張量;但在 float32 中不會完全相同,而兩者的差距可以低成本診斷計算圖是否正常運作。
美式選擇權與自由邊界問題

美式選擇權增加了提前履約約束:價值永遠不能低於內在價值。這會把 PDE 變成自由邊界問題,等價於線性互補問題(LCP):
其中 是 Black-Scholes 算子, 是支付函數。有兩種方式可以將它放入損失。
懲罰方法
以平滑懲罰項取代互補約束:
其中 很大(通常為 到 )。當 低於內在價值時,懲罰項會迫使它回升,PINN 損失變為:
架構不變,只修改殘差。代價是增加一個新的超參數,並帶來糟糕的條件數權衡:太小則約束會被違反,太大則損失地形會被懲罰項主導。
直接自由邊界方法
聯合訓練兩個網路:一個用於價格 ,另一個用於最佳履約邊界 。損失在繼續區域中包含 PDE、邊界處的平滑貼合條件,以及履約區域中的支付函數。邊界會以一級輸出的形式產生,而這正是對美式選擇權部位進行避險真正需要的結果。
以 PINN 處理跳躍擴散模型

Merton 模型在幾何布朗運動中加入 Poisson 跳躍:
其中 是強度為 且跳躍大小服從對數常態分布的複合 Poisson 過程。定價因此成為偏積分微分方程(PIDE):
其中 是跳躍乘數的密度。
積分正是有限差分難以處理的部分——它將定義域中的每個點與其他所有點耦合,破壞解算器所依賴的帶狀結構。PINN 沒有這種結構可被破壞。積分只是殘差中的另一項,在每個配置點透過求積計算;而且由於網路處處有定義, 是一次免費的前向傳遞,而非插值:
def jump_integral(model, x, t, lam, mu_j, sigma_j, n_quad=32):
"""Approximate jump integral using Gauss-Hermite quadrature."""
nodes, weights = np.polynomial.hermite.hermgauss(n_quad)
nodes = torch.tensor(nodes, dtype=torch.float32, device=x.device)
weights = torch.tensor(weights, dtype=torch.float32, device=x.device)
y_nodes = mu_j + sigma_j * np.sqrt(2) * nodes
integral = torch.zeros_like(x)
for i in range(n_quad):
x_shifted = x + y_nodes[i]
v_shifted = model(x_shifted, t)
integral += weights[i] * v_shifted
integral *= 1.0 / np.sqrt(np.pi)
return integral
PIDE 殘差於是為:
其中 是求積近似。每個訓練步驟的迴圈都會額外耗費 n_quad 次前向傳遞,且全部都會進入 autograd 計算圖——跳躍真正的代價是記憶體,而非數學運算。
與傳統方法的比較

結構上的差異確實存在,不需要基準測試也能說明:
| 標準 | 有限差分 | 蒙地卡羅 | PINN |
|---|---|---|---|
| 需要網格/網格剖分 | 是(結構化網格) | 否 | 否(無網格) |
| 維度詛咒 | 嚴重(>3D 不可行) | 輕微( 收斂) | 輕微(隨網路容量擴展) |
| Greeks | 有限差分近似 | 路徑法/LR 估計量 | 透過自動微分精確取得 |
| 跨參數重用 | 必須重新求解 | 必須重新模擬 | 參數化:訓練一次 |
| 美式選擇權 | LCP 上的 SOR/PSOR | Longstaff-Schwartz 回歸 | 懲罰項或自由邊界 |
| 誤差界限 | 有(方法階數) | 有(CLT) | 無——只有經驗損失 |
通常應該出現在這裡的效能列——訓練時間、推理延遲、準確度——被刻意省略,因為測量它們是尚待完成的工作,而不是表格中的一項。
PINN 可能勝出的地方
即時重新定價。 訓練完成後,評估只需對一個批次進行前向傳遞,因此整個部位可以在一次核心啟動中重新定價,而不是每組參數各求解一次。在實際部位規模下這是否勝過調校良好的 Crank-Nicolson 解算器,仍是尚未測量的實證問題。
高維模型。 隨機波動率加上隨機利率再加上跳躍會達到 4 個以上的維度,此時有限差分實際上已不可行。PINN 的維度擴展會較為平緩,但仍受訓練難度限制。
連續 Greeks。 網路平滑且可微,因此 Delta、Gamma、Theta 和 Vega 都來自與 PDE 殘差相同的 autograd 機制——不需要 bump-and-revalue,也沒有有限差分雜訊。這是本文最強的主張,也是最需要背後有測量過的 Gamma 曲面的主張。
參數化解。 將模型參數(、、)作為網路輸入,就能讓一個 PINN 覆蓋一族模型,而不只是一個校準結果。
PINN 面臨困難的地方
訓練成本。 對單一參數組合下的單一選擇權,有限差分解算在 PINN 完成前一千個 epoch 之前就已經結束。
沒有誤差界限。 使用 Richardson 外推的有限差分可按已知收斂階數達到機器精度。PINN 回報的是損失值,而不是誤差界限。不確定性感知變體(Bai 等人,2025)會附帶信賴區間,但這個領域仍很年輕。
最佳化困難。 損失地形高度非凸,而 PDE、邊界和終端項之間的權重是一個調參問題。典型故障是網路把 PDE 殘差降到接近零,卻完全忽略邊界條件——那是對錯誤問題的完全有效解。
可重現性。 不同的隨機種子、配置點分布和最佳化器設定,可能得到實質不同的解。集成有幫助,但也會增加成本。
後兩項是本文最值得轉成圖表的部分,因為任何重新實作本文的人都會遇到這些失敗模式。
仍需要測量的內容

本文目前的真實狀態是:公式正確,程式碼也能執行,但尚未在本團隊的硬體或資料上進行基準測試。要讓它從推導變成結果,需要完成以下測量:
- 在 網格上相對於封閉形式 Black-Scholes 的 sup-norm 與 RMSE,每個種子各測一次,共五個種子。通常流傳的目標是吻合到小數點後 4 位以上;重點是在 、 下驗證這一點,並公布失敗時所用的種子。
- Delta 和 Gamma 誤差,而不只是價格誤差。 如果網路價格吻合到四位數,但 帶有雜訊,對避險就毫無用處,因此 Gamma 是驗收標準。
- 10,000 個選擇權部位的實際訓練時間與單一選擇權推理延遲,並與相同 GPU 上對同一問題進行的 Crank-Nicolson 解算比較。
- 刻意重現失敗模式。 降低邊界損失權重,直到網路滿足 PDE 卻錯過邊界;執行五個種子並繪製其差異。兩項實驗成本都很低,也比再畫一個看似正確的價格曲面更有用。
- 擬合真實 Deribit BTC 報價,或至少保留上面的加密貨幣實際參數,不要退回 、。
- 把架構和最佳化器選擇當作研究結果,而非建議。 寬度與深度的比較、
tanh與 ReLU 的比較(ReLU 不連續的二階導數應該會明顯破壞殘差)、 掃描,以及 Adam 接 L-BFGS 與只用 Adam 的比較,都是一行就能設定的實驗。在實際執行前,它們都只是從文獻反覆傳述的經驗說法;本文不把它們重複成建議。
即使沒有測量,仍有兩項結構性主張成立,因為它們是公式的性質,而不是某次執行的性質:使用對數價格座標(PDE 變成常係數形式,這是代數上的事實),以及讓終端條件的權重高於 PDE 項(齊次 PDE 接受零解,這是問題本身的事實)。
其他研究方向

以下方向值得了解,但本文都沒有測試:
- 殘差自適應配置取樣——在殘差較大的地方放置點,例如 Black-Scholes 的履約價附近或 Heston 的 Feller 邊界附近,而不是均勻取樣。實作很短:
def adaptive_resample(model, x_pool, t_pool, n_select):
"""Select collocation points with highest PDE residual."""
with torch.no_grad():
residuals = compute_pde_residual(model, x_pool, t_pool).abs()
probs = residuals.squeeze() / residuals.sum()
indices = torch.multinomial(probs, n_select, replacement=False)
return x_pool[indices], t_pool[indices]
- 跨履約價和到期日的遷移學習——從相鄰的 微調,而不是從頭訓練,以維護覆蓋整個選擇權鏈的模型庫。
- 物理資訊極限學習機——凍結隱藏層權重,只訓練輸出層,將訓練簡化成一次線性求解。表達能力較弱,但 Black-Scholes 的維度足夠低,可能不成問題。
- 算子學習(DeepONet、FNO)——學習解算子而不是解本身,將 映射,因此新的支付函數結構不需要重新訓練。參見 DeepSVM。
結論

PINN 不會取代有限差分或蒙地卡羅。對單一參數組合下的單一低維選擇權,有限差分會勝出,而且差距不小。PINN 的適用範圍狹窄而明確:網格在其中失效的高維模型、可在整個部位重複使用的參數化解,以及與價格共享同一次自動微分傳遞所得到的 Greeks。
本文提供的是轉換層——說明 Heston 混合偏導數、美式自由邊界和 Merton 跳躍積分如何各自成為損失函數中的一項。本文尚未提供的,是由此產生的網路是否足夠準確、可以用於避險的證據。那是下一輪工作;在它完成之前,請將以上內容視為推導,而不是建議。
參考文獻與延伸閱讀
- Raissi, M., Perdikaris, P., Karniadakis, G.E. (2019)。物理資訊神經網路:解決涉及非線性偏微分方程之正向與逆向問題的深度學習框架。Journal of Computational Physics,378,686-707。
- Dhiman, A., Kaur, D. (2023)。用於選擇權定價的物理資訊神經網路。arXiv 預印本。
- Salvador, B. 等人(2023)。透過物理資訊神經網路進行美式選擇權定價的無網格方法。Engineering Analysis with Boundary Elements。
- Bai, G. 等人(2025)。Black-Scholes 方程的不確定性感知物理資訊神經網路解法。arXiv 預印本。
- Chen, Y. 等人(2025)。資料稀缺情況下、由隨機跳躍擴散過程提供資訊的美式選擇權定價神經網路。Applied Soft Computing。
- Benth, F.E. 等人(2025)。DeepSVM:以物理資訊深度算子網路學習隨機波動率模型。arXiv 預印本。
- He, Y. 等人(2024)。金融資訊神經網路:學習選擇權定價的幾何。arXiv 預印本。
- MathWorks:用於選擇權定價的物理資訊神經網路(PINN)。MATLAB Finance Blog,2025。
- GitHub:BlackScholesPINN(PyTorch 實作)。
- Raissi PINN GitHub 儲存庫。
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.