Example #1
0
def test_5():
    accrual_type = DayCountTypes.THIRTY_E_PLUS_360
    maturityDt = Date(7, 9, 2014)
    coupon = 0.0500000000
    clean_price = 109.35500000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.1667
    assert round(ytm * 100, 4) == 0.2297
Example #2
0
def test_6():
    accrual_type = DayCountTypes.ACT_ACT_ISDA
    maturityDt = Date(22, 1, 2015)
    coupon = 0.0275000000
    clean_price = 105.62500000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.4433
    assert round(ytm * 100, 4) == 0.3334
Example #3
0
def test_3():
    accrual_type = DayCountTypes.THIRTY_E_360
    maturityDt = Date(27, 9, 2013)
    coupon = 0.080000
    clean_price = 107.92000000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 3.8222
    assert round(ytm * 100, 4) == 0.2380
Example #4
0
def test_4():
    accrual_type = DayCountTypes.THIRTY_E_360_ISDA
    maturityDt = Date(7, 3, 2014)
    coupon = 0.022500
    clean_price = 102.9750

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.0750
    assert round(ytm * 100, 4) == 0.2172
Example #5
0
def test_11():
    accrual_type = DayCountTypes.SIMPLE
    maturityDt = Date(25, 8, 2017)
    coupon = 0.0875000000
    clean_price = 138.57000000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.5993
    assert round(ytm * 100, 4) == 0.7652
Example #6
0
def test_2():
    accrual_type = DayCountTypes.THIRTY_360_BOND
    maturityDt = Date(7, 3, 2013)
    coupon = 0.045
    clean_price = 101.99500000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.1500
    assert round(ytm * 100, 4) == 0.2203
Example #7
0
def test_9():
    accrual_type = DayCountTypes.ACT_360
    maturityDt = Date(22, 1, 2016)
    coupon = 0.0200000000
    clean_price = 104.98000000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.3278
    assert round(ytm * 100, 4) == 0.4930
Example #8
0
def test_10():
    accrual_type = DayCountTypes.ACT_365L
    maturityDt = Date(7, 9, 2016)
    coupon = 0.0400000000
    clean_price = 113.49500000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.1315
    assert round(ytm * 100, 4) == 0.5559
Example #9
0
def test_8():
    accrual_type = DayCountTypes.ACT_365F
    maturityDt = Date(7, 12, 2015)
    coupon = 0.0800000000
    clean_price = 124.47000000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 2.2795
    assert round(ytm * 100, 4) == 0.3405
Example #10
0
def test_7():
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    maturityDt = Date(7, 9, 2015)
    coupon = 0.0475000000
    clean_price = 112.98000000

    issueDt = Date(maturityDt._d, maturityDt._m, 2000)
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)

    ytm = bond.yield_to_maturity(settlement, clean_price)
    assert round(bond._accrued_interest, 4) == 0.1575
    assert round(ytm * 100, 4) == 0.3485
Example #11
0
def test_BondOptionAmericanConvergenceONE():

    # Build discount curve
    settlement_date = Date(1, 12, 2019)
    discount_curve = DiscountCurveFlat(settlement_date, 0.05)

    # Bond details
    maturity_date = Date(1, 9, 2025)
    issue_date = Date(1, 9, 2016)
    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)

    # Option Details
    expiry_date = Date(1, 12, 2020)
    strike_price = 100.0
    face = 100.0

    testCases.header("TIME", "N", "PUT_AMER", "PUT_EUR",
                     "CALL_AME", "CALL_EUR")

    timeSteps = range(30, 100, 10)

    for num_time_steps in timeSteps:

        sigma = 0.20
        a = 0.1

        start = time.time()

        option_type = OptionTypes.AMERICAN_PUT
        bond_option1 = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model1 = BKTree(sigma, a, num_time_steps)
        v1put = bond_option1.value(settlement_date, discount_curve, model1)

        option_type = OptionTypes.EUROPEAN_PUT
        bond_option2 = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model2 = BKTree(sigma, a, num_time_steps)
        v2put = bond_option2.value(settlement_date, discount_curve, model2)

        option_type = OptionTypes.AMERICAN_CALL
        bond_option1 = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model1 = BKTree(sigma, a, num_time_steps)
        v1call = bond_option1.value(settlement_date, discount_curve, model1)

        option_type = OptionTypes.EUROPEAN_CALL
        bond_option2 = BondOption(
            bond, expiry_date, strike_price, face, option_type)
        model2 = BKTree(sigma, a, num_time_steps)
        v2call = bond_option2.value(settlement_date, discount_curve, model2)

        end = time.time()

        period = end - start

        testCases.print(period, num_time_steps, v1put, v2put, v1call, v2call)
Example #12
0
def test_bond_future_2():
    bond = Bond(issue_date, Date(15, 8, 2027), 0.0225, freq, basis)
    assert bond._maturity_date == Date(15, 8, 2027)

    settlement_date = Date(10, 10, 2017)
    price = 99 + 1 / 32

    yld = bond.yield_to_maturity(settlement_date, price)

    assert round(yld, 4) == 0.0236

    first_delivery_date = Date(1, 12, 2017)
    last_delivery_date = Date(28, 12, 2017)

    contract_size = 100000
    contractCoupon = 0.06
    bondFutureContract = BondFuture("TYZ7",
                                    first_delivery_date,
                                    last_delivery_date,
                                    contract_size,
                                    contractCoupon)

    cf = bondFutureContract.conversion_factor(bond)

    assert round(cf, 4) == 74.2122

    futures_price = 125.265625

    pip = bondFutureContract.principal_invoice_price(bond, futures_price)

    assert round(pip, 4) == 9296237.6200

    tia = bondFutureContract.total_invoice_amount(
            settlement_date, bond, futures_price)

    assert round(tia, 4) == 9296580.0100
Example #13
0
def test_bond_future_1():
    bond = Bond(issue_date, Date(15, 8, 2011), 0.0500, freq, basis)

    assert bond._maturity_date == Date(15, 8, 2011)
    assert bond._coupon * 100 == 5.0

    first_delivery_date = Date(1, 3, 2002)
    last_delivery_date = Date(28, 3, 2002)
    contract_size = 100000
    contractCoupon = 0.06
    bondFutureContract = BondFuture("TYH2",
                                    first_delivery_date,
                                    last_delivery_date,
                                    contract_size,
                                    contractCoupon)

    cf = bondFutureContract.conversion_factor(bond)

    assert round(cf, 4) == 92.9688
