def test_FinInterpolatedForwards():

    import matplotlib.pyplot as plt

    tValues = np.array([0.0, 3.0, 5.0, 10.0])
    rValues = np.array([0.04, 0.07, 0.08, 0.09])
    df_values = np.exp(-tValues*rValues)
    tInterpValues = np.linspace(0.0, 12.0, 49)

    curve_date = Date(1, 1, 2019)

    tDates = curve_date.add_years(tValues)
    tInterpDates = curve_date.add_years(tInterpValues)

    for interp_type in InterpTypes:

        discount_curve = DiscountCurve(
            curve_date, tDates, df_values, interp_type)
        dfInterpValues = discount_curve.df(tInterpDates)
        fwdInterpValues = discount_curve.fwd(tInterpDates)
        zeroInterpValues = discount_curve.zero_rate(tInterpDates)

        if PLOT_GRAPHS:
            plt.figure(figsize=(8, 6))
            plt.plot(tValues, df_values, 'o', color='g', label="DFS:")
            plt.plot(tInterpValues, dfInterpValues, color='r',
                     label="DF:" + str(interp_type))
            plt.legend()
            plt.figure(figsize=(8, 6))
            plt.plot(tInterpValues, fwdInterpValues, color='r',
                     label="FWD:" + str(interp_type))
            plt.plot(tInterpValues, zeroInterpValues, color='b',
                     label="ZERO:" + str(interp_type))
            plt.plot(tValues, rValues, 'o', color='g',  label="ZERO RATES")
            plt.legend()
示例#2
0
def test_CDSFastApproximation():

    valuation_date = Date(20, 6, 2018)
    # I build a discount curve that requires no bootstrap
    times = np.linspace(0, 10.0, 11)
    r = 0.05

    discount_factors = np.power((1.0 + r), -times)
    dates = valuation_date.add_years(times)

    libor_curve = DiscountCurve(valuation_date, dates, discount_factors,
                                InterpTypes.FLAT_FWD_RATES)

    ##########################################################################

    maturity_date = valuation_date.next_cds_date(120)
    t = (maturity_date - valuation_date) / 365.242
    z = libor_curve.df(maturity_date)
    r = -np.log(z) / t

    recovery_rate = 0.40

    contractCoupon = 0.010

    testCases.header("MKT_SPD", "EXACT_VALUE", "APPROX_VALUE", "DIFF(%NOT)")

    for mktCoupon in np.linspace(0.000, 0.05, 21):

        cds_contracts = []

        cdsMkt = CDS(valuation_date, maturity_date, mktCoupon, ONE_MILLION)

        cds_contracts.append(cdsMkt)

        issuer_curve = CDSCurve(valuation_date, cds_contracts, libor_curve,
                                recovery_rate)

        cds_contract = CDS(valuation_date, maturity_date, contractCoupon)
        v_exact = cds_contract.value(valuation_date, issuer_curve,
                                     recovery_rate)['full_pv']
        v_approx = cds_contract.value_fast_approx(valuation_date, r, mktCoupon,
                                                  recovery_rate)[0]
        pctdiff = (v_exact - v_approx) / ONE_MILLION * 100.0
        testCases.print(mktCoupon * 10000, v_exact, v_approx, pctdiff)
示例#3
0
def test_IssuerCurveBuild():
    """ Test issuer curve build with simple libor curve to isolate cds
    curve building time cost. """

    valuation_date = Date(20, 6, 2018)

    times = np.linspace(0.0, 10.0, 11)
    r = 0.05
    discount_factors = np.power((1.0 + r), -times)
    dates = valuation_date.add_years(times)
    libor_curve = DiscountCurve(valuation_date, dates, discount_factors,
                                InterpTypes.FLAT_FWD_RATES)
    recovery_rate = 0.40

    cds_contracts = []

    cdsCoupon = 0.005  # 50 bps
    maturity_date = valuation_date.add_months(12)
    cds = CDS(valuation_date, maturity_date, cdsCoupon)
    cds_contracts.append(cds)

    cdsCoupon = 0.0055
    maturity_date = valuation_date.add_months(24)
    cds = CDS(valuation_date, maturity_date, cdsCoupon)
    cds_contracts.append(cds)

    cdsCoupon = 0.0060
    maturity_date = valuation_date.add_months(36)
    cds = CDS(valuation_date, maturity_date, cdsCoupon)
    cds_contracts.append(cds)

    cdsCoupon = 0.0065
    maturity_date = valuation_date.add_months(60)
    cds = CDS(valuation_date, maturity_date, cdsCoupon)
    cds_contracts.append(cds)

    cdsCoupon = 0.0070
    maturity_date = valuation_date.add_months(84)
    cds = CDS(valuation_date, maturity_date, cdsCoupon)
    cds_contracts.append(cds)

    cdsCoupon = 0.0073
    maturity_date = valuation_date.add_months(120)
    cds = CDS(valuation_date, maturity_date, cdsCoupon)
    cds_contracts.append(cds)

    issuer_curve = CDSCurve(valuation_date, cds_contracts, libor_curve,
                            recovery_rate)

    return cds_contracts, issuer_curve
