BDT利率二叉树

作者: estate47 | 来源:发表于2019-06-18 18:27 被阅读0次
    利率树在金融债券方面具有广泛的应用,对债券利率的趋势分析、利率路经预测、各种利率结构债券的定价等都具有重要的参考意义。债券的定价就是确定债券的真实价值,债券的价值就是其未来现金流的现值,现值体现了现金流的时间价值。如果在贴现计算的时候,对于各个时间期限的现金流我们都是采用同样的贴现率,这样的估值方法我们称之为传统估价法。这种估价的方法存在一个缺陷,每期贴现都采用同一个贴现率使其存在套利的空间,而无套利估价的方法则弥补了这个缺陷。无套利估价的方法是将债券的每一个现金流都看成是一个独立的零息现金流,对于不同期限的现金流都采用不同的贴现率来进行贴现,这样就可以避免通过分离债券来获得套利收益。这样的零息利率我们也称之为即期利率。 image.png

    BDT二叉树无套利算法的构建
    我们假设零息债券如下表所示。表中,0.20代表的是一年即期利率的波动率,依次类推,0.19代表的是两年即期利率的波动率。


    image.png

    BDT模型假设了利率服从对数正态分布,导致波动率是利率取自然对数之后的波动率。因此有:


    image.png

    除了上面式子,BDT和其它无套利模型构成的二叉树定价模型是完全一样的。
    步骤1:构建第一阶段利率二叉树。
    二叉树根部数据就是0.1,因此不用做任何修改。对于第一阶段二叉树的两个端点r_H,r_L需要使用两年期的即期利率和其对应的波动率,方程为:


    image.png

    步骤2:构建第二阶段利率二叉树:
    需要使用三年期即期利率以及相应的波动率。首先需要解决的是当年的三年期即期利率在一年后变成两年期的即期利率r_H3和r_L3。
    根据风险中性定价方程和波动率方程分别为:

    image.png

    步骤3:构建第三阶段利率二叉树
    同上需要使用四年的零息债券和其对应的波动率0.17构建方程:


    image.png
    image.png
    image.png

    更多阶二叉树依此类推,以上就是基于无套利定价二叉树算法。

    用python实现代码如下: BDT.xlsx
    import math
    import pandas as pd
    import numpy as np
    import sympy as sp
    import os
    
    
    data = pd.read_excel("BDT.xlsx")
    N = data.shape[0]
    p_tilda = 1 / 2
    data.index = np.arange(1, N + 1)
    
    data['Rate'] = (data['Rate']) / 10
    
    T = data['Term']
    T.index = np.arange(0, N)
    T = np.array(T)
    T1 = T / 360
    "probability matrix"
    P = np.full((N + 1, N + 1), p_tilda)
    
    "rates matrix"
    R = np.zeros((N, N))
    R[0, 0] = data['Rate'][1]
    
    AD = np.zeros((N, N, N, N))
    AD[0, 0, 0, 0] = 1
    
    TIME_ZERO_BOND_PRICES = []
    
    
    def martingale_pricing(i, n, j):
        if i == j - 1:
            ad = P[n - 1, j - 1] / (1 + R[n - 1, j - 1]) ** (T1[n - 1])
        elif i == j:
            ad = (1 - P[n - 1, j]) / (1 + R[n - 1, j]) ** (T1[n - 1])
        else:
            ad = 0
        AD[n - 1, i, n, j] = ad
    
    
    def jfi(n, i, m, j):
        if j == 0:
            ad = AD[n, i, m - 1, j] * (1 - P[m - 1][j]) / (1 + R[m - 1][j]) ** (T1[m - 1])
        elif 0 < j & j < m:
            ad = AD[n, i, m - 1, j] * (1 - P[m - 1][j]) / (1 + R[m - 1][j]) ** (T1[m - 1]) + AD[n, i, m - 1, j - 1] * (
                P[m - 1][j - 1]) / (1 + R[m - 1][j - 1]) ** (T1[m - 1])
        elif j == m:
            ad = AD[n, i, m - 1, j - 1] * (P[m - 1][j - 1]) / (1 + R[m - 1][j - 1]) ** (T1[m - 1])
        AD[n, i, m, j] = ad
    
    
    def rate_vol(x):
        return (1 / 2) * math.log(x)
    
    
    yield_tree = np.zeros((2, N))
    for n in range(1, N):
    
        r = sp.Symbol('r')
        sigma = sp.Symbol('sigma')
    
        for j in range(0, n + 1):
            jfi(0, 0, n, j)
    
        bond_price = pow(1 + data['Rate'][n + 1], -(n + 1) * T1[n])  #
        TIME_ZERO_BOND_PRICES.append(bond_price)
    
        if n == 1:
    
            rate_volatility = math.exp(2 * data['VAR'][n + 1] / math.sqrt(1 / T1[n]))
            B = sum([AD[0, 0, n, j] / (1 + r * pow(rate_volatility, j)) for j in range(0, n + 1)])
            rate = np.array([sp.re(x) for x in sp.solvers.solve(bond_price - B, r)])
            rate = rate[rate > 0][0]
        else:
    
            B = sum([AD[0, 0, n, j] / (1 + r * pow(sigma / math.sqrt(1 / T1[n]), j)) for j in range(0, n + 1)])
    
        if n > 1:
    
            Y = []
            for i in range(0, 2):
                p = 0
                for j in range(0, n + 1):
                    martingale_pricing(i, n, j)
                    if n > 2:
                        jfi(1, i, n, j)
                    p += (AD[1, i, n, j]) / (1 + r * pow(sigma / math.sqrt(1 / T1[n - 1]), j))  # P[1,i,n+1]
                Y.append(pow(p, -(1 / n)) - 1)
    
            solution = sp.nsolve(
                [Y[0] * math.exp(2 * data['VAR'][n + 1] / math.sqrt(1 / T1[n - 1])) - Y[1], bond_price - B],
                [r, sigma], [0.08, 0.01])
            rate = solution[0]
            rate_volatility = solution[1]
    
        if n > 1:
            for i in range(0, 2):
                p = 0  #
                for j in range(0, n + 1):
                    p += (AD[1, i, n, j]) / (1 + rate * pow(rate_volatility, j))  # P[1,i,n+1]
                yield_tree[i, n] = pow(p, -(1 / n)) - 1
    
        print('Time {} rate volatility is {}'.format(n, rate_vol(rate_volatility)))
    
        R[n][0] = rate  # save the rate to the tree
    
        for j in range(1, n + 1):
            R[n][j] = R[n][0] * pow(rate_volatility, j)
    R = R * 10
    I = []
    for row in R:
        I.extend(row[np.nonzero(row)][::-1])
    
    
    def get_list_by_size(row_size, L="L", R="H"):
        try:
            row_size = int(row_size)
        except Exception:
            raise ValueError("row_size:应该为数字")
        H = ['0']
        for i in range(1, row_size + 1):
            H.extend([size * R + L * (i - size) for size in range(i, -1, -1)])
        return H
    
    
    H = get_list_by_size(N - 1)
    Z = {'EdgeLabel': H,
         'Rate': I}
    frame = pd.DataFrame(Z)
    
    print(frame)
    
    输出结果: image.png

    相关文章

      网友评论

        本文标题:BDT利率二叉树

        本文链接:https://www.haomeiwen.com/subject/hcdqqctx.html