Example #14
0
def test_BondZeroCurve():

    import pandas as pd
    path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt')
    bondDataFrame = pd.read_csv(path, sep='\t')
    bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask'])

    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    settlement = Date(19, 9, 2012)

    bonds = []
    clean_prices = []

    for _, bondRow in bondDataFrame.iterrows():
        dateString = bondRow['maturity']
        matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y')
        maturityDt = fromDatetime(matDatetime)
        issueDt = Date(maturityDt._d, maturityDt._m, 2000)
        coupon = bondRow['coupon'] / 100.0
        clean_price = bondRow['mid']
        bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)
        bonds.append(bond)
        clean_prices.append(clean_price)

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

    bondCurve = BondZeroCurve(settlement, bonds, clean_prices)

    testCases.header("DATE", "ZERO RATE")

    for _, bond in bondDataFrame.iterrows():

        dateString = bond['maturity']
        matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y')
        maturityDt = fromDatetime(matDatetime)
        zeroRate = bondCurve.zeroRate(maturityDt)
        testCases.print(maturityDt, zeroRate)

    if plotGraphs:
        bondCurve.plot("BOND CURVE")
Example #15
0
def test_BondExDividend():
    issue_date = Date(7, 9, 2000)
    maturity_date = Date(7, 9, 2020)
    coupon = 0.05
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    face = 100.0
    exDivDays = 7
    testCases.header("LABEL", "VALUE")

    calendar_type = CalendarTypes.UNITED_KINGDOM
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type,
                face)
    settlement_date = Date(7, 9, 2003)
    accrued = bond.calc_accrued_interest(settlement_date, exDivDays,
                                         calendar_type)
    testCases.print("SettlementDate:", settlement_date)
    testCases.print("Accrued:", accrued)

    ###########################################################################
    testCases.banner("=======================================================")
    testCases.header("SETTLEMENT", "ACCRUED")

    issue_date = Date(7, 9, 2000)
    maturity_date = Date(7, 9, 2020)
    coupon = 0.05
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    face = 100.0
    exDivDays = 7

    calendar_type = CalendarTypes.UNITED_KINGDOM
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type,
                face)

    settlement_date = Date(25, 8, 2010)

    for _ in range(0, 13):
        settlement_date = settlement_date.add_days(1)
        accrued = bond.calc_accrued_interest(settlement_date, exDivDays,
                                             calendar_type)
        testCases.print(settlement_date, accrued)