示例#4
0
def test_BondOption():

    settlement_date = Date(1, 12, 2019)
    issue_date = Date(1, 12, 2018)
    maturity_date = settlement_date.add_tenor("10Y")
    coupon = 0.05
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    tmat = (maturity_date - settlement_date) / gDaysInYear
    times = np.linspace(0, tmat, 20)
    dates = settlement_date.add_years(times)
    dfs = np.exp(-0.05*times)
    discount_curve = DiscountCurve(settlement_date, dates, dfs)

    expiry_date = settlement_date.add_tenor("18m")
    strike_price = 105.0
    face = 100.0

    ###########################################################################

    strikes = [80, 85, 90, 95, 100, 105, 110, 115, 120]

    option_type = OptionTypes.EUROPEAN_CALL

    testCases.header("LABEL", "VALUE")

    price = bond.full_price_from_discount_curve(
        settlement_date, discount_curve)
    testCases.print("Fixed Income Price:", price)

    num_time_steps = 20

    testCases.header("OPTION TYPE AND MODEL", "STRIKE", "VALUE")

    for strike_price in strikes:

        sigma = 0.20
        a = 0.1

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a, num_time_steps)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("EUROPEAN CALL - BK", strike_price, v)

    for strike_price in strikes:

        sigma = 0.20
        a = 0.05

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a, num_time_steps)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("EUROPEAN CALL - BK", strike_price, v)

    ###########################################################################

    option_type = OptionTypes.AMERICAN_CALL

    price = bond.full_price_from_discount_curve(
        settlement_date, discount_curve)
    testCases.header("LABEL", "VALUE")
    testCases.print("Fixed Income Price:", price)

    testCases.header("OPTION TYPE AND MODEL", "STRIKE", "VALUE")

    for strike_price in strikes:

        sigma = 0.01
        a = 0.1

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("AMERICAN CALL - BK", strike_price, v)

    for strike_price in strikes:

        sigma = 0.20
        a = 0.05

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("AMERICAN CALL - BK", strike_price, v)

    ###########################################################################

    option_type = OptionTypes.EUROPEAN_PUT

    price = bond.full_price_from_discount_curve(
        settlement_date, discount_curve)

    for strike_price in strikes:

        sigma = 0.01
        a = 0.1

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("EUROPEAN PUT - BK", strike_price, v)

    for strike_price in strikes:

        sigma = 0.20
        a = 0.05

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("EUROPEAN PUT - BK", strike_price, v)

    ###########################################################################

    option_type = OptionTypes.AMERICAN_PUT

    price = bond.full_price_from_discount_curve(
        settlement_date, discount_curve)

    for strike_price in strikes:

        sigma = 0.02
        a = 0.1

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("AMERICAN PUT - BK", strike_price, v)

    for strike_price in strikes:

        sigma = 0.20
        a = 0.05

        bond_option = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model = BKTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print("AMERICAN PUT - BK", strike_price, v)
示例#5
0
def test_BKExampleTwo():
    # Valuation of a European option on a coupon bearing bond
    # This follows example in Fig 28.11 of John Hull's book but does not
    # have the exact same dt so there are some differences

    settlement_date = Date(1, 12, 2019)
    issue_date = Date(1, 12, 2018)
    expiry_date = settlement_date.add_tenor("18m")
    maturity_date = settlement_date.add_tenor("10Y")
    coupon = 0.05
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    coupon_times = []
    coupon_flows = []
    cpn = bond._coupon / bond._frequency
    num_flows = len(bond._flow_dates)

    for i in range(1, num_flows):
        pcd = bond._flow_dates[i - 1]
        ncd = bond._flow_dates[i]
        if pcd < settlement_date and ncd > settlement_date:
            flow_time = (pcd - settlement_date) / gDaysInYear
            coupon_times.append(flow_time)
            coupon_flows.append(cpn)

    for flow_date in bond._flow_dates:
        if flow_date > settlement_date:
            flow_time = (flow_date - settlement_date) / gDaysInYear
            coupon_times.append(flow_time)
            coupon_flows.append(cpn)

    coupon_times = np.array(coupon_times)
    coupon_flows = np.array(coupon_flows)

    strike_price = 105.0
    face = 100.0

    tmat = (maturity_date - settlement_date) / gDaysInYear
    texp = (expiry_date - settlement_date) / gDaysInYear
    times = np.linspace(0, tmat, 11)
    dates = settlement_date.add_years(times)
    dfs = np.exp(-0.05 * times)
    curve = DiscountCurve(settlement_date, dates, dfs)

    price = bond.clean_price_from_discount_curve(settlement_date, curve)
    testCases.header("LABEL", "VALUE")
    testCases.print("Fixed Income Price:", price)

    sigma = 0.20
    a = 0.05
    num_time_steps = 26

    model = BKTree(sigma, a, num_time_steps)
    model.build_tree(tmat, times, dfs)
    exercise_type = FinExerciseTypes.AMERICAN
    v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows,
                          exercise_type)

    # Test convergence
    num_steps_list = [100, 200, 300, 500, 1000]
    exercise_type = FinExerciseTypes.AMERICAN

    testCases.header("TIMESTEPS", "TIME", "VALUE")
    treeVector = []
    for num_time_steps in num_steps_list:
        start = time.time()
        model = BKTree(sigma, a, num_time_steps)
        model.build_tree(tmat, times, dfs)
        v = model.bond_option(texp, strike_price, face, coupon_times,
                              coupon_flows, exercise_type)
        end = time.time()
        period = end - start
        treeVector.append(v)
        testCases.print(num_time_steps, period, v)

