程式

Quantlib:如何使用 Hull White 模型為 ZC 債券定價?

  • August 11, 2020

我正在嘗試使用 QuantLib 來模擬短期利率,看起來 QL 在這裡有一些材料 http://gouthamanbalaraman.com/blog/hull-white-simulation-quantlib-python.html

我已經能夠使用實際的期限結構進行模擬,儘管在附加的連結中為簡單起見,GB 假設了平順。這是我在下面使用的。

我正在使用以下程式碼計算時間 t 的零息債券的價格

def price(T, t, r0):
   tau = T - t
   B = (1 - np.exp(-a * tau)) / a
   A = np.exp(-r0 * tau - B * r0 - sigma ** 2 / (4 * a ** 3) *
              (np.exp(-a * T) - np.exp(-a * t)) * (np.exp(2 * a * t) - 1))
   return A * np.exp(-r0 * B)

但我覺得我的 zc 債券價格到處都是。任何線索我在這裡做錯了什麼?

QuantLib 是否提供了一個包裝器來使用 HW 模型計算 zc 價格?

完整程式碼如下

import QuantLib as ql
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd


sigma = 0.1
a = 0.1
length = 30 # in years
steps_per_year = 12
timestep = length * steps_per_year
forward_rate = 0.05
day_count = ql.Thirty360()
todays_date = ql.Date(15, 1, 2015)


ql.Settings.instance().evaluationDate = todays_date

spot_curve = ql.FlatForward(todays_date, ql.QuoteHandle(ql.SimpleQuote(forward_rate)), day_count)
spot_curve_handle = ql.YieldTermStructureHandle(spot_curve)

hw_process = ql.HullWhiteProcess(spot_curve_handle, a, sigma)
rng = ql.GaussianRandomSequenceGenerator(ql.UniformRandomSequenceGenerator(timestep, ql.UniformRandomGenerator()))
seq = ql.GaussianPathGenerator(hw_process, length, timestep, rng, False)


def generate_paths(n_scenarios):
   arr = np.zeros((n_scenarios, timestep+1))
   for i in range(n_scenarios):
       sample_path = seq.next()
       path = sample_path.value()
       time = [path.time(j) for j in range(len(path))]
       value = [path[j] for j in range(len(path))]
       arr[i, :] = np.array(value)
   return np.array(time), arr

n_scenarios = 1
time, paths = generate_paths(n_scenarios)
rates = pd.DataFrame(paths).T



#price a zero coupon bond

n_years = length
num_steps = timestep
dt = 1 / steps_per_year
prices = np.empty_like(rates)


def price(T, t, r0):
   tau = T - t
   B = (1 - np.exp(-a * tau)) / a
   A = np.exp(-r0 * tau - B * r0 - sigma ** 2 / (4 * a ** 3) *
              (np.exp(-a * T) - np.exp(-a * t)) * (np.exp(2 * a * t) - 1))
   return A * np.exp(-r0 * B)

prices[0] = price(n_years,dt*0,rates.values[0])

for steps in range(1,num_steps+1):
   prices[steps] = price(n_years, dt * steps, rates.values[steps])

plt.plot(prices)
plt.show()

這是HW的價格

$$ 4 $$一次 ZCB $ t $ : $$ \begin{align} P(t,T) &= A(t,T) e^{-B(t,T) r(t)}\ A(t,T) &= {\frac {P(0,T)} {P(0,t)}} \exp \Bigl( B(t,T)F(0,t) - {\frac {\sigma^2} {4a}} B(t,T)^2(1-e^{-2at})\Bigr)\ B(t,T) &= {\frac {1-e^{-a(T-t)}} {a}} \end{align} $$

你似乎在模擬評分 $ r(t) $ 有時 $ t $ 並將其放入您的函式參數r0中。我不確定r0應該是什麼,但請注意,上面的等式包括 $ F(0,t) $ - 這只是您的模擬中的一個常數(因為您使用了一條FlatForward曲線,我認為它應該取代您的大部分r0條款,但最後一行應該是return A * np.exp(-rt * B),其中rt是目前的速率值。還有一個符號錯誤B * r0術語,應該+代替-

當我進行這些更改(並稍微降低利率波動率,因為 30 年的 10% 是很長一段時間,而對於短期利率模型來說波動率很大),並平均沿路徑的價格,我看到以下內容,這很好地顯示了隨著到期日的臨近,債券的拉動至面值:

硬體中的 ZCB 價格路徑

完整修改程式碼:

import QuantLib as ql
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd


sigma = 0.01
a = 0.1
length = 30 # in years
steps_per_year = 12
timestep = length * steps_per_year
forward_rate = 0.01
day_count = ql.Thirty360()
todays_date = ql.Date(15, 1, 2015)


ql.Settings.instance().evaluationDate = todays_date

spot_curve = ql.FlatForward(todays_date, ql.QuoteHandle(ql.SimpleQuote(forward_rate)), day_count)
spot_curve_handle = ql.YieldTermStructureHandle(spot_curve)

hw_process = ql.HullWhiteProcess(spot_curve_handle, a, sigma)
rng = ql.GaussianRandomSequenceGenerator(ql.UniformRandomSequenceGenerator(timestep, ql.UniformRandomGenerator()))
seq = ql.GaussianPathGenerator(hw_process, length, timestep, rng, False)


def generate_paths(n_scenarios):
   arr = np.zeros((n_scenarios, timestep+1))
   for i in range(n_scenarios):
       sample_path = seq.next()
       path = sample_path.value()
       time = [path.time(j) for j in range(len(path))]
       value = [path[j] for j in range(len(path))]
       arr[i, :] = np.array(value)
   return np.array(time), arr

n_scenarios = 1000
time, paths = generate_paths(n_scenarios)
rates = pd.DataFrame(paths).T

#price a zero coupon bond
n_years = length
num_steps = timestep
dt = 1 / steps_per_year
prices = np.empty_like(rates)


def price(T, t, f0, rt):
   tau = T - t
   B = (1 - np.exp(-a * tau)) / a
   A = np.exp(-f0 * tau + B * f0 - sigma ** 2 / (4 * a ** 3) *
              (np.exp(-a * T) - np.exp(-a * t)) * (np.exp(2 * a * t) - 1))
   return A * np.exp(-rt * B)

prices[0] = price(n_years,dt*0, forward_rate, rates.values[0])

for steps in range(1,num_steps+1):
   prices[steps] = price(n_years, dt * steps, forward_rate, rates.values[steps])


fig = plt.figure()
plt.figure(figsize=(16,10))

plt.subplot(2, 1, 1)
plt.title("All ZCB paths")
plt.plot(prices)

plt.subplot(2, 1, 2)

ave = [np.mean(x) for x in prices]
plt.plot(ave)
plt.title("Average ZCB paths")

plt.show()

$$ 4 $$: Hull, J., White, A.,“利率衍生證券定價”,金融研究評論,第 3 卷,第 4 期,第 573-592 頁,1990 年

引用自:https://quant.stackexchange.com/questions/57251