怎样计算亚式期权的 theta?
theta 可能是最难计算的一个期权参数,时间变了,一切都变了。
怎样计算亚式期权的 theta?
采用 Turnbull-Wakeman1 或 Levy2 近似公式计算亚式期权的价格时,都需要一个特定的参数——当前平均价格,也就是观察起始日到估值日这一段时间窗口内价格的平均值。举个例子,观察起始日是 2026-AUG-1,估值日是 2026-AUG-5,当前平均价格就是 2026-AUG-1、2026-AUG-2、2026-AUG-3 和 2026-AUG-4 这四天价格的平均值。
当前平均价格表面上看是一个常量,其实它是一个和时间有关的变量,这使得计算亚式期权的 theta 时需要小心处理这个参数的值。
以 Turnbull-Wakeman 近似公式为例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import numpy as np
from financepy.utils.date import Date
from financepy.utils.global_types import OptionTypes
from financepy.utils.math import normcdf
def TurnbullWakeman(
t0,
t_exp,
tau,
s,
k,
r,
q,
v,
accrued_average,
opt_type_int
):
'''
:param t0: start averaging date to value date
:param t_exp: value date to expiry date
:param tau: start averaging date to expiry date
:param s: spot price
:param k: strike price
:param r: risk-free rate
:param q: dividend yield
:param v: volatility
:param accrued_average: accrued average price
:param opt_type_int: Call(1), Put(2)
:return: Asian option price
'''
multiplier = 1.0
if t0 < 0: # we are in the averaging period
# we adjust the strike to account for the accrued coupon
k = (k * tau + accrued_average * t0) / t_exp
# the number of options is rescaled also
multiplier = t_exp / tau
# there is no pre-averaging time
t0 = 0.0
# need to handle this
b = r - q
sigma2 = v ** 2
a1 = b + sigma2
a2 = 2 * b + sigma2
s0 = s
dt = t_exp - t0
if b == 0:
m1 = 1.0
m2 = 2.0 * np.exp(sigma2 * t_exp) - 2.0 * np.exp(sigma2 * t0) * (
1.0 + sigma2 * dt
)
m2 = m2 / sigma2 / sigma2 / dt / dt
else:
m1 = s0 * (np.exp(b * t_exp) - np.exp(b * t0)) / (b * dt)
m2 = np.exp(a2 * t_exp) / a1 / a2 / dt / dt + (
np.exp(a2 * t0) / b / dt / dt
) * (1.0 / a2 - np.exp(b * dt) / a1)
m2 = 2.0 * m2 * s0 * s0
f0 = m1
sigma2 = (1.0 / t_exp) * np.log(m2 / m1 / m1)
sigma = np.sqrt(sigma2)
d1 = (np.log(f0 / k) + sigma2 * t_exp / 2) / sigma / np.sqrt(t_exp)
d2 = d1 - sigma * np.sqrt(t_exp)
if opt_type_int == OptionTypes.EUROPEAN_CALL.value:
call = np.exp(-r * t_exp) * (f0 * normcdf(d1) - k * normcdf(d2))
v = call
elif opt_type_int == OptionTypes.EUROPEAN_PUT.value:
put = np.exp(-r * t_exp) * (k * normcdf(-d2) - f0 * normcdf(-d1))
v = put
else:
return None
v = v * multiplier
return v
用差分法计算 theta 时,如果假定“当前平均价格”是常量,将得到一个错误的结果。正确的做法是根据时间差分的数值更新当前平均价格,用更新的参数计算期权价格。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from financepy.utils.date import Date
s = 100
k = 100
r = 0.05
q = 0.03
v = 0.2
opt_type_int = OptionTypes.EUROPEAN_PUT.value
start_averaging_date = Date(1, 8, 2026)
value_date = Date(5, 8, 2026)
expiry_date = Date(31, 8, 2026)
days_peer_year = 365
t0 = (start_averaging_date - value_date) / days_peer_year
t_exp = (expiry_date - value_date) / days_peer_year
tau = (expiry_date - start_averaging_date) / days_peer_year
accrued_average = (104 + 103 + 102 + 101) / 4.0
# accrued_average = (96 + 97 + 98 + 99) / 4.0
call = TurnbullWakeman(t0, t_exp, tau, s, k, r, q, v, accrued_average, opt_type_int)
print("npv:", call)
ds = 1
call_up = TurnbullWakeman(t0, t_exp, tau, s + ds, k, r, q, v, accrued_average, opt_type_int)
call_dn = TurnbullWakeman(t0, t_exp, tau, s - ds, k, r, q, v, accrued_average, opt_type_int)
delta = (call_up - call_dn) / (2 * ds)
print("delta:", delta)
gamma = (call_up - 2 * call + call_dn) / (ds ** 2)
print("gamma:", gamma)
dt = 1e-3
call_next = TurnbullWakeman(t0 - dt, t_exp - dt, tau, s, k, r, q, v, accrued_average, opt_type_int)
theta_one_day = (call_next - call) / dt * 1 / days_peer_year
print("wrong theta_one_day:", theta_one_day)
accrued_average_next = (-accrued_average * t0 + s * dt) / (-t0 + dt)
call_next = TurnbullWakeman(t0 - dt, t_exp - dt, tau, s, k, r, q, v, accrued_average_next, opt_type_int)
theta_one_day = (call_next - call) / dt * 1 / days_peer_year
print("reasonable theta_one_day:", theta_one_day)
1
2
3
4
5
npv: 0.8751257730086413
delta: -0.37710904369368664
gamma: 0.10943927075583715
wrong theta_one_day: -0.09505525169875748
reasonable theta_one_day: -0.05819583706393781
由更新当前平均价格的逻辑可以得知,当参数
t0恰好等于 0 的时候,accrued_average应该等于s才是合理的。
下面验证一下上述更新当前平均价格的逻辑合理的。
首先,模拟出 2026-AUG-6 可能的价格,再计算出这一天亚式期权的价格。通常情况下,用 theta、delta 和 gamma 构造的线性近似可以解释大部分期权价格的变化。下面以期权价格的变化量为因变量,资产价格的变化量为自变量,建立一个二次多项式回归模型。得到的截距和回归参数分别对应 theta、delta 和二分之一 gamma。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
value_date_next = Date(6, 8, 2026)
t0 = (start_averaging_date - value_date_next) / days_peer_year
t_exp = (expiry_date - value_date_next) / days_peer_year
tau = (expiry_date - start_averaging_date) / days_peer_year
dt = 1 / days_peer_year
np.random.seed(42)
s_next = s * np.exp(
(r - q - 0.5 * v ** 2) * dt
+ v * np.sqrt(dt) * np.random.normal(size=200)
)
accrued_average_next = (accrued_average * 4 + s) / 5
call_next = np.array(
[TurnbullWakeman(t0, t_exp, tau, price, k, r, q, v, accrued_average_next, opt_type_int) for
price in s_next]
)
delta_s = s_next - s
delta_s2 = delta_s ** 2
delta_call = call_next - call
import statsmodels.api as sm
X = sm.add_constant(np.column_stack((delta_s, delta_s2)))
model = sm.OLS(delta_call, X).fit()
print(model.summary())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 1.000
Model: OLS Adj. R-squared: 1.000
Method: Least Squares F-statistic: 1.589e+06
Date: Sat, 26 Sep 2026 Prob (F-statistic): 0.00
Time: 18:07:50 Log-Likelihood: 892.02
No. Observations: 200 AIC: -1778.
Df Residuals: 197 BIC: -1768.
Df Model: 2
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -0.0566 0.000 -231.298 0.000 -0.057 -0.056
x1 -0.3627 0.000 -1766.535 0.000 -0.363 -0.362
x2 0.0513 0.000 343.595 0.000 0.051 0.052
==============================================================================
Omnibus: 184.249 Durbin-Watson: 1.959
Prob(Omnibus): 0.000 Jarque-Bera (JB): 6122.068
Skew: -3.247 Prob(JB): 0.00
Kurtosis: 29.315 Cond. No. 2.34
==============================================================================
可以看出来,x1 和 x2 的系数和差分得到的 delta 和二分之一 gamma 基本一致,截距和一日 theta 基本一致,和错误的 theta 相差甚远。
本文由作者按照 CC BY 4.0 进行授权