#    plt.plot(num_steps_list, treeVector)

# Value in Hill converges to 0.699 with 100 time steps while I get 0.700

    if 1 == 0:
        print("RT")
        print_tree(model._rt, 5)
        print("Q")
        print_tree(model._Q, 5)
def test_BKExampleTwo():
    # Valuation of a European option on a coupon bearing bond
    # This follows example in Fig 28.11 of John Hull's book but does not
    # have the exact same dt so there are some differences

    settlement_date = Date(1, 12, 2019)
    issue_date = Date(1, 12, 2018)
    expiry_date = settlement_date.add_tenor("18m")
    maturity_date = settlement_date.add_tenor("10Y")
    coupon = 0.05
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    coupon_times = []
    coupon_flows = []
    cpn = bond._coupon / bond._frequency
    num_flows = len(bond._coupon_dates)

    for i in range(1, num_flows):
        pcd = bond._coupon_dates[i - 1]
        ncd = bond._coupon_dates[i]
        if pcd < settlement_date and ncd > settlement_date:
            flow_time = (pcd - settlement_date) / gDaysInYear
            coupon_times.append(flow_time)
            coupon_flows.append(cpn)

    for flow_date in bond._coupon_dates:
        if flow_date > settlement_date:
            flow_time = (flow_date - settlement_date) / gDaysInYear
            coupon_times.append(flow_time)
            coupon_flows.append(cpn)

    coupon_times = np.array(coupon_times)
    coupon_flows = np.array(coupon_flows)

    strike_price = 105.0
    face = 100.0

    tmat = (maturity_date - settlement_date) / gDaysInYear
    texp = (expiry_date - settlement_date) / gDaysInYear
    times = np.linspace(0, tmat, 11)
    dates = settlement_date.add_years(times)
    dfs = np.exp(-0.05 * times)
    curve = DiscountCurve(settlement_date, dates, dfs)

    price = bond.clean_price_from_discount_curve(settlement_date, curve)
    assert round(price, 4) == 99.5420

    sigma = 0.20
    a = 0.05
    num_time_steps = 26

    model = BKTree(sigma, a, num_time_steps)
    model.build_tree(tmat, times, dfs)
    exercise_type = FinExerciseTypes.AMERICAN
    v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows,
                          exercise_type)

    # Test convergence
    num_time_steps = 200
    exercise_type = FinExerciseTypes.AMERICAN

    treeVector = []
    model = BKTree(sigma, a, num_time_steps)
    model.build_tree(tmat, times, dfs)
    v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows,
                          exercise_type)
    treeVector.append(v)

    assert round(v['call'], 4) == 0.6998
    assert round(v['put'], 4) == 7.9605