Example #16
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)
Example #17
0
def test_Bond():
    import pandas as pd
    path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt')
    bondDataFrame = pd.read_csv(path, sep='\t')
    bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask'])

    freq_type = FrequencyTypes.SEMI_ANNUAL
    settlement_date = Date(19, 9, 2012)
    face = ONE_MILLION

    for accrual_type in DayCountTypes:

        testCases.header("MATURITY", "COUPON", "CLEAN_PRICE", "ACCD_DAYS",
                         "ACCRUED", "YTM")

        for _, bond in bondDataFrame.iterrows():
            dateString = bond['maturity']
            matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y')
            maturityDt = fromDatetime(matDatetime)
            issueDt = Date(maturityDt._d, maturityDt._m, 2000)

            coupon = bond['coupon'] / 100.0
            clean_price = bond['mid']
            bond = Bond(issueDt, maturityDt,
                        coupon, freq_type, accrual_type, 100)

            ytm = bond.yield_to_maturity(settlement_date, clean_price)
            accrued_interest= bond._accruedInterest
            accd_days = bond._accrued_days

            testCases.print("%18s" % maturityDt, "%8.4f" % coupon,
                            "%10.4f" % clean_price, "%6.0f" % accd_days,
                            "%10.4f" % accrued_interest, "%8.4f" % ytm)

    ###########################################################################
    #  EXAMPLE FROM http://bondtutor.com/btchp4/topic6/topic6.htm

    accrualConvention = DayCountTypes.ACT_ACT_ICMA
    y = 0.062267
    settlement_date = Date(19, 4, 1994)
    issue_date = Date(15, 7, 1990)
    maturity_date = Date(15, 7, 1997)
    coupon = 0.085
    face = ONE_MILLION
    freq_type = FrequencyTypes.SEMI_ANNUAL
    bond = Bond(issue_date, maturity_date,
                coupon, freq_type, accrualConvention, face)

    testCases.header("FIELD", "VALUE")
    full_price = bond.full_price_from_ytm(settlement_date, y)
    testCases.print("Full Price = ", full_price)
    clean_price = bond.clean_price_from_ytm(settlement_date, y)
    testCases.print("Clean Price = ", clean_price)
    accrued_interest= bond._accruedInterest
    testCases.print("Accrued = ", accrued_interest)
    ytm = bond.yield_to_maturity(settlement_date, clean_price)
    testCases.print("Yield to Maturity = ", ytm)

    bump = 1e-4
    priceBumpedUp = bond.full_price_from_ytm(settlement_date, y + bump)
    testCases.print("Price Bumped Up:", priceBumpedUp)

    priceBumpedDn = bond.full_price_from_ytm(settlement_date, y - bump)
    testCases.print("Price Bumped Dn:", priceBumpedDn)

    durationByBump = -(priceBumpedUp - full_price) / bump
    testCases.print("Duration by Bump = ", durationByBump)

    duration = bond.dollar_duration(settlement_date, y)
    testCases.print("Dollar Duration = ", duration)
    testCases.print("Duration Difference:", duration - durationByBump)

    modified_duration = bond.modified_duration(settlement_date, y)
    testCases.print("Modified Duration = ", modified_duration)

    macauley_duration = bond.macauley_duration(settlement_date, y)
    testCases.print("Macauley Duration = ", macauley_duration)

    conv = bond.convexity_from_ytm(settlement_date, y)
    testCases.print("Convexity = ", conv)

    # ASSET SWAP SPREAD

    # When the libor curve is the flat bond curve then the ASW is zero by
    # definition
    flatCurve = DiscountCurveFlat(settlement_date,
                                  ytm,
                                  FrequencyTypes.SEMI_ANNUAL)

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

    clean_price = bond.clean_price_from_ytm(settlement_date, ytm)
    asw = bond.asset_swap_spread(settlement_date, clean_price, flatCurve)
    testCases.print("Discounted on Bond Curve ASW:", asw * 10000)

    # When the libor curve is the Libor curve then the ASW is positive
    libor_curve = buildIborCurve(settlement_date)
    asw = bond.asset_swap_spread(settlement_date, clean_price, libor_curve)
    oas = bond.option_adjusted_spread(settlement_date, clean_price, libor_curve)
    testCases.print("Discounted on LIBOR Curve ASW:", asw * 10000)
    testCases.print("Discounted on LIBOR Curve OAS:", oas * 10000)

    p = 90.0
    asw = bond.asset_swap_spread(settlement_date, p, libor_curve)
    oas = bond.option_adjusted_spread(settlement_date, p, libor_curve)
    testCases.print("Deep discount bond at 90 ASW:", asw * 10000)
    testCases.print("Deep discount bond at 90 OAS:", oas * 10000)

    p = 100.0
    asw = bond.asset_swap_spread(settlement_date, p, libor_curve)
    oas = bond.option_adjusted_spread(settlement_date, p, libor_curve)
    testCases.print("Par bond at 100 ASW:", asw * 10000)
    testCases.print("Par bond at 100 OAS:", oas * 10000)

    p = 120.0
    asw = bond.asset_swap_spread(settlement_date, p, libor_curve)
    oas = bond.option_adjusted_spread(settlement_date, p, libor_curve)
    testCases.print("Above par bond at 120 ASW:", asw * 10000)
    testCases.print("Above par bond at 120 OAS:", oas * 10000)

    ##########################################################################
    # https://data.bloomberglp.com/bat/sites/3/2017/07/SF-2017_Paul-Fjeldsted.pdf
    # Page 10 TREASURY NOTE SCREENSHOT
    ##########################################################################

    testCases.banner("BLOOMBERG US TREASURY EXAMPLE")
    settlement_date = Date(21, 7, 2017)
    issue_date = Date(15, 5, 2010)
    maturity_date = Date(15, 5, 2027)
    coupon = 0.02375
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    face = 100.0

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

    testCases.header("FIELD", "VALUE")
    clean_price = 99.7808417

    yld = bond.current_yield(clean_price)
    testCases.print("Current Yield = ", yld)

    ytm = bond.yield_to_maturity(settlement_date, clean_price,
                                 FinYTMCalcType.UK_DMO)
    testCases.print("UK DMO Yield To Maturity = ", ytm)

    ytm = bond.yield_to_maturity(settlement_date, clean_price,
                                 FinYTMCalcType.US_STREET)
    testCases.print("US STREET Yield To Maturity = ", ytm)

    ytm = bond.yield_to_maturity(settlement_date, clean_price,
                                 FinYTMCalcType.US_TREASURY)
    testCases.print("US TREASURY Yield To Maturity = ", ytm)

    full_price = bond.full_price_from_ytm(settlement_date, ytm)
    testCases.print("Full Price = ", full_price)

    clean_price = bond.clean_price_from_ytm(settlement_date, ytm)
    testCases.print("Clean Price = ", clean_price)

    accrued_interest= bond._accruedInterest
    testCases.print("Accrued = ", accrued_interest)

    accddays = bond._accrued_days
    testCases.print("Accrued Days = ", accddays)

    duration = bond.dollar_duration(settlement_date, ytm)
    testCases.print("Dollar Duration = ", duration)

    modified_duration = bond.modified_duration(settlement_date, ytm)
    testCases.print("Modified Duration = ", modified_duration)

    macauley_duration = bond.macauley_duration(settlement_date, ytm)
    testCases.print("Macauley Duration = ", macauley_duration)

    conv = bond.convexity_from_ytm(settlement_date, ytm)
    testCases.print("Convexity = ", conv)

    ##########################################################################
    # Page 11 APPLE NOTE SCREENSHOT
    ##########################################################################

    testCases.banner("BLOOMBERG APPLE CORP BOND EXAMPLE")
    settlement_date = Date(21, 7, 2017)
    issue_date = Date(13, 5, 2012)
    maturity_date = Date(13, 5, 2022)
    coupon = 0.027
    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.THIRTY_E_360_ISDA
    face = 100.0

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

    testCases.header("FIELD", "VALUE")
    clean_price = 101.581564

    yld = bond.current_yield(clean_price)
    testCases.print("Current Yield", yld)

    ytm = bond.yield_to_maturity(settlement_date, clean_price,
                                 FinYTMCalcType.UK_DMO)
    testCases.print("UK DMO Yield To Maturity", ytm)

    ytm = bond.yield_to_maturity(settlement_date, clean_price,
                                 FinYTMCalcType.US_STREET)
    testCases.print("US STREET Yield To Maturity", ytm)

    ytm = bond.yield_to_maturity(settlement_date, clean_price,
                                 FinYTMCalcType.US_TREASURY)
    testCases.print("US TREASURY Yield To Maturity", ytm)

    full_price = bond.full_price_from_ytm(settlement_date, ytm)
    testCases.print("Full Price", full_price)

    clean_price = bond.clean_price_from_ytm(settlement_date, ytm)
    testCases.print("Clean Price", clean_price)

    accddays = bond._accrued_days
    testCases.print("Accrued Days", accddays)

    accrued_interest= bond._accruedInterest
    testCases.print("Accrued", accrued_interest)

    duration = bond.dollar_duration(settlement_date, ytm)
    testCases.print("Dollar Duration", duration)

    modified_duration = bond.modified_duration(settlement_date, ytm)
    testCases.print("Modified Duration", modified_duration)

    macauley_duration = bond.macauley_duration(settlement_date, ytm)
    testCases.print("Macauley Duration", macauley_duration)

    conv = bond.convexity_from_ytm(settlement_date, ytm)
    testCases.print("Convexity", conv)
