Quantlib:如何使用 Hull White 模型為 ZC 債券定價?
我正在嘗試使用 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% 是很長一段時間,而對於短期利率模型來說波動率很大),並平均沿路徑的價格,我看到以下內容,這很好地顯示了隨著到期日的臨近,債券的拉動至面值:
完整修改程式碼:
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 年