示例#7
0
def test_BDTExampleThree():
    # Valuation of a swaption as in Leif Andersen's paper - see Table 1 on
    # SSRN-id155208.pdf

    testCases.banner("===================== ANDERSEN PAPER ==============")

    # This is a sanity check
    testBlackModelCheck()

    settlement_date = Date(1, 1, 2020)
    times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
    dates = settlement_date.add_years(times)
    rate = 0.06
    dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times)
    curve = DiscountCurve(settlement_date, dates, dfs)

    coupon = 0.06
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    strike_price = 100.0
    face = 100.0
    # Andersen paper
    num_time_steps = 200

    testCases.header("ExerciseType", "Sigma", "NumSteps", "Texp", "Tmat",
                     "V_Fixed", "V_pay", "V_rec")

    for exercise_type in [
            FinExerciseTypes.EUROPEAN, FinExerciseTypes.BERMUDAN
    ]:

        for years_to_maturity in [4.0, 5.0, 10.0, 20.0]:

            maturity_date = settlement_date.add_years(years_to_maturity)
            issue_date = Date(maturity_date._d, maturity_date._m, 2000)

            if years_to_maturity == 4.0 or years_to_maturity == 5.0:
                sigma = 0.2012
            elif years_to_maturity == 10.0:
                sigma = 0.1522
            elif years_to_maturity == 20.0:
                sigma = 0.1035

            for expiryYears in range(
                    int(years_to_maturity / 2) - 1, int(years_to_maturity)):

                expiry_date = settlement_date.add_years(expiryYears)

                tmat = (maturity_date - settlement_date) / gDaysInYear
                texp = (expiry_date - settlement_date) / gDaysInYear

                bond = Bond(issue_date, maturity_date, coupon, freq_type,
                            accrual_type)

                coupon_times = []
                coupon_flows = []
                cpn = bond._coupon / bond._frequency
                for flow_date in bond._flow_dates:
                    if flow_date > expiry_date:
                        flow_time = (flow_date - settlement_date) / gDaysInYear
                        coupon_times.append(flow_time)
                        coupon_flows.append(cpn)

                coupon_times = np.array(coupon_times)
                coupon_flows = np.array(coupon_flows)

                price = bond.clean_price_from_discount_curve(
                    settlement_date, curve)

                model = BDTTree(sigma, num_time_steps)
                model.build_tree(tmat, times, dfs)

                v = model.bermudan_swaption(texp, tmat, strike_price, face,
                                            coupon_times, coupon_flows,
                                            exercise_type)

                testCases.print("%s" % exercise_type, "%9.5f" % sigma,
                                "%9.5f" % num_time_steps,
                                "%9.5f" % expiryYears,
                                "%9.5f" % years_to_maturity, "%9.5f" % price,
                                "%9.2f" % (v['pay'] * 100.0),
                                "%9.2f" % (v['rec'] * 100.0))
示例#8
0
def test_FinDiscountCurve():

    # Create a curve from times and discount factors
    start_date = Date(1, 1, 2018)
    years = np.linspace(0, 10, 6)
    rate = 0.05 + 0.005*years - 0.0003*years*years
    dfs = np.exp(-rate * years)
    dates = start_date.add_years(years)

    curve = DiscountCurve(start_date, dates, dfs, InterpTypes.FLAT_FWD_RATES)

    testCases.header("T", "DF", "ZERORATE", "CC_FWD", "MM_FWD", "SURVPROB")

    plotYears = np.linspace(0, 12, 12*12+1)[1:]
    plotDates = start_date.add_years(plotYears)

    # Examine dependency of curve on compounding rate
    zero_rates_A = curve.zero_rate(plotDates, FrequencyTypes.ANNUAL)
    zero_rates_S = curve.zero_rate(plotDates, FrequencyTypes.SEMI_ANNUAL)
    zero_rates_Q = curve.zero_rate(plotDates, FrequencyTypes.QUARTERLY)
    zero_rates_M = curve.zero_rate(plotDates, FrequencyTypes.MONTHLY)
    zero_rates_C = curve.zero_rate(plotDates, FrequencyTypes.CONTINUOUS)

    if PLOT_GRAPHS:
        plt.figure(figsize=(6, 4))
        plt.plot(plotYears, scale(zero_rates_A, 100), label='A')
        plt.plot(plotYears, scale(zero_rates_S, 100), label='S')
        plt.plot(plotYears, scale(zero_rates_Q, 100), label='Q')
        plt.plot(plotYears, scale(zero_rates_M, 100), label='M')
        plt.plot(plotYears, scale(zero_rates_C, 100), label='C')
        plt.ylim((5, 8))

        plt.title('Discount Curves')
        plt.xlabel('Time (years)')
        plt.ylabel('Zero Rate (%)')
        plt.legend(loc='lower right', frameon=False)

    # Examine dependency of fwd curve on the interpolation scheme

    for interp in InterpTypes:

        curve = DiscountCurve(start_date, dates, dfs, interp)
        fwd_rates = curve.fwd(plotDates)
        zero_rates = curve.zero_rate(plotDates, FrequencyTypes.ANNUAL)
        parRates = curve.swap_rate(
            start_date, plotDates, FrequencyTypes.ANNUAL)

        if PLOT_GRAPHS:
            plt.figure(figsize=(6, 4))
            plt.plot(plotYears, scale(fwd_rates, 100), label='FWD RATES')
            plt.plot(plotYears, scale(zero_rates, 100), label='ZERO RATES')
            plt.plot(plotYears, scale(parRates, 100), label='PAR RATES')
            plt.ylim((3.0, 8.5))

            plt.title('Forward Curves using ' + str(interp))
            plt.xlabel('Time (years)')
            plt.ylabel('Fwd Rate (%)')
            plt.legend(loc='lower right', frameon=False)
示例#9
0
from financepy.utils.date import Date
import numpy as np

settlement_date = Date(1, 12, 2019)
issue_date = Date(1, 12, 2018)
maturity_date = settlement_date.add_tenor("10Y")
coupon = 0.05
freq_type = FrequencyTypes.SEMI_ANNUAL
accrual_type = DayCountTypes.ACT_ACT_ICMA
bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