Example #18
0
def test_HullWhiteCallableBond():
    # Valuation of a European option on a coupon bearing bond

    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)

    coupon_times = []
    coupon_flows = []
    cpn = bond._coupon / bond._frequency

    for flow_date in bond._coupon_dates[1:]:

        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)

    ###########################################################################
    # Set up the call and put times and prices
    ###########################################################################

    call_dates = []
    call_prices = []
    callPx = 120.0
    call_dates.append(settlement_date.add_tenor("2Y"))
    call_prices.append(callPx)
    call_dates.append(settlement_date.add_tenor("3Y"))
    call_prices.append(callPx)
    call_dates.append(settlement_date.add_tenor("4Y"))
    call_prices.append(callPx)
    call_dates.append(settlement_date.add_tenor("5Y"))
    call_prices.append(callPx)
    call_dates.append(settlement_date.add_tenor("6Y"))
    call_prices.append(callPx)
    call_dates.append(settlement_date.add_tenor("7Y"))
    call_prices.append(callPx)
    call_dates.append(settlement_date.add_tenor("8Y"))
    call_prices.append(callPx)

    call_times = []
    for dt in call_dates:
        t = (dt - settlement_date) / gDaysInYear
        call_times.append(t)

    put_dates = []
    put_prices = []
    putPx = 98.0
    put_dates.append(settlement_date.add_tenor("2Y"))
    put_prices.append(putPx)
    put_dates.append(settlement_date.add_tenor("3Y"))
    put_prices.append(putPx)
    put_dates.append(settlement_date.add_tenor("4Y"))
    put_prices.append(putPx)
    put_dates.append(settlement_date.add_tenor("5Y"))
    put_prices.append(putPx)
    put_dates.append(settlement_date.add_tenor("6Y"))
    put_prices.append(putPx)
    put_dates.append(settlement_date.add_tenor("7Y"))
    put_prices.append(putPx)
    put_dates.append(settlement_date.add_tenor("8Y"))
    put_prices.append(putPx)

    put_times = []
    for dt in put_dates:
        t = (dt - settlement_date) / gDaysInYear
        put_times.append(t)

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

    tmat = (maturity_date - settlement_date) / gDaysInYear
    curve = DiscountCurveFlat(settlement_date, 0.05, FrequencyTypes.CONTINUOUS)

    dfs = []
    times = []

    for dt in bond._coupon_dates:
        if dt > settlement_date:
            t = (dt - settlement_date) / gDaysInYear
            df = curve.df(dt)
            times.append(t)
            dfs.append(df)

    dfs = np.array(dfs)
    times = np.array(times)

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

    v1 = bond.clean_price_from_discount_curve(settlement_date, curve)

    sigma = 0.02  # basis point volatility
    a = 0.01

    # Test convergence
    num_steps_list = [100, 200, 500, 1000]
    tmat = (maturity_date - settlement_date) / gDaysInYear

    testCases.header("NUMSTEPS", "TIME", "BOND_ONLY", "CALLABLE_BOND")

    for num_time_steps in num_steps_list:

        start = time.time()
        model = HWTree(sigma, a, num_time_steps)
        model.build_tree(tmat, times, dfs)

        v2 = model.callable_puttable_bond_tree(coupon_times, coupon_flows,
                                               call_times, call_prices,
                                               put_times, put_prices, 100.0)

        end = time.time()
        period = end - start
        testCases.print(num_time_steps, period, v1, v2)
Example #19
0
def test_HullWhiteBondOption():
    # Valuation of a European option on a coupon bearing bond

    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 ncd > settlement_date:

            if len(coupon_times) == 0:
                flow_time = (pcd - settlement_date) / gDaysInYear
                coupon_times.append(flow_time)
                coupon_flows.append(cpn)

            flow_time = (ncd - 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 = 100.0
    face = 100.0
    y = 0.05
    times = np.linspace(0, 10, 21)
    dfs = np.power(1 + y / 2, -times * 2)

    sigma = 0.0000001
    a = 0.1
    model = HWTree(sigma, a, None)

    #  Test convergence
    num_steps_list = range(50, 500, 50)
    texp = (expiry_date - settlement_date) / gDaysInYear

    vJam = model.european_bond_option_jamshidian(texp, strike_price, face,
                                                 coupon_times, coupon_flows,
                                                 times, dfs)

    testCases.banner(
        "Pricing bond option on tree that goes to bond maturity and one using european bond option tree that goes to expiry."
    )

    testCases.header("NUMSTEPS", "TIME", "EXPIRY_ONLY", "EXPIRY_TREE",
                     "JAMSHIDIAN")

    for num_time_steps in num_steps_list:

        start = time.time()
        model = HWTree(sigma, a, num_time_steps,
                       FinHWEuropeanCalcType.EXPIRY_ONLY)
        model.build_tree(texp, times, dfs)

        exercise_type = FinExerciseTypes.EUROPEAN

        v1 = model.bond_option(texp, strike_price, face, coupon_times,
                               coupon_flows, exercise_type)

        model = HWTree(sigma, a, num_time_steps,
                       FinHWEuropeanCalcType.EXPIRY_TREE)
        model.build_tree(texp, times, dfs)

        v2 = model.bond_option(texp, strike_price, face, coupon_times,
                               coupon_flows, exercise_type)

        end = time.time()
        period = end - start

        testCases.print(num_time_steps, period, v1, v2, vJam)

#    plt.plot(num_steps_list, treeVector)

    if 1 == 0:
        print("RT")
        print_tree(model._rt, 5)
        print("BOND")
        print_tree(model._bond_values, 5)
        print("OPTION")
        print_tree(model._option_values, 5)
Example #20
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))
Example #21
0
def test_BondYieldCurve():

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

    import pandas as pd
    path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt')
    bondDataFrame = pd.read_csv(path, sep='\t')
    bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask'])

    freq_type = FrequencyTypes.SEMI_ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    settlement = Date(19, 9, 2012)

    bonds = []
    ylds = []

    for _, bond in bondDataFrame.iterrows():

        dateString = bond['maturity']
        matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y')
        maturityDt = fromDatetime(matDatetime)
        issueDt = Date(maturityDt._d, maturityDt._m, 2000)
        coupon = bond['coupon'] / 100.0
        clean_price = bond['mid']
        bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type)
        yld = bond.yield_to_maturity(settlement, clean_price)
        bonds.append(bond)
        ylds.append(yld)

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

    curveFitMethod = CurveFitPolynomial()
    fittedCurve1 = BondYieldCurve(settlement, bonds, ylds, curveFitMethod)
    #    fittedCurve1.display("GBP Yield Curve")

    curveFitMethod = CurveFitPolynomial(5)
    fittedCurve2 = BondYieldCurve(settlement, bonds, ylds, curveFitMethod)
    #    fittedCurve2.display("GBP Yield Curve")

    curveFitMethod = CurveFitNelsonSiegel()
    fittedCurve3 = BondYieldCurve(settlement, bonds, ylds, curveFitMethod)
    #    fittedCurve3.display("GBP Yield Curve")

    curveFitMethod = CurveFitNelsonSiegelSvensson()
    fittedCurve4 = BondYieldCurve(settlement, bonds, ylds, curveFitMethod)
    #    fittedCurve4.display("GBP Yield Curve")

    curveFitMethod = CurveFitBSpline()
    fittedCurve5 = BondYieldCurve(settlement, bonds, ylds, curveFitMethod)
    #    fittedCurve5.display("GBP Yield Curve")

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

    testCases.header("PARAMETER", "VALUE")
    testCases.print("beta1", fittedCurve3._curveFit._beta1)
    testCases.print("beta2", fittedCurve3._curveFit._beta2)
    testCases.print("beta3", fittedCurve3._curveFit._beta3)
    testCases.print("tau", fittedCurve3._curveFit._tau)

    testCases.header("PARAMETER", "VALUE")
    testCases.print("beta1", fittedCurve4._curveFit._beta1)
    testCases.print("beta2", fittedCurve4._curveFit._beta2)
    testCases.print("beta3", fittedCurve4._curveFit._beta3)
    testCases.print("beta4", fittedCurve4._curveFit._beta4)
    testCases.print("tau1", fittedCurve4._curveFit._tau1)
    testCases.print("tau2", fittedCurve4._curveFit._tau2)

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

    maturity_date = Date(19, 9, 2030)
    interpolatedYield = fittedCurve5.interpolatedYield(maturity_date)
    testCases.print(maturity_date, interpolatedYield)