tmat = (maturity_date - settlement_date) / gDaysInYear
times = np.linspace(0, tmat, 20)
dates = settlement_date.add_years(times)
dfs = np.exp(-0.05 * times)
discount_curve = DiscountCurve(settlement_date, dates, dfs)

expiry_date = settlement_date.add_tenor("18m")
face = 100.0

num_time_steps = 100


def test_european_call_bk():
    option_type = OptionTypes.EUROPEAN_CALL
    strike_price = 100

    bond_option = BondOption(bond, expiry_date, strike_price, face,
                             option_type)

    sigma = 0.20
示例#10
0
def test_dp_example():

    #  http://www.derivativepricing.com/blogpage.asp?id=8

    start_date = Date(14, 11, 2011)
    end_date = Date(14, 11, 2016)
    fixedFreqType = FrequencyTypes.SEMI_ANNUAL
    swapCalendarType = CalendarTypes.TARGET
    bus_day_adjust_type = BusDayAdjustTypes.MODIFIED_FOLLOWING
    date_gen_rule_type = DateGenRuleTypes.BACKWARD
    fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA
    fixed_leg_type = SwapTypes.PAY
    fixed_coupon = 0.0124
    notional = ONE_MILLION

    swap = IborSwap(start_date,
                    end_date,
                    fixed_leg_type,
                    fixed_coupon=fixed_coupon,
                    fixed_freq_type=fixedFreqType,
                    fixed_day_count_type=fixed_day_count_type,
                    float_freq_type=FrequencyTypes.SEMI_ANNUAL,
                    float_day_count_type=DayCountTypes.ACT_360,
                    notional=notional,
                    calendar_type=swapCalendarType,
                    bus_day_adjust_type=bus_day_adjust_type,
                    date_gen_rule_type=date_gen_rule_type)

    #    swap.printFixedLegFlows()

    dts = [
        Date(14, 11, 2011),
        Date(14, 5, 2012),
        Date(14, 11, 2012),
        Date(14, 5, 2013),
        Date(14, 11, 2013),
        Date(14, 5, 2014),
        Date(14, 11, 2014),
        Date(14, 5, 2015),
        Date(16, 11, 2015),
        Date(16, 5, 2016),
        Date(14, 11, 2016)
    ]

    dfs = [
        0.9999843, 0.9966889, 0.9942107, 0.9911884, 0.9880738, 0.9836490,
        0.9786276, 0.9710461, 0.9621778, 0.9514315, 0.9394919
    ]

    valuation_date = start_date

    curve = DiscountCurve(valuation_date, dts, np.array(dfs),
                          InterpTypes.FLAT_FWD_RATES)

    v = swap.value(valuation_date, curve, curve)

    #    swap.print_fixed_leg_pv()
    #    swap.print_float_leg_pv()

    # This is essentially zero
    testCases.header("LABEL", "VALUE")
    testCases.print("Swap Value on a Notional of $1M:", v)
示例#11
0
def test_FinDiscountCurves():

    # Create a curve from times and discount factors
    valuation_date = Date(1, 1, 2018)
    years = [1.0, 2.0, 3.0, 4.0, 5.0]
    dates = valuation_date.add_years(years)
    years2 = []

    for dt in dates:
        y = (dt - valuation_date) / gDaysInYear
        years2.append(y)

    rates = np.array([0.05, 0.06, 0.065, 0.07, 0.075])
    discount_factors = np.exp(-np.array(rates) * np.array(years2))
    curvesList = []

    finDiscountCurve = DiscountCurve(valuation_date, dates, discount_factors,
                                     InterpTypes.FLAT_FWD_RATES)
    curvesList.append(finDiscountCurve)

    finDiscountCurveFlat = DiscountCurveFlat(valuation_date, 0.05)
    curvesList.append(finDiscountCurveFlat)

    finDiscountCurveNS = DiscountCurveNS(valuation_date, 0.0305, -0.01,
                                         0.08, 10.0)
    curvesList.append(finDiscountCurveNS)

    finDiscountCurveNSS = DiscountCurveNSS(valuation_date, 0.035, -0.02,
                                           0.09, 0.1, 1.0, 2.0)
    curvesList.append(finDiscountCurveNSS)

    finDiscountCurvePoly = DiscountCurvePoly(valuation_date, [0.05, 0.002,
                                                              -0.00005])
    curvesList.append(finDiscountCurvePoly)

    finDiscountCurvePWF = DiscountCurvePWF(valuation_date, dates, rates)
    curvesList.append(finDiscountCurvePWF)

    finDiscountCurvePWL = DiscountCurvePWL(valuation_date, dates, rates)
    curvesList.append(finDiscountCurvePWL)

    finDiscountCurveZeros = DiscountCurveZeros(valuation_date, dates, rates)
    curvesList.append(finDiscountCurveZeros)

    curveNames = []
    for curve in curvesList:
        curveNames.append(type(curve).__name__)

    testCases.banner("SINGLE CALLS NO VECTORS")
    testCases.header("CURVE", "DATE", "ZERO", "DF", "CCFWD", "MMFWD", "SWAP")

    years = np.linspace(1, 10, 10)
    fwdMaturityDates = valuation_date.add_years(years)

    testCases.banner("######################################################")
    testCases.banner("SINGLE CALLS")
    testCases.banner("######################################################")

    for name, curve in zip(curveNames, curvesList):
        for fwdMaturityDate in fwdMaturityDates:
            tenor = "3M"
            zero_rate = curve.zero_rate(fwdMaturityDate)
            fwd = curve.fwd(fwdMaturityDate)
            fwd_rate = curve.fwd_rate(fwdMaturityDate, tenor)
            swap_rate = curve.swap_rate(valuation_date, fwdMaturityDate)
            df = curve.df(fwdMaturityDate)

            testCases.print("%-20s" % name,
                            "%-12s" % fwdMaturityDate,
                            "%7.6f" % (zero_rate),
                            "%8.7f" % (df),
                            "%7.6f" % (fwd),
                            "%7.6f" % (fwd_rate),
                            "%7.6f" % (swap_rate))

    # Examine vectorisation
    testCases.banner("######################################################")
    testCases.banner("VECTORISATIONS")
    testCases.banner("######################################################")

    for name, curve in zip(curveNames, curvesList):
        tenor = "3M"
        zero_rate = curve.zero_rate(fwdMaturityDates)
        fwd = curve.fwd(fwdMaturityDates)
        fwd_rate = curve.fwd_rate(fwdMaturityDates, tenor)
        swap_rate = curve.swap_rate(valuation_date, fwdMaturityDates)
        df = curve.df(fwdMaturityDates)

        for i in range(0, len(fwdMaturityDates)):
            testCases.print("%-20s" % name,
                            "%-12s" % fwdMaturityDate,
                            "%7.6f" % (zero_rate[i]),
                            "%8.7f" % (df[i]),
                            "%7.6f" % (fwd[i]),
                            "%7.6f" % (fwd_rate[i]),
                            "%7.6f" % (swap_rate[i]))

    if PLOT_GRAPHS:

        years = np.linspace(0, 10, 121)
        years2 = years + 1.0
        fwdDates = valuation_date.add_years(years)
        fwdDates2 = valuation_date.add_years(years2)

        plt.figure()
        for name, curve in zip(curveNames, curvesList):
            zero_rates = curve.zero_rate(fwdDates)
            plt.plot(years, zero_rates, label=name)
        plt.legend()
        plt.title("Zero Rates")

        plt.figure()
        for name, curve in zip(curveNames, curvesList):
            fwd_rates = curve.fwd(fwdDates)
            plt.plot(years, fwd_rates, label=name)
        plt.legend()
        plt.title("CC Fwd Rates")

        plt.figure()
        for name, curve in zip(curveNames, curvesList):
            fwd_rates = curve.fwd_rate(fwdDates, fwdDates2)
            plt.plot(years, fwd_rates, label=name)
        plt.legend()
        plt.title("CC Fwd Rates")

        plt.figure()
        for name, curve in zip(curveNames, curvesList):
            dfs = curve.df(fwdDates)
            plt.plot(years, dfs, label=name)
        plt.legend()
        plt.title("Discount Factors")