Example #22
0
def test_BondFuture():

    # Example taken from Martellini and Priaulet page 360
    freq = FrequencyTypes.SEMI_ANNUAL
    basis = DayCountTypes.ACT_ACT_ICMA
    issue_date = Date(15, 2, 2004)

    bond1 = Bond(issue_date, Date(15, 8, 2011), 0.0500, freq, basis)
    bond2 = Bond(issue_date, Date(15, 2, 2011), 0.0500, freq, basis)
    bond3 = Bond(issue_date, Date(15, 8, 2010), 0.0575, freq, basis)
    bond4 = Bond(issue_date, Date(15, 2, 2010), 0.0650, freq, basis)
    bond5 = Bond(issue_date, Date(15, 8, 2009), 0.0600, freq, basis)
    bond6 = Bond(issue_date, Date(15, 5, 2009), 0.0550, freq, basis)
    bond7 = Bond(issue_date, Date(15, 11, 2008), 0.0475, freq, basis)

    bonds = []
    bonds.append(bond1)
    bonds.append(bond2)
    bonds.append(bond3)
    bonds.append(bond4)
    bonds.append(bond5)
    bonds.append(bond6)
    bonds.append(bond7)

    first_delivery_date = Date(1, 3, 2002)
    last_delivery_date = Date(28, 3, 2002)
    contract_size = 100000
    contractCoupon = 0.06

    bondFutureContract = BondFuture("TYH2", first_delivery_date,
                                    last_delivery_date, contract_size,
                                    contractCoupon)

    settlement_date = Date(10, 12, 2001)

    # Get the Conversion Factors
    testCases.header("Bond Maturity", "Coupon", "Conversion Factor")
    for bond in bonds:
        cf = bondFutureContract.conversion_factor(bond)
        testCases.print(bond._maturity_date, bond._coupon * 100, cf)

    # Example from
    # https://www.cmegroup.com/education/files/understanding-treasury-futures.pdf

    testCases.banner("EXAMPLE FROM CME")
    testCases.banner("================")
    settlement_date = Date(10, 10, 2017)

    bonds = []
    prices = []
    bond = Bond(issue_date, Date(15, 8, 2027), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(99 + 1 / 32)
    bond = Bond(issue_date, Date(15, 5, 2027), 0.02375, freq, basis)
    bonds.append(bond)
    prices.append(100 + 5 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 2, 2027), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(99 + 5 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 11, 2026), 0.02, freq, basis)
    bonds.append(bond)
    prices.append(97 + 7 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 8, 2026), 0.015, freq, basis)
    bonds.append(bond)
    prices.append(93 + 14 / 32)
    bond = Bond(issue_date, Date(15, 5, 2026), 0.01625, freq, basis)
    bonds.append(bond)
    prices.append(94 + 21 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 2, 2026), 0.01625, freq, basis)
    bonds.append(bond)
    prices.append(94 + 29 / 32)
    bond = Bond(issue_date, Date(15, 11, 2025), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(99 + 25 / 32)
    bond = Bond(issue_date, Date(15, 8, 2025), 0.02, freq, basis)
    bonds.append(bond)
    prices.append(98 + 3 / 32)
    bond = Bond(issue_date, Date(15, 5, 2025), 0.02125, freq, basis)
    bonds.append(bond)
    prices.append(99 + 5 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 2, 2025), 0.02, freq, basis)
    bonds.append(bond)
    prices.append(98 + 14 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 11, 2024), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(100 + 9 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 8, 2024), 0.02375, freq, basis)
    bonds.append(bond)
    prices.append(101 + 7 / 32 + 1 / 64)
    bond = Bond(issue_date, Date(15, 8, 2024), 0.01875, freq, basis)
    bonds.append(bond)
    # There may be an error in the document says 98-01+
    prices.append(98 + 1 / 32)

    testCases.header("BOND MATURITY", "YIELD")
    for bond, clean_price in zip(bonds, prices):
        yld = bond.yield_to_maturity(settlement_date, clean_price)
        testCases.print(str(bond._maturity_date), yld)

    first_delivery_date = Date(1, 12, 2017)
    last_delivery_date = Date(28, 12, 2017)

    contract_size = 100000
    contractCoupon = 0.06

    bondFutureContract = BondFuture("TYZ7", first_delivery_date,
                                    last_delivery_date, contract_size,
                                    contractCoupon)

    testCases.header("BOND MATURITY", "CF")
    for bond in bonds:
        cf = bondFutureContract.conversion_factor(bond)
        testCases.print(str(bond._maturity_date), cf)

    # Get the Invoice Prices
    futures_price = 125.265625

    testCases.header("BOND MATURITY", "PRINCIPAL INVOICE PRICE")
    for bond in bonds:
        pip = bondFutureContract.principal_invoice_price(bond, futures_price)
        testCases.print(str(bond._maturity_date), pip)

    testCases.header("BOND MATURITY", "TOTAL INVOICE AMOUNT")
    for bond in bonds:
        tia = bondFutureContract.total_invoice_amount(settlement_date, bond,
                                                      futures_price)
        testCases.print(str(bond._maturity_date), tia)

    ctd = bondFutureContract.cheapest_to_deliver(bonds, prices, futures_price)

    testCases.header("CTD MATURITY", "CTD COUPON")
    testCases.print(str(ctd._maturity_date), ctd._coupon)