def test_FinInterpolatedForwards():
    interp_type = InterpTypes.FLAT_FWD_RATES
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855,
         0.840, 0.825, 0.811, 0.792, 0.773, 0.755, 0.737, 0.720, 0.703, 0.687,
         0.670, 0.654, 0.638, 0.622, 0.607, 0.592, 0.577, 0.563, 0.549, 0.536,
         0.523, 0.510, 0.497, 0.485, 0.473, 0.461, 0.450, 0.439, 0.428, 0.417,
         0.407, 0.397, 0.387, 0.378, 0.368, 0.359, 0.350, 0.342, 0.333]

    interp_type = InterpTypes.LINEAR_FWD_RATES
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855,
         0.840, 0.825, 0.811, 0.796, 0.781, 0.764, 0.747, 0.729, 0.710, 0.691,
         0.671, 0.655, 0.639, 0.624, 0.609, 0.595, 0.580, 0.566, 0.552, 0.539,
         0.526, 0.513, 0.500, 0.488, 0.475, 0.463, 0.451, 0.440, 0.429, 0.418,
         0.407, 0.397, 0.387, 0.378, 0.368, 0.359, 0.350, 0.342, 0.333]

    interp_type = InterpTypes.LINEAR_ZERO_RATES
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855,
         0.840, 0.825, 0.811, 0.794, 0.776, 0.759, 0.741, 0.724, 0.706, 0.688,
         0.671, 0.656, 0.641, 0.626, 0.612, 0.598, 0.584, 0.570, 0.556, 0.542,
         0.529, 0.516, 0.503, 0.490, 0.478, 0.465, 0.453, 0.441, 0.430, 0.418,
         0.407, 0.398, 0.389, 0.380, 0.372, 0.364, 0.356, 0.348, 0.340]

    interp_type = InterpTypes.FINCUBIC_ZERO_RATES
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.983, 0.966, 0.950, 0.934, 0.918, 0.903, 0.888, 0.873, 0.858,
         0.843, 0.827, 0.811, 0.795, 0.778, 0.760, 0.742, 0.725, 0.707, 0.688,
         0.671, 0.653, 0.636, 0.620, 0.603, 0.588, 0.573, 0.558, 0.544, 0.530,
         0.517, 0.504, 0.491, 0.480, 0.468, 0.457, 0.446, 0.436, 0.426, 0.416,
         0.407, 0.398, 0.389, 0.381, 0.372, 0.365, 0.357, 0.349, 0.342]

    interp_type = InterpTypes.NATCUBIC_LOG_DISCOUNT
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.985, 0.969, 0.954, 0.939, 0.924, 0.908, 0.893, 0.877, 0.861,
         0.845, 0.828, 0.811, 0.794, 0.776, 0.758, 0.740, 0.723, 0.705, 0.688,
         0.671, 0.654, 0.638, 0.622, 0.607, 0.592, 0.577, 0.563, 0.549, 0.536,
         0.523, 0.510, 0.497, 0.485, 0.473, 0.461, 0.450, 0.439, 0.428, 0.417,
         0.407, 0.397, 0.387, 0.378, 0.368, 0.359, 0.350, 0.342, 0.333]

    interp_type = InterpTypes.NATCUBIC_ZERO_RATES
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.983, 0.966, 0.950, 0.934, 0.918, 0.903, 0.888, 0.873, 0.858,
         0.843, 0.827, 0.811, 0.795, 0.778, 0.760, 0.742, 0.724, 0.707, 0.688,
         0.671, 0.653, 0.636, 0.620, 0.604, 0.589, 0.574, 0.559, 0.545, 0.531,
         0.518, 0.505, 0.493, 0.481, 0.470, 0.458, 0.447, 0.437, 0.427, 0.417,
         0.407, 0.397, 0.388, 0.379, 0.370, 0.361, 0.352, 0.343, 0.334]

    interp_type = InterpTypes.PCHIP_ZERO_RATES
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855,
         0.840, 0.825, 0.811, 0.796, 0.780, 0.762, 0.743, 0.725, 0.706, 0.687,
         0.670, 0.655, 0.639, 0.623, 0.608, 0.593, 0.578, 0.564, 0.549, 0.535,
         0.522, 0.508, 0.495, 0.483, 0.471, 0.459, 0.447, 0.437, 0.426, 0.416,
         0.407, 0.398, 0.390, 0.382, 0.374, 0.368, 0.362, 0.356, 0.351]

    interp_type = InterpTypes.PCHIP_LOG_DISCOUNT
    discount_curve = DiscountCurve(
        curve_date, tDates, df_values, interp_type)
    dfInterpValues = discount_curve.df(tInterpDates)
    assert [round(x, 3) for x in dfInterpValues] == \
        [1.0, 0.986, 0.972, 0.957, 0.941, 0.925, 0.910, 0.893, 0.877, 0.861,
         0.844, 0.827, 0.811, 0.794, 0.777, 0.758, 0.740, 0.722, 0.705, 0.687,
         0.670, 0.654, 0.639, 0.623, 0.608, 0.594, 0.579, 0.565, 0.551, 0.538,
         0.525, 0.512, 0.499, 0.487, 0.475, 0.463, 0.451, 0.440, 0.429, 0.418,
         0.407, 0.397, 0.387, 0.376, 0.367, 0.357, 0.348, 0.339, 0.330]
def test_BDTExampleThree():
    # Valuation of a swaption as in Leif Andersen's paper - see Table 1 on
    # SSRN-id155208.pdf

    settlement_date = Date(1, 1, 2020)
    times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
    dates = settlement_date.add_years(times)
    rate = 0.06
    dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times)
    curve = DiscountCurve(settlement_date, dates, dfs)

    coupon = 0.06
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    strike_price = 100.0
    face = 100.0
    # Andersen paper
    num_time_steps = 200

    exercise_type = FinExerciseTypes.EUROPEAN
    years_to_maturity = 4.0
    expiryYears = 2.0

    maturity_date = settlement_date.add_years(years_to_maturity)
    issue_date = Date(maturity_date._d, maturity_date._m, 2000)

    sigma = 0.2012

    expiry_date = settlement_date.add_years(expiryYears)

    tmat = (maturity_date - settlement_date) / gDaysInYear
    texp = (expiry_date - settlement_date) / gDaysInYear

    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    coupon_times = []
    coupon_flows = []
    cpn = bond._coupon / bond._frequency
    for flow_date in bond._coupon_dates:
        if flow_date > expiry_date:
            flow_time = (flow_date - settlement_date) / gDaysInYear
            coupon_times.append(flow_time)
            coupon_flows.append(cpn)

    coupon_times = np.array(coupon_times)
    coupon_flows = np.array(coupon_flows)

    price = bond.clean_price_from_discount_curve(settlement_date, curve)

    model = BDTTree(sigma, num_time_steps)
    model.build_tree(tmat, times, dfs)

    v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times,
                                coupon_flows, exercise_type)

    assert round(price, 5) == 100.01832
    assert round(v['pay'] * 100, 2) == 0.00
    assert round(v['rec'] * 100, 2) == 8883.21

    exercise_type = FinExerciseTypes.BERMUDAN
    years_to_maturity = 10.0
    expiryYears = 5.0

    maturity_date = settlement_date.add_years(years_to_maturity)
    issue_date = Date(maturity_date._d, maturity_date._m, 2000)

    sigma = 0.1522

    expiry_date = settlement_date.add_years(expiryYears)

    tmat = (maturity_date - settlement_date) / gDaysInYear
    texp = (expiry_date - settlement_date) / gDaysInYear

    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    coupon_times = []
    coupon_flows = []
    cpn = bond._coupon / bond._frequency
    for flow_date in bond._coupon_dates:
        if flow_date > expiry_date:
            flow_time = (flow_date - settlement_date) / gDaysInYear
            coupon_times.append(flow_time)
            coupon_flows.append(cpn)

    coupon_times = np.array(coupon_times)
    coupon_flows = np.array(coupon_flows)

    price = bond.clean_price_from_discount_curve(settlement_date, curve)

    model = BDTTree(sigma, num_time_steps)
    model.build_tree(tmat, times, dfs)

    v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times,
                                coupon_flows, exercise_type)

    assert round(price, 5) == 100.08625
    assert round(v['pay'] * 100, 2) == 263.28
    assert round(v['rec'] * 100, 2) == 7437.00
示例#14
0
def test_BondOption():

    settlement_date = Date(1, 12, 2019)
    issue_date = Date(1, 12, 2018)
    maturity_date = settlement_date.add_tenor("10Y")
    coupon = 0.05
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    times = np.linspace(0, 10.0, 21)
    dfs = np.exp(-0.05 * times)
    dates = settlement_date.add_years(times)
    discount_curve = DiscountCurve(settlement_date, dates, dfs)

    expiry_date = settlement_date.add_tenor("18m")
    strike_price = 105.0
    face = 100.0

    ###########################################################################

    strikes = [80, 90, 100, 110, 120]

    option_type = OptionTypes.EUROPEAN_CALL

    testCases.header("LABEL", "VALUE")

    price = bond.clean_price_from_discount_curve(settlement_date,
                                                 discount_curve)
    testCases.print("Fixed Income Price:", price)

    num_time_steps = 50

    testCases.banner("HW EUROPEAN CALL")
    testCases.header("STRIKE", "VALUE")

    for strike_price in strikes:

        sigma = 0.01
        a = 0.1

        bond_option = BondOption(bond, expiry_date, strike_price, face,
                                 option_type)

        model = HWTree(sigma, a, num_time_steps)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print(strike_price, v)

    ###########################################################################

    option_type = OptionTypes.AMERICAN_CALL

    price = bond.clean_price_from_discount_curve(settlement_date,
                                                 discount_curve)
    testCases.header("LABEL", "VALUE")
    testCases.print("Fixed Income Price:", price)

    testCases.banner("HW AMERICAN CALL")
    testCases.header("STRIKE", "VALUE")

    for strike_price in strikes:

        sigma = 0.01
        a = 0.1

        bond_option = BondOption(bond, expiry_date, strike_price, face,
                                 option_type)

        model = HWTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print(strike_price, v)

    ###########################################################################

    option_type = OptionTypes.EUROPEAN_PUT
    testCases.banner("HW EUROPEAN PUT")
    testCases.header("STRIKE", "VALUE")

    price = bond.clean_price_from_discount_curve(settlement_date,
                                                 discount_curve)

    for strike_price in strikes:

        sigma = 0.01
        a = 0.1

        bond_option = BondOption(bond, expiry_date, strike_price, face,
                                 option_type)

        model = HWTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print(strike_price, v)

    ###########################################################################

    option_type = OptionTypes.AMERICAN_PUT
    testCases.banner("HW AMERICAN PUT")
    testCases.header("STRIKE", "VALUE")

    price = bond.clean_price_from_discount_curve(settlement_date,
                                                 discount_curve)

    for strike_price in strikes:

        sigma = 0.02
        a = 0.1

        bond_option = BondOption(bond, expiry_date, strike_price, face,
                                 option_type)

        model = HWTree(sigma, a)
        v = bond_option.value(settlement_date, discount_curve, model)
        testCases.print(strike_price, v)