def test_BondEmbeddedOptionMATLAB():
    # https://fr.mathworks.com/help/fininst/optembndbybk.html
    # I FIND THAT THE PRICE CONVERGES TO 102.365 WHICH IS CLOSE TO 102.382
    # FOUND BY MATLAB ALTHOUGH THEY DO NOT EXAMINE THE ASYMPTOTIC PRICE
    # WHICH MIGHT BE A BETTER MATCH - ALSO THEY DO NOT USE A REALISTIC VOL

    valuation_date = Date(1, 1, 2007)
    settlement_date = valuation_date

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

    fixed_leg_type = SwapTypes.PAY
    dcType = DayCountTypes.THIRTY_E_360
    fixedFreq = FrequencyTypes.ANNUAL
    swap1 = IborSwap(settlement_date, "1Y", fixed_leg_type, 0.0350, fixedFreq, dcType)
    swap2 = IborSwap(settlement_date, "2Y", fixed_leg_type, 0.0400, fixedFreq, dcType)
    swap3 = IborSwap(settlement_date, "3Y", fixed_leg_type, 0.0450, fixedFreq, dcType)
    swaps = [swap1, swap2, swap3]
    discount_curve = IborSingleCurve(valuation_date, [], [], swaps)

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

    issue_date = Date(1, 1, 2005)
    maturity_date = Date(1, 1, 2010)
    coupon = 0.0525
    freq_type = FrequencyTypes.ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    call_dates = []
    call_prices = []
    put_dates = []
    put_prices = []

    putDate = Date(1, 1, 2008)
    for _ in range(0, 24):
        put_dates.append(putDate)
        put_prices.append(100)
        putDate = putDate.add_months(1)

    testCases.header("BOND PRICE", "PRICE")
    v = bond.clean_price_from_discount_curve(settlement_date, discount_curve)
    testCases.print("Bond Pure Price:", v)

    sigma = 0.01  # This volatility is very small for a BK process
    a = 0.1

    puttableBond = BondEmbeddedOption(issue_date, maturity_date, coupon,
                                      freq_type, accrual_type,
                                      call_dates, call_prices,
                                      put_dates, put_prices)

    testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure")

    timeSteps = range(100, 200, 10)  # 1000, 10)
    values = []
    for num_time_steps in timeSteps:
        model = BKTree(sigma, a, num_time_steps)
        start = time.time()
        v = puttableBond.value(settlement_date, discount_curve, model)
        end = time.time()
        period = end - start
        testCases.print(period, num_time_steps, v['bondwithoption'],
                        v['bondpure'])

        values.append(v['bondwithoption'])

    if plotGraphs:
        plt.figure()
        plt.plot(timeSteps, values)
def test_BondEmbeddedOptionQUANTLIB():

    # Based on example at the nice blog on Quantlib at
    # http://gouthamanbalaraman.com/blog/callable-bond-quantlib-python.html
    # I get a price of 68.97 for 1000 time steps which is higher than the
    # 68.38 found in blog article. But this is for 40 grid points.
    # Note also that a basis point vol of 0.120 is 12% which is VERY HIGH!

    valuation_date = Date(16, 8, 2016)
    settlement_date = valuation_date.add_weekdays(3)

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

    discount_curve = DiscountCurveFlat(valuation_date, 0.035,
                                       FrequencyTypes.SEMI_ANNUAL)

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

    issue_date = Date(15, 9, 2010)
    maturity_date = Date(15, 9, 2022)
    coupon = 0.025
    freq_type = FrequencyTypes.QUARTERLY
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    ###########################################################################
    # Set up the call and put times and prices
    ###########################################################################

    nextCallDate = Date(15, 9, 2016)
    call_dates = [nextCallDate]
    call_prices = [100.0]

    for _ in range(1, 24):
        nextCallDate = nextCallDate.add_months(3)
        call_dates.append(nextCallDate)
        call_prices.append(100.0)

    put_dates = []
    put_prices = []

    # the value used in blog of 12% bp vol is unrealistic
    sigma = 0.12/0.035  # basis point volatility
    a = 0.03

    puttableBond = BondEmbeddedOption(issue_date, maturity_date, coupon,
                                      freq_type, accrual_type,
                                      call_dates, call_prices,
                                      put_dates, put_prices)

    testCases.header("BOND PRICE", "PRICE")
    v = bond.clean_price_from_discount_curve(settlement_date, discount_curve)
    testCases.print("Bond Pure Price:", v)

    testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure")
    timeSteps = range(100, 200, 20)  # 1000, 10)
    values = []
    for num_time_steps in timeSteps:
        model = BKTree(sigma, a, num_time_steps)
        start = time.time()
        v = puttableBond.value(settlement_date, discount_curve, model)
        end = time.time()
        period = end - start
        testCases.print(period, num_time_steps, v['bondwithoption'],
                        v['bondpure'])
        values.append(v['bondwithoption'])

    if plotGraphs:
        plt.figure()
        plt.title("Puttable Bond Price Convergence")
        plt.plot(timeSteps, values)
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
Example #26
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)
Example #27
0
def test_BondOptionAmericanConvergenceTWO():

    # Build discount curve
    settlement_date = Date(1, 12, 2019)
    discount_curve = DiscountCurveFlat(settlement_date,
                                       0.05,
                                       FrequencyTypes.CONTINUOUS)

    # Bond details
    issue_date = Date(1, 9, 2014)
    maturity_date = Date(1, 9, 2025)
    coupon = 0.05
    freq_type = FrequencyTypes.ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)
    expiry_date = settlement_date.add_tenor("18m")
    face = 100.0

    spotValue = bond.full_price_from_discount_curve(
        settlement_date, discount_curve)
    testCases.header("LABEL", "VALUE")
    testCases.print("BOND PRICE", spotValue)

    testCases.header("TIME", "N", "EUR_CALL", "AMER_CALL",
                     "EUR_PUT", "AMER_PUT")

    sigma = 0.2
    a = 0.1
    bkModel = BKTree(sigma, a)
    K = 101.0

    vec_ec = []
    vec_ac = []
    vec_ep = []
    vec_ap = []

    if 1 == 1:
        K = 100.0
        bkModel = BKTree(sigma, a, 100)
        europeanCallBondOption = BondOption(bond, expiry_date, K, face,
                                            OptionTypes.EUROPEAN_CALL)

        v_ec = europeanCallBondOption.value(settlement_date, discount_curve,
                                            bkModel)
        testCases.header("LABEL", "VALUE")
        testCases.print("OPTION", v_ec)

    num_stepsVector = range(100, 100, 1)  # should be 100-400

    for num_steps in num_stepsVector:

        bkModel = BKTree(sigma, a, num_steps)

        start = time.time()

        europeanCallBondOption = BondOption(bond, expiry_date, K, face,
                                            OptionTypes.EUROPEAN_CALL)
        v_ec = europeanCallBondOption.value(settlement_date, discount_curve,
                                            bkModel)

        americanCallBondOption = BondOption(bond, expiry_date, K, face,
                                            OptionTypes.AMERICAN_CALL)
        v_ac = americanCallBondOption.value(settlement_date, discount_curve,
                                            bkModel)

        europeanPutBondOption = BondOption(bond, expiry_date, K, face,
                                           OptionTypes.EUROPEAN_PUT)
        v_ep = europeanPutBondOption.value(settlement_date, discount_curve,
                                           bkModel)

        americanPutBondOption = BondOption(bond, expiry_date, K, face,
                                           OptionTypes.AMERICAN_PUT)
        v_ap = americanPutBondOption.value(settlement_date, discount_curve,
                                           bkModel)

        end = time.time()
        period = end - start

        testCases.print(period, num_steps, v_ec, v_ac, v_ep, v_ap)

        vec_ec.append(v_ec)
        vec_ac.append(v_ac)
        vec_ep.append(v_ep)
        vec_ap.append(v_ap)

    if plotGraphs:

        plt.figure()
        plt.plot(num_stepsVector, vec_ec, label="European Call")
        plt.legend()

        plt.figure()
        plt.plot(num_stepsVector, vec_ac, label="American Call")
        plt.legend()

        plt.figure()
        plt.plot(num_stepsVector, vec_ep, label="European Put")
        plt.legend()

        plt.figure()
        plt.plot(num_stepsVector, vec_ap, label="American Put")
        plt.legend()
Example #28
0
def test_BondOptionEuropeanConvergence():

    # CONVERGENCE TESTS
    # COMPARE AMERICAN TREE VERSUS JAMSHIDIAN IN EUROPEAN LIMIT TO CHECK THAT
    # TREE HAS BEEN CORRECTLY CONSTRUCTED. FIND VERY GOOD AGREEMENT.

    # Build discount curve
    settlement_date = Date(1, 12, 2019)
    discount_curve = DiscountCurveFlat(settlement_date, 0.05,
                                       FrequencyTypes.CONTINUOUS)

    # Bond details
    issue_date = Date(1, 12, 2015)
    maturity_date = Date(1, 12, 2020)
    coupon = 0.05
    freq_type = FrequencyTypes.ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    # Option Details - put expiry in the middle of a coupon period
    expiry_date = Date(1, 3, 2020)
    strike_price = 100.0
    face = 100.0

    timeSteps = range(100, 400, 100)
    strike_price = 100.0

    testCases.header("TIME", "N", "PUT_JAM", "PUT_TREE", "CALL_JAM",
                     "CALL_TREE")

    for num_time_steps in timeSteps:

        sigma = 0.05
        a = 0.1

        start = time.time()
        option_type = OptionTypes.EUROPEAN_PUT

        bond_option1 = BondOption(bond, expiry_date, strike_price, face,
                                  option_type)
        model1 = HWTree(sigma, a, num_time_steps)
        v1put = bond_option1.value(settlement_date, discount_curve, model1)

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

        model2 = HWTree(sigma, a, num_time_steps,
                        FinHWEuropeanCalcType.EXPIRY_ONLY)
        v2put = bond_option2.value(settlement_date, discount_curve, model2)

        option_type = OptionTypes.EUROPEAN_CALL

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

        model1 = HWTree(sigma, a, num_time_steps)
        v1call = bond_option1.value(settlement_date, discount_curve, model1)

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

        model2 = HWTree(sigma, a, num_time_steps,
                        FinHWEuropeanCalcType.EXPIRY_TREE)
        v2call = bond_option2.value(settlement_date, discount_curve, model2)

        end = time.time()
        period = end - start
        testCases.print(period, num_time_steps, v1put, v2put, v1call, v2call)
Example #29
0
def test_BondOptionZEROVOLConvergence():

    # Build discount curve
    settlement_date = Date(1, 9, 2019)
    rate = 0.05
    discount_curve = DiscountCurveFlat(
        settlement_date, rate, FrequencyTypes.ANNUAL)

    # Bond details
    issue_date = Date(1, 9, 2014)
    maturity_date = Date(1, 9, 2025)
    coupon = 0.06
    freq_type = FrequencyTypes.ANNUAL
    accrual_type = DayCountTypes.ACT_ACT_ICMA
    bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type)

    # Option Details
    expiry_date = Date(1, 12, 2021)
    face = 100.0

    dfExpiry = discount_curve.df(expiry_date)
    fwdCleanValue = bond.clean_price_from_discount_curve(
        expiry_date, discount_curve)
    fwdFullValue = bond.full_price_from_discount_curve(
        expiry_date, discount_curve)
#    print("BOND FwdCleanBondPx", fwdCleanValue)
#    print("BOND FwdFullBondPx", fwdFullValue)
#    print("BOND Accrued:", bond._accrued_interest)

    spotCleanValue = bond.clean_price_from_discount_curve(
        settlement_date, discount_curve)

    testCases.header("STRIKE", "STEPS",
                     "CALL_INT", "CALL_INT_PV", "CALL_EUR", "CALL_AMER",
                     "PUT_INT", "PUT_INT_PV", "PUT_EUR", "PUT_AMER")

    num_time_steps = range(100, 1000, 100)
    strike_prices = [90, 100, 110, 120]

    for strike_price in strike_prices:

        callIntrinsic = max(spotCleanValue - strike_price, 0)
        putIntrinsic = max(strike_price - spotCleanValue, 0)
        callIntrinsicPV = max(fwdCleanValue - strike_price, 0) * dfExpiry
        putIntrinsicPV = max(strike_price - fwdCleanValue, 0) * dfExpiry

        for num_steps in num_time_steps:

            sigma = 0.0000001
            a = 0.1
            model = BKTree(sigma, a, num_steps)

            option_type = OptionTypes.EUROPEAN_CALL
            bond_option1 = BondOption(
                bond, expiry_date, strike_price, face, option_type)
            v1 = bond_option1.value(settlement_date, discount_curve, model)

            option_type = OptionTypes.AMERICAN_CALL
            bond_option2 = BondOption(
                bond, expiry_date, strike_price, face, option_type)
            v2 = bond_option2.value(settlement_date, discount_curve, model)

            option_type = OptionTypes.EUROPEAN_PUT
            bond_option3 = BondOption(
                bond, expiry_date, strike_price, face, option_type)
            v3 = bond_option3.value(settlement_date, discount_curve, model)

            option_type = OptionTypes.AMERICAN_PUT
            bond_option4 = BondOption(
                bond, expiry_date, strike_price, face, option_type)
            v4 = bond_option4.value(settlement_date, discount_curve, model)

            testCases.print(strike_price, num_steps,
                            callIntrinsic, callIntrinsicPV, v1, v2,
                            putIntrinsic, putIntrinsicPV, v3, v4)
Example #30
0
def test_BondOptionDerivaGem():

    # See https://github.com/domokane/FinancePy/issues/98

    settlement_date = Date(1, 12, 2019)

    rate = 0.05
    dcType = DayCountTypes.THIRTY_360_BOND
    fixedFreq = FrequencyTypes.SEMI_ANNUAL
    discount_curve = DiscountCurveFlat(settlement_date, rate, fixedFreq,
                                       dcType)

    issue_date = Date(1, 12, 2018)
    expiry_date = settlement_date.add_tenor("18m")
    maturity_date = settlement_date.add_tenor("10Y")

    coupon = 0.05
    freqType = FrequencyTypes.SEMI_ANNUAL
    accrualType = DayCountTypes.THIRTY_360_BOND
    bond = Bond(issue_date, maturity_date, coupon, freqType, accrualType)
    strike_price = 100.0
    face = 100.0

    europeanCallBondOption = BondOption(bond, expiry_date, strike_price, face,
                                        OptionTypes.EUROPEAN_CALL)
    cp = bond.clean_price_from_discount_curve(expiry_date, discount_curve)
    fp = bond.full_price_from_discount_curve(expiry_date, discount_curve)
    #    print("Fixed Income Clean Price: %9.3f"% cp)
    #    print("Fixed Income Full  Price: %9.3f"% fp)

    num_steps = 500
    sigma = 0.0125
    a = 0.1
    modelHW = HWTree(sigma, a, num_steps)

    ec = europeanCallBondOption.value(settlement_date, discount_curve, modelHW)

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

    couponTimes = []
    couponFlows = []
    cpn = bond._coupon / bond._frequency

    numFlows = len(bond._flow_dates)
    for i in range(0, numFlows):

        pcd = bond._flow_dates[i - 1]
        ncd = bond._flow_dates[i]

        if ncd > settlement_date:

            if len(couponTimes) == 0:
                flowTime = (pcd - settlement_date) / gDaysInYear
                couponTimes.append(flowTime)
                couponFlows.append(cpn)

            flowTime = (ncd - settlement_date) / gDaysInYear
            couponTimes.append(flowTime)
            couponFlows.append(cpn)

    couponTimes = np.array(couponTimes)
    couponFlows = np.array(couponFlows)

    y = 0.05
    times = np.linspace(0, 10, 21)
    dfs = np.power(1 + y / 2, -times * 2)

    sigma = 0.0125
    a = 0.1
    model = HWTree(sigma, a, None)

    #  Test convergence
    texp = (expiry_date - settlement_date) / gDaysInYear
    tmat = (maturity_date - settlement_date) / gDaysInYear

    # Jamshidian approach
    vjam = model.european_bond_option_jamshidian(texp, strike_price, face,
                                                 couponTimes, couponFlows,
                                                 times, dfs)
    # print("Jamshidian:", vjam)

    model._num_time_steps = 100
    model.build_tree(tmat, times, dfs)
    exerciseType = FinExerciseTypes.EUROPEAN

    vHW = model.bond_option(texp, strike_price, face, couponTimes, couponFlows,
                            exerciseType)