Beispiel #1
0
def test_FinBondOptionAmericanConvergenceTWO():

    # Build discount curve
    settlementDate = FinDate(1, 12, 2019)
    discountCurve = FinDiscountCurveFlat(settlementDate, 0.05,
                                         FinFrequencyTypes.CONTINUOUS)

    # Bond details
    issueDate = FinDate(1, 9, 2014)
    maturityDate = FinDate(1, 9, 2025)
    coupon = 0.05
    frequencyType = FinFrequencyTypes.ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)
    expiryDate = settlementDate.addTenor("18m")
    face = 100.0

    spotValue = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve)
    testCases.header("LABEL", "VALUE")
    testCases.print("BOND PRICE", spotValue)

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

    sigma = 0.2
    model = FinModelRatesBDT(sigma)
    K = 101.0

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

    if 1 == 1:
        K = 100.0
        bkModel = FinModelRatesBDT(sigma, 100)
        europeanCallBondOption = FinBondOption(bond, expiryDate, K, face,
                                               FinOptionTypes.EUROPEAN_CALL)

        v_ec = europeanCallBondOption.value(settlementDate, discountCurve,
                                            model)
        testCases.header("LABEL", "VALUE")
        testCases.print("OPTION", v_ec)

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

    for numSteps in numStepsVector:

        bkModel = FinModelRatesBDT(sigma, numSteps)

        start = time.time()

        europeanCallBondOption = FinBondOption(bond, expiryDate, K, face,
                                               FinOptionTypes.EUROPEAN_CALL)
        v_ec = europeanCallBondOption.value(settlementDate, discountCurve,
                                            bkModel)

        americanCallBondOption = FinBondOption(bond, expiryDate, K, face,
                                               FinOptionTypes.AMERICAN_CALL)
        v_ac = americanCallBondOption.value(settlementDate, discountCurve,
                                            bkModel)

        europeanPutBondOption = FinBondOption(bond, expiryDate, K, face,
                                              FinOptionTypes.EUROPEAN_PUT)
        v_ep = europeanPutBondOption.value(settlementDate, discountCurve,
                                           bkModel)

        americanPutBondOption = FinBondOption(bond, expiryDate, K, face,
                                              FinOptionTypes.AMERICAN_PUT)
        v_ap = americanPutBondOption.value(settlementDate, discountCurve,
                                           bkModel)

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

        testCases.print(period, numSteps, 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(numStepsVector, vec_ec, label="European Call")
        plt.legend()

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

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

        plt.figure()
        plt.plot(numStepsVector, vec_ap, label="American Put")
        plt.legend()
Beispiel #2
0
def test_FinBondOption():

    settlementDate = FinDate(1, 12, 2019)
    issueDate = FinDate(1, 12, 2018)
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

    tmat = (maturityDate - settlementDate) / gDaysInYear
    times = np.linspace(0, tmat, 20)
    dates = settlementDate.addYears(times)
    dfs = np.exp(-0.05 * times)
    discountCurve = FinDiscountCurve(settlementDate, dates, dfs)

    expiryDate = settlementDate.addTenor("18m")
    strikePrice = 105.0
    face = 100.0

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

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

    optionType = FinOptionTypes.EUROPEAN_CALL

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

    price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve)
    testCases.print("Fixed Income Price:", price)

    numTimeSteps = 100

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

    for strikePrice in strikes:

        sigma = 0.20

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("EUROPEAN CALL - BK", strikePrice, v)

    for strikePrice in strikes:

        sigma = 0.20

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("EUROPEAN CALL - BK", strikePrice, v)

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

    optionType = FinOptionTypes.AMERICAN_CALL

    price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve)
    testCases.header("LABEL", "VALUE")
    testCases.print("Fixed Income Price:", price)

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

    for strikePrice in strikes:

        sigma = 0.20

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("AMERICAN CALL - BK", strikePrice, v)

    for strikePrice in strikes:

        sigma = 0.20

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("AMERICAN CALL - BK", strikePrice, v)

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

    optionType = FinOptionTypes.EUROPEAN_PUT

    price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve)

    for strikePrice in strikes:

        sigma = 0.01

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("EUROPEAN PUT - BK", strikePrice, v)

    for strikePrice in strikes:

        sigma = 0.20

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("EUROPEAN PUT - BK", strikePrice, v)

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

    optionType = FinOptionTypes.AMERICAN_PUT

    price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve)

    for strikePrice in strikes:

        sigma = 0.02

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("AMERICAN PUT - BK", strikePrice, v)

    for strikePrice in strikes:

        sigma = 0.20

        bondOption = FinBondOption(bond, expiryDate, strikePrice, face,
                                   optionType)
        model = FinModelRatesBDT(sigma, numTimeSteps)
        v = bondOption.value(settlementDate, discountCurve, model)
        testCases.print("AMERICAN PUT - BK", strikePrice, v)
def test_FinBondEmbeddedOptionQUANTLIB():

    # 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!

    valuationDate = FinDate(16, 8, 2016)
    settlementDate = valuationDate.addWeekDays(3)

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

    discountCurve = FinDiscountCurveFlat(valuationDate, 0.035,
                                         FinFrequencyTypes.SEMI_ANNUAL)

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

    issueDate = FinDate(15, 9, 2010)
    maturityDate = FinDate(15, 9, 2022)
    coupon = 0.025
    frequencyType = FinFrequencyTypes.QUARTERLY
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

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

    nextCallDate = FinDate(15, 9, 2016)
    callDates = [nextCallDate]
    callPrices = [100.0]

    for i in range(1, 24):
        nextCallDate = nextCallDate.addMonths(3)
        callDates.append(nextCallDate)
        callPrices.append(100.0)

    putDates = []
    putPrices = []

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

    puttableBond = FinBondEmbeddedOption(issueDate, maturityDate, coupon,
                                         frequencyType, accrualType, callDates,
                                         callPrices, putDates, putPrices)

    testCases.header("BOND PRICE", "PRICE")
    v = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve)
    testCases.print("Bond Pure Price:", v)

    testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure")
    timeSteps = range(100, 1000, 100)
    values = []
    for numTimeSteps in timeSteps:
        model = FinModelRatesHW(sigma, a, numTimeSteps)
        start = time.time()
        v = puttableBond.value(settlementDate, discountCurve, model)
        end = time.time()
        period = end - start
        testCases.print(period, numTimeSteps, v['bondwithoption'],
                        v['bondpure'])
        values.append(v['bondwithoption'])

    if plotGraphs:
        plt.figure()
        plt.title("Puttable Bond Price Convergence")
        plt.plot(timeSteps, values)
def test_FinBondEmbeddedOptionMATLAB():

    # https://fr.mathworks.com/help/fininst/optembndbyhw.html
    # I FIND THAT THE PRICE CONVERGES TO 102.88 WHICH IS CLOSE TO 102.9127
    # FOUND BY MATLAB ALTHOUGH THEY DO NOT EXAMINE THE ASYMPTOTIC PRICE
    # WHICH MIGHT BE A BETTER MATCH

    settlementDate = FinDate(1, 1, 2007)

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

    dcType = FinDayCountTypes.THIRTY_E_360
    fixedFreq = FinFrequencyTypes.ANNUAL
    swapType = FinSwapTypes.PAYER
    swap1 = FinLiborSwap(settlementDate, "1Y", swapType, 0.0350, fixedFreq,
                         dcType)
    swap2 = FinLiborSwap(settlementDate, "2Y", swapType, 0.0400, fixedFreq,
                         dcType)
    swap3 = FinLiborSwap(settlementDate, "3Y", swapType, 0.0450, fixedFreq,
                         dcType)
    swaps = [swap1, swap2, swap3]
    discountCurve = FinLiborCurve(settlementDate, [], [], swaps)

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

    issueDate = FinDate(1, 1, 2004)
    maturityDate = FinDate(1, 1, 2010)

    coupon = 0.0525
    frequencyType = FinFrequencyTypes.ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

    callDates = []
    callPrices = []
    putDates = []
    putPrices = []

    putDate = FinDate(1, 1, 2008)
    for i in range(0, 24):
        putDates.append(putDate)
        putPrices.append(100)
        putDate = putDate.addMonths(1)

    testCases.header("BOND PRICE", "PRICE")
    v = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve)
    testCases.print("Bond Pure Price:", v)

    sigma = 0.01  # basis point volatility
    a = 0.1

    puttableBond = FinBondEmbeddedOption(issueDate, maturityDate, coupon,
                                         frequencyType, accrualType, callDates,
                                         callPrices, putDates, putPrices)

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

    timeSteps = range(50, 1000, 10)
    values = []
    for numTimeSteps in timeSteps:
        model = FinModelRatesHW(sigma, a, numTimeSteps)
        start = time.time()
        v = puttableBond.value(settlementDate, discountCurve, model)
        end = time.time()
        period = end - start
        testCases.print(period, numTimeSteps, v['bondwithoption'],
                        v['bondpure'])
        values.append(v['bondwithoption'])

    if plotGraphs:
        plt.figure()
        plt.plot(timeSteps, values)
Beispiel #5
0
def test_HullWhiteCallableBond():
    # Valuation of a European option on a coupon bearing bond

    settlementDate = FinDate(1, 12, 2019)
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(maturityDate, coupon, frequencyType, accrualType)

    bond.calculateFlowDates(settlementDate)
    couponTimes = []
    couponFlows = []
    cpn = bond._coupon / bond._frequency
    for flowDate in bond._flowDates[1:]:
        flowTime = (flowDate - settlementDate) / gDaysInYear
        couponTimes.append(flowTime)
        couponFlows.append(cpn)
    couponTimes = np.array(couponTimes)
    couponFlows = np.array(couponFlows)

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

    callDates = []
    callPrices = []
    callPx = 120.0
    callDates.append(settlementDate.addTenor("5Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("6Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("7Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("8Y"))
    callPrices.append(callPx)

    callTimes = []
    for dt in callDates:
        t = (dt - settlementDate) / gDaysInYear
        callTimes.append(t)

    putDates = []
    putPrices = []
    putPx = 98.0
    putDates.append(settlementDate.addTenor("5Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("6Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("7Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("8Y"))
    putPrices.append(putPx)

    putTimes = []
    for dt in putDates:
        t = (dt - settlementDate) / gDaysInYear
        putTimes.append(t)

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

    tmat = (maturityDate - settlementDate) / gDaysInYear
    times = np.linspace(0, tmat, 20)
    dfs = np.exp(-0.05 * times)
    curve = FinDiscountCurve(settlementDate, times, dfs)

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

    v1 = bond.fullPriceFromDiscountCurve(settlementDate, curve)

    sigma = 0.02  # basis point volatility
    a = 0.1

    # Test convergence
    numStepsList = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
    tmat = (maturityDate - settlementDate) / gDaysInYear

    print("NUMSTEPS", "BOND_ONLY", "CALLABLE_BOND", "TIME")

    for numTimeSteps in numStepsList:
        start = time.time()
        model = FinModelRatesHullWhite(a, sigma)
        model.buildTree(tmat, numTimeSteps, times, dfs)

        v2 = model.callablePuttableBond_Tree(couponTimes, couponFlows,
                                             callTimes, callPrices, putTimes,
                                             putPrices)

        end = time.time()
        period = end - start
        print(numTimeSteps, v1, v2, period)

    if 1 == 0:
        print("RT")
        printTree(model._rt, 5)
        print("BOND")
        printTree(model._bondValues, 5)
        print("OPTION")
        printTree(model._optionValues, 5)
Beispiel #6
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()

    settlementDate = FinDate(1, 1, 2020)
    times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
    dates = settlementDate.addYears(times)
    rate = 0.06
    dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times)
    curve = FinDiscountCurve(settlementDate, dates, dfs)

    coupon = 0.06
    freqType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    strikePrice = 100.0
    face = 100.0
    # Andersen paper
    numTimeSteps = 200

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

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

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

            maturityDate = settlementDate.addYears(maturityYears)
            issueDate = FinDate(maturityDate._d, maturityDate._m, 2000)

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

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

                expiryDate = settlementDate.addYears(expiryYears)

                tmat = (maturityDate - settlementDate) / gDaysInYear
                texp = (expiryDate - settlementDate) / gDaysInYear

                bond = FinBond(issueDate, maturityDate, coupon, freqType,
                               accrualType)

                couponTimes = []
                couponFlows = []
                cpn = bond._coupon / bond._frequency
                for flowDate in bond._flowDates:
                    if flowDate > expiryDate:
                        flowTime = (flowDate - settlementDate) / gDaysInYear
                        couponTimes.append(flowTime)
                        couponFlows.append(cpn)

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

                price = bond.cleanPriceFromDiscountCurve(settlementDate, curve)

                model = FinModelRatesBDT(sigma, numTimeSteps)
                model.buildTree(tmat, times, dfs)

                v = model.bermudanSwaption(texp, tmat, strikePrice, face,
                                           couponTimes, couponFlows,
                                           exerciseType)

                testCases.print("%s" % exerciseType, "%9.5f" % sigma,
                                "%9.5f" % numTimeSteps, "%9.5f" % expiryYears,
                                "%9.5f" % maturityYears, "%9.5f" % price,
                                "%9.2f" % (v['pay'] * 100.0),
                                "%9.2f" % (v['rec'] * 100.0))
Beispiel #7
0
def test_FinBondOptionEuropeanConvergence():

    # 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
    settlementDate = FinDate(1, 12, 2019)
    discountCurve = FinDiscountCurveFlat(settlementDate, 0.05,
                                         FinFrequencyTypes.CONTINUOUS)

    # Bond details
    issueDate = FinDate(1, 12, 2015)
    maturityDate = FinDate(1, 12, 2020)
    coupon = 0.05
    frequencyType = FinFrequencyTypes.ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

    # Option Details - put expiry in the middle of a coupon period
    expiryDate = FinDate(1, 3, 2020)
    strikePrice = 100.0
    face = 100.0

    timeSteps = range(10, 400, 10)
    strikePrice = 100.0

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

    for numTimeSteps in timeSteps:

        sigma = 0.05
        a = 0.1

        start = time.time()
        optionType = FinOptionTypes.EUROPEAN_PUT

        bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)
        model1 = FinModelRatesHW(sigma, a, numTimeSteps)
        v1put = bondOption1.value(settlementDate, discountCurve, model1)

        bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model2 = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_ONLY)
        v2put = bondOption2.value(settlementDate, discountCurve, model2)

        optionType = FinOptionTypes.EUROPEAN_CALL

        bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model1 = FinModelRatesHW(sigma, a, numTimeSteps)
        v1call = bondOption1.value(settlementDate, discountCurve, model1)

        bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model2 = FinModelRatesHW(sigma, a, numTimeSteps,  FinHWEuropeanCalcType.EXPIRY_TREE)
        v2call = bondOption2.value(settlementDate, discountCurve, model2)

        end = time.time()
        period = end - start
        testCases.print(period, numTimeSteps, v1put, v2put, v1call, v2call)
def test_FinBondYieldCurve():

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

    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'])

    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    settlement = FinDate(2012, 9, 19)

    bonds = []
    ylds = []

    for index, bond in bondDataFrame.iterrows():

        dateString = bond['maturity']
        matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y')
        maturityDt = fromDatetime(matDatetime)
        issueDt = FinDate(maturityDt._d, maturityDt._m, 2000)
        coupon = bond['coupon']/100.0
        cleanPrice = bond['mid']
        bond = FinBond(issueDt, maturityDt, coupon, frequencyType, accrualType)
        yld = bond.yieldToMaturity(settlement, cleanPrice)
        bonds.append(bond)
        ylds.append(yld)

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

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

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

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

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

    curveFitMethod = FinCurveFitBSpline()
    fittedCurve5 = FinBondYieldCurve(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)

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

    maturityDate = FinDate(2030, 9, 19)
    interpolatedYield = fittedCurve5.interpolatedYield(maturityDate)
    testCases.print(maturityDate, interpolatedYield)
def test_HullWhiteBondOption():
    # Valuation of a European option on a coupon bearing bond

    settlementDate = FinDate(1, 12, 2019)
    issueDate = FinDate(1, 12, 2018)
    expiryDate = settlementDate.addTenor("18m")
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

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

    numFlows = len(bond._flowDates)
    for i in range(1, numFlows):

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

        if ncd > settlementDate:

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

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

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

    strikePrice = 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 = FinModelRatesHW(sigma, a, None)

    #  Test convergence
    numStepsList = range(20, 500, 10)
    texp = (expiryDate - settlementDate) / gDaysInYear

    vJam = model.europeanBondOptionJamshidian(texp, strikePrice, face,
                                              couponTimes, couponFlows, 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", "EXPIRY_ONLY", "EXPIRY_TREE", "JAMSHIDIAN",
                     "TIME")

    for numTimeSteps in numStepsList:

        start = time.time()
        model = FinModelRatesHW(sigma, a, numTimeSteps,
                                FinHWEuropeanCalcType.EXPIRY_ONLY)
        model.buildTree(texp, times, dfs)

        exerciseType = FinOptionExerciseTypes.EUROPEAN

        v1 = model.bondOption(texp, strikePrice, face, couponTimes,
                              couponFlows, exerciseType)

        model = FinModelRatesHW(sigma, a, numTimeSteps,
                                FinHWEuropeanCalcType.EXPIRY_TREE)
        model.buildTree(texp, times, dfs)

        v2 = model.bondOption(texp, strikePrice, face, couponTimes,
                              couponFlows, exerciseType)

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

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

#    plt.plot(numStepsList, treeVector)

    if 1 == 0:
        print("RT")
        printTree(model._rt, 5)
        print("BOND")
        printTree(model._bondValues, 5)
        print("OPTION")
        printTree(model._optionValues, 5)
def test_HullWhiteCallableBond():
    # Valuation of a European option on a coupon bearing bond

    settlementDate = FinDate(1, 12, 2019)
    issueDate = FinDate(1, 12, 2018)
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

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

    for flowDate in bond._flowDates[1:]:

        if flowDate > settlementDate:
            flowTime = (flowDate - settlementDate) / gDaysInYear
            couponTimes.append(flowTime)
            couponFlows.append(cpn)

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

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

    callDates = []
    callPrices = []
    callPx = 120.0
    callDates.append(settlementDate.addTenor("2Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("3Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("4Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("5Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("6Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("7Y"))
    callPrices.append(callPx)
    callDates.append(settlementDate.addTenor("8Y"))
    callPrices.append(callPx)

    callTimes = []
    for dt in callDates:
        t = (dt - settlementDate) / gDaysInYear
        callTimes.append(t)

    putDates = []
    putPrices = []
    putPx = 98.0
    putDates.append(settlementDate.addTenor("2Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("3Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("4Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("5Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("6Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("7Y"))
    putPrices.append(putPx)
    putDates.append(settlementDate.addTenor("8Y"))
    putPrices.append(putPx)

    putTimes = []
    for dt in putDates:
        t = (dt - settlementDate) / gDaysInYear
        putTimes.append(t)

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

    tmat = (maturityDate - settlementDate) / gDaysInYear
    curve = FinDiscountCurveFlat(settlementDate, 0.05,
                                 FinFrequencyTypes.CONTINUOUS)

    dfs = []
    times = []

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

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

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

    v1 = bond.cleanPriceFromDiscountCurve(settlementDate, curve)

    sigma = 0.02  # basis point volatility
    a = 0.01

    # Test convergence
    numStepsList = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
    tmat = (maturityDate - settlementDate) / gDaysInYear

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

    for numTimeSteps in numStepsList:

        start = time.time()
        model = FinModelRatesHW(sigma, a, numTimeSteps)
        model.buildTree(tmat, times, dfs)

        v2 = model.callablePuttableBond_Tree(couponTimes, couponFlows,
                                             callTimes, callPrices, putTimes,
                                             putPrices, 100.0)

        end = time.time()
        period = end - start
        testCases.print(numTimeSteps, v1, v2, period)
Beispiel #11
0
from financepy.market.curves.FinFlatCurve import FinFlatCurve
from financepy.market.curves.FinFlatCurve import FinCompoundingMethods

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

print("BLOOMBERG US TREASURY EXAMPLE")
settlementDate = FinDate(2017, 7, 21)
maturityDate = FinDate(2027, 5, 15)
coupon = 0.02375
freqType = FinFrequencyTypes.SEMI_ANNUAL
accrualType = FinDayCountTypes.ACT_ACT_ICMA

# By setting the face to 100 we expect a price of par to be 100.0
face = 100.0

bond = FinBond(maturityDate, coupon, freqType, accrualType, face)

cleanPrice = 99.780842  # if face is 1 then this must be 0.99780842

yld = bond.currentYield(cleanPrice)
print("Current Yield = ", yld)

ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                           FinYieldConventions.UK_DMO)
print("UK DMO Yield To Maturity = ", ytm)

ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                           FinYieldConventions.US_STREET)
print("US STREET Yield To Maturity = ", ytm)

ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
Beispiel #12
0
accrualType = FinDayCountTypes.ACT_ACT_ICMA
settlement = FinDate(2012, 9, 19)

bonds = []
ylds = []

# LOAD BONDS AND CREATE A VECTOR OF FINBOND AND THEIR CORRESPONDING YIELDS

for index, bond in bondDataFrame.iterrows():

    dateString = bond['maturity']
    matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y')
    maturityDt = FinDate.fromDatetime(matDatetime)
    coupon = bond['coupon'] / 100.0
    cleanPrice = bond['mid']
    bond = FinBond(maturityDt, coupon, frequencyType, accrualType)
    yld = bond.yieldToMaturity(settlement, cleanPrice)
    bonds.append(bond)
    ylds.append(yld)

# FIT THE BOND YIELDS TO A CUBIC POLYNOMIAL
curveFitMethod = FinCurveFitMethodPolynomial()
fittedCurve1 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod)
fittedCurve1.display("GBP Yield Curve")

# FIT THE BOND YIELDS TO A QUINTIC POLYNOMIAL
curveFitMethod = FinCurveFitMethodPolynomial(5)
fittedCurve2 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod)
fittedCurve2.display("GBP Yield Curve")

# FIT THE BONDS TO A NELSON-SIEGEL CURVE
Beispiel #13
0
def test_HullWhiteBondOption():
    # Valuation of a European option on a coupon bearing bond

    settlementDate = FinDate(1, 12, 2019)
    expiryDate = settlementDate.addTenor("18m")
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(maturityDate, coupon, frequencyType, accrualType)

    bond.calculateFlowDates(settlementDate)
    couponTimes = []
    couponFlows = []
    cpn = bond._coupon / bond._frequency
    for flowDate in bond._flowDates[1:]:
        flowTime = (flowDate - settlementDate) / gDaysInYear
        couponTimes.append(flowTime)
        couponFlows.append(cpn)
    couponTimes = np.array(couponTimes)
    couponFlows = np.array(couponFlows)

    strikePrice = 105.0
    face = 100.0

    tmat = (maturityDate - settlementDate) / gDaysInYear
    times = np.linspace(0, tmat, 20)
    dfs = np.exp(-0.05 * times)
    curve = FinDiscountCurve(settlementDate, times, dfs)

    price = bond.fullPriceFromDiscountCurve(settlementDate, curve)
    print("Spot Bond Price:", price)

    price = bond.fullPriceFromDiscountCurve(expiryDate, curve)
    print("Fwd Bond Price:", price)

    sigma = 0.01
    a = 0.1

    # Test convergence
    numStepsList = [100, 200, 300, 400, 500]
    texp = (expiryDate - settlementDate) / gDaysInYear

    print("NUMSTEPS", "FAST TREE", "FULLTREE", "TIME")

    for numTimeSteps in numStepsList:
        start = time.time()
        model = FinModelRatesHullWhite(a, sigma)
        model.buildTree(texp, numTimeSteps, times, dfs)

        americanExercise = False
        v1 = model.americanBondOption_Tree(texp, strikePrice, face,
                                           couponTimes, couponFlows,
                                           americanExercise)

        v2 = model.europeanBondOption_Tree(texp, strikePrice, face,
                                           couponTimes, couponFlows)

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

        print(numTimeSteps, v1, v2, period)

#    plt.plot(numStepsList, treeVector)

    if 1 == 0:
        print("RT")
        printTree(model._rt, 5)
        print("BOND")
        printTree(model._bondValues, 5)
        print("OPTION")
        printTree(model._optionValues, 5)

    v = model.europeanBondOption_Jamshidian(texp, strikePrice, face,
                                            couponTimes, couponFlows, times,
                                            dfs)

    print("EUROPEAN BOND JAMSHIDIAN DECOMP", v)
Beispiel #14
0
def test_FinBondOptionZEROVOLConvergence():

    # Build discount curve
    settlementDate = FinDate(1, 12, 2019)  # CHANGED
    rate = 0.05
    discountCurve = FinDiscountCurveFlat(settlementDate, rate,
                                         FinFrequencyTypes.ANNUAL)

    # Bond details
    issueDate = FinDate(1, 9, 2015)
    maturityDate = FinDate(1, 9, 2025)
    coupon = 0.06
    frequencyType = FinFrequencyTypes.ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

    # Option Details
    expiryDate = settlementDate.addTenor("18m")  # FinDate(1, 12, 2021)
    print("EXPIRY:", expiryDate)
    face = 100.0

    dfExpiry = discountCurve.df(expiryDate)
    spotCleanValue = bond.cleanPriceFromDiscountCurve(settlementDate,
                                                      discountCurve)
    fwdCleanValue = bond.cleanPriceFromDiscountCurve(expiryDate, discountCurve)
    print("BOND SpotCleanBondPx", spotCleanValue)
    print("BOND FwdCleanBondPx", fwdCleanValue)
    print("BOND Accrued:", bond._accruedInterest)

    spotCleanValue = bond.cleanPriceFromDiscountCurve(settlementDate,
                                                      discountCurve)

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

    numTimeSteps = range(50, 1000, 50)
    strikePrices = [90, 100, 110, 120]

    for strikePrice in strikePrices:

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

        for numSteps in numTimeSteps:

            sigma = 0.0000001
            model = FinModelRatesBDT(sigma, numSteps)

            optionType = FinOptionTypes.EUROPEAN_CALL
            bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face,
                                        optionType)
            v1 = bondOption1.value(settlementDate, discountCurve, model)

            optionType = FinOptionTypes.AMERICAN_CALL
            bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face,
                                        optionType)
            v2 = bondOption2.value(settlementDate, discountCurve, model)

            optionType = FinOptionTypes.EUROPEAN_PUT
            bondOption3 = FinBondOption(bond, expiryDate, strikePrice, face,
                                        optionType)
            v3 = bondOption3.value(settlementDate, discountCurve, model)

            optionType = FinOptionTypes.AMERICAN_PUT
            bondOption4 = FinBondOption(bond, expiryDate, strikePrice, face,
                                        optionType)
            v4 = bondOption4.value(settlementDate, discountCurve, model)

            testCases.print(strikePrice, numSteps, callIntrinsic,
                            callIntrinsicPV, v1, v2, putIntrinsic,
                            putIntrinsicPV, v3, v4)
Beispiel #15
0
def test_FinBondOptionAmericanConvergenceONE():

    # Build discount curve
    settlementDate = FinDate(1, 12, 2019)
    discountCurve = FinDiscountCurveFlat(settlementDate, 0.05)

    # Bond details
    issueDate = FinDate(1, 9, 2014)
    maturityDate = FinDate(1, 9, 2025)
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)

    # Option Details
    expiryDate = FinDate(1, 12, 2020)
    strikePrice = 100.0
    face = 100.0

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

    timeSteps = range(100, 500, 10)

    for numTimeSteps in timeSteps:

        sigma = 0.05
        a = 0.1

        start = time.time()

        optionType = FinOptionTypes.AMERICAN_PUT
        bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model1 = FinModelRatesHW(sigma, a, numTimeSteps)
        v1put = bondOption1.value(settlementDate, discountCurve, model1)

        optionType = FinOptionTypes.EUROPEAN_PUT
        bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model2 = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_ONLY)
        v2put = bondOption2.value(settlementDate, discountCurve, model2)

        optionType = FinOptionTypes.AMERICAN_CALL
        bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model1 = FinModelRatesHW(sigma, a, numTimeSteps)
        v1call = bondOption1.value(settlementDate, discountCurve, model1)

        optionType = FinOptionTypes.EUROPEAN_CALL
        bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face,
                                    optionType)

        model2 = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_TREE)
        v2call = bondOption2.value(settlementDate, discountCurve, model2)

        end = time.time()

        period = end - start

        testCases.print(period, numTimeSteps, v1put, v2put, v1call, v2call)
Beispiel #16
0
def test_FinBondFuture():

    # Example taken from Martellini and Priaulet page 360
    freq = FinFrequencyTypes.SEMI_ANNUAL
    basis = FinDayCountTypes.ACT_ACT_ICMA
    issueDate = FinDate(15, 2, 2004)

    bond1 = FinBond(issueDate, FinDate(15, 8, 2011), 0.0500, freq, basis)
    bond2 = FinBond(issueDate, FinDate(15, 2, 2011), 0.0500, freq, basis)
    bond3 = FinBond(issueDate, FinDate(15, 8, 2010), 0.0575, freq, basis)
    bond4 = FinBond(issueDate, FinDate(15, 2, 2010), 0.0650, freq, basis)
    bond5 = FinBond(issueDate, FinDate(15, 8, 2009), 0.0600, freq, basis)
    bond6 = FinBond(issueDate, FinDate(15, 5, 2009), 0.0550, freq, basis)
    bond7 = FinBond(issueDate, FinDate(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)

    firstDeliveryDate = FinDate(1, 3, 2002)
    lastDeliveryDate = FinDate(28, 3, 2002)
    contractSize = 100000
    contractCoupon = 0.06

    bondFutureContract = FinBondFuture("TYH2", firstDeliveryDate,
                                       lastDeliveryDate, contractSize,
                                       contractCoupon)

    settlementDate = FinDate(10, 12, 2001)

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

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

    testCases.banner("EXAMPLE FROM CME")
    testCases.banner("================")
    settlementDate = FinDate(10, 10, 2017)

    bonds = []
    prices = []
    bond = FinBond(issueDate, FinDate(15, 8, 2027), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(99 + 1 / 32)
    bond = FinBond(issueDate, FinDate(15, 5, 2027), 0.02375, freq, basis)
    bonds.append(bond)
    prices.append(100 + 5 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 2, 2027), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(99 + 5 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 11, 2026), 0.02, freq, basis)
    bonds.append(bond)
    prices.append(97 + 7 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 8, 2026), 0.015, freq, basis)
    bonds.append(bond)
    prices.append(93 + 14 / 32)
    bond = FinBond(issueDate, FinDate(15, 5, 2026), 0.01625, freq, basis)
    bonds.append(bond)
    prices.append(94 + 21 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 2, 2026), 0.01625, freq, basis)
    bonds.append(bond)
    prices.append(94 + 29 / 32)
    bond = FinBond(issueDate, FinDate(15, 11, 2025), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(99 + 25 / 32)
    bond = FinBond(issueDate, FinDate(15, 8, 2025), 0.02, freq, basis)
    bonds.append(bond)
    prices.append(98 + 3 / 32)
    bond = FinBond(issueDate, FinDate(15, 5, 2025), 0.02125, freq, basis)
    bonds.append(bond)
    prices.append(99 + 5 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 2, 2025), 0.02, freq, basis)
    bonds.append(bond)
    prices.append(98 + 14 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 11, 2024), 0.0225, freq, basis)
    bonds.append(bond)
    prices.append(100 + 9 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(15, 8, 2024), 0.02375, freq, basis)
    bonds.append(bond)
    prices.append(101 + 7 / 32 + 1 / 64)
    bond = FinBond(issueDate, FinDate(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, cleanPrice in zip(bonds, prices):
        yld = bond.yieldToMaturity(settlementDate, cleanPrice)
        testCases.print(str(bond._maturityDate), yld)

    firstDeliveryDate = FinDate(1, 12, 2017)
    lastDeliveryDate = FinDate(28, 12, 2017)

    contractSize = 100000
    contractCoupon = 0.06

    bondFutureContract = FinBondFuture("TYZ7", firstDeliveryDate,
                                       lastDeliveryDate, contractSize,
                                       contractCoupon)

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

    # Get the Invoice Prices
    futuresPrice = 125.265625

    testCases.header("BOND MATURITY", "PRINCIPAL INVOICE PRICE")
    for bond in bonds:
        pip = bondFutureContract.principalInvoicePrice(bond, futuresPrice)
        testCases.print(str(bond._maturityDate), pip)

    testCases.header("BOND MATURITY", "TOTAL INVOICE AMOUNT")
    for bond in bonds:
        tia = bondFutureContract.totalInvoiceAmount(settlementDate, bond,
                                                    futuresPrice)
        testCases.print(str(bond._maturityDate), tia)

    ctd = bondFutureContract.cheapestToDeliver(bonds, prices, futuresPrice)

    testCases.header("CTD MATURITY", "CTD COUPON")
    testCases.print(str(ctd._maturityDate), ctd._coupon)
Beispiel #17
0
def test_BDTExampleTwo():
    # Valuation of a European option on a coupon bearing bond
    # This follows example in Fig 28.11 of John Hull's book (6th Edition)
    # but does not have the exact same dt so there are some differences

    testCases.banner("===================== FIG 28.11 HULL BOOK =============")

    settlementDate = FinDate(1, 12, 2019)
    issueDate = FinDate(1, 12, 2015)
    expiryDate = settlementDate.addTenor("18m")
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    freqType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType)

    couponTimes = []
    couponFlows = []
    cpn = bond._coupon / bond._frequency
    numFlows = len(bond._flowDates)

    for i in range(1, numFlows):
        pcd = bond._flowDates[i - 1]
        ncd = bond._flowDates[i]
        if pcd < settlementDate and ncd > settlementDate:
            flowTime = (pcd - settlementDate) / gDaysInYear
            couponTimes.append(flowTime)
            couponFlows.append(cpn)

    for flowDate in bond._flowDates:
        if flowDate > settlementDate:
            flowTime = (flowDate - settlementDate) / gDaysInYear
            couponTimes.append(flowTime)
            couponFlows.append(cpn)

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

    strikePrice = 105.0
    face = 100.0

    tmat = (maturityDate - settlementDate) / gDaysInYear
    texp = (expiryDate - settlementDate) / gDaysInYear
    times = np.linspace(0, tmat, 11)
    dates = settlementDate.addYears(times)
    dfs = np.exp(-0.05 * times)

    testCases.header("LABEL", "VALUES")
    testCases.print("TIMES:", times)

    curve = FinDiscountCurve(settlementDate, dates, dfs)

    price = bond.cleanPriceFromDiscountCurve(settlementDate, curve)
    testCases.print("Fixed Income Price:", price)

    sigma = 0.20

    # Test convergence
    numStepsList = [5]  #[100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
    exerciseType = FinExerciseTypes.AMERICAN

    testCases.header("Values")
    treeVector = []
    for numTimeSteps in numStepsList:
        model = FinModelRatesBDT(sigma, numTimeSteps)
        model.buildTree(tmat, times, dfs)
        v = model.bondOption(texp, strikePrice, face, couponTimes, couponFlows,
                             exerciseType)

        testCases.print(v)
        treeVector.append(v['call'])

    if PLOT_GRAPHS:
        plt.plot(numStepsList, treeVector)

    # The value in Hull converges to 0.699 with 100 time steps while I get 0.70

    if 1 == 0:
        print("RT")
        printTree(model._rt, 5)
        print("Q")
        printTree(model._Q, 5)
Beispiel #18
0
def test_FinBond():

    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'])

    freqType = FinFrequencyTypes.SEMI_ANNUAL
    settlementDate = FinDate(19, 9, 2012)
    face = ONE_MILLION

    for accrualType in FinDayCountTypes:

        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 = FinDate(maturityDt._d, maturityDt._m, 2000)

            coupon = bond['coupon'] / 100.0
            cleanPrice = bond['mid']
            bond = FinBond(issueDt, maturityDt, coupon, freqType, accrualType,
                           100)

            ytm = bond.yieldToMaturity(settlementDate, cleanPrice)
            accd = bond._accruedInterest
            accd_days = bond._accruedDays

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

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

    accrualConvention = FinDayCountTypes.ACT_ACT_ICMA
    y = 0.062267
    settlementDate = FinDate(19, 4, 1994)
    issueDate = FinDate(15, 7, 1990)
    maturityDate = FinDate(15, 7, 1997)
    coupon = 0.085
    face = ONE_MILLION
    freqType = FinFrequencyTypes.SEMI_ANNUAL
    bond = FinBond(issueDate, maturityDate, coupon, freqType,
                   accrualConvention, face)

    testCases.header("FIELD", "VALUE")
    fullPrice = bond.fullPriceFromYTM(settlementDate, y)
    testCases.print("Full Price = ", fullPrice)
    cleanPrice = bond.cleanPriceFromYTM(settlementDate, y)
    testCases.print("Clean Price = ", cleanPrice)
    accd = bond._accruedInterest
    testCases.print("Accrued = ", accd)
    ytm = bond.yieldToMaturity(settlementDate, cleanPrice)
    testCases.print("Yield to Maturity = ", ytm)

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

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

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

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

    modifiedDuration = bond.modifiedDuration(settlementDate, y)
    testCases.print("Modified Duration = ", modifiedDuration)

    macauleyDuration = bond.macauleyDuration(settlementDate, y)
    testCases.print("Macauley Duration = ", macauleyDuration)

    conv = bond.convexityFromYTM(settlementDate, 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 = FinDiscountCurveFlat(settlementDate, ytm,
                                     FinFrequencyTypes.SEMI_ANNUAL)

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

    cleanPrice = bond.cleanPriceFromYTM(settlementDate, ytm)
    asw = bond.assetSwapSpread(settlementDate, cleanPrice, flatCurve)
    testCases.print("Discounted on Bond Curve ASW:", asw * 10000)

    # When the libor curve is the Libor curve then the ASW is positive
    liborCurve = buildIborCurve(settlementDate)
    asw = bond.assetSwapSpread(settlementDate, cleanPrice, liborCurve)
    oas = bond.optionAdjustedSpread(settlementDate, cleanPrice, liborCurve)
    testCases.print("Discounted on LIBOR Curve ASW:", asw * 10000)
    testCases.print("Discounted on LIBOR Curve OAS:", oas * 10000)

    p = 90.0
    asw = bond.assetSwapSpread(settlementDate, p, liborCurve)
    oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve)
    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.assetSwapSpread(settlementDate, p, liborCurve)
    oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve)
    testCases.print("Par bond at 100 ASW:", asw * 10000)
    testCases.print("Par bond at 100 OAS:", oas * 10000)

    p = 120.0
    asw = bond.assetSwapSpread(settlementDate, p, liborCurve)
    oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve)
    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")
    settlementDate = FinDate(21, 7, 2017)
    issueDate = FinDate(15, 5, 2010)
    maturityDate = FinDate(15, 5, 2027)
    coupon = 0.02375
    freqType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    face = 100.0

    bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType,
                   face)

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

    yld = bond.currentYield(cleanPrice)
    testCases.print("Current Yield = ", yld)

    ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                               FinYTMCalcType.UK_DMO)
    testCases.print("UK DMO Yield To Maturity = ", ytm)

    ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                               FinYTMCalcType.US_STREET)
    testCases.print("US STREET Yield To Maturity = ", ytm)

    ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                               FinYTMCalcType.US_TREASURY)
    testCases.print("US TREASURY Yield To Maturity = ", ytm)

    fullPrice = bond.fullPriceFromYTM(settlementDate, ytm)
    testCases.print("Full Price = ", fullPrice)

    cleanPrice = bond.cleanPriceFromYTM(settlementDate, ytm)
    testCases.print("Clean Price = ", cleanPrice)

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

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

    duration = bond.dollarDuration(settlementDate, ytm)
    testCases.print("Dollar Duration = ", duration)

    modifiedDuration = bond.modifiedDuration(settlementDate, ytm)
    testCases.print("Modified Duration = ", modifiedDuration)

    macauleyDuration = bond.macauleyDuration(settlementDate, ytm)
    testCases.print("Macauley Duration = ", macauleyDuration)

    conv = bond.convexityFromYTM(settlementDate, ytm)
    testCases.print("Convexity = ", conv)

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

    testCases.banner("BLOOMBERG APPLE CORP BOND EXAMPLE")
    settlementDate = FinDate(21, 7, 2017)
    issueDate = FinDate(13, 5, 2012)
    maturityDate = FinDate(13, 5, 2022)
    coupon = 0.027
    freqType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.THIRTY_E_360_ISDA
    face = 100.0

    bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType,
                   face)

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

    yld = bond.currentYield(cleanPrice)
    testCases.print("Current Yield", yld)

    ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                               FinYTMCalcType.UK_DMO)
    testCases.print("UK DMO Yield To Maturity", ytm)

    ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                               FinYTMCalcType.US_STREET)
    testCases.print("US STREET Yield To Maturity", ytm)

    ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
                               FinYTMCalcType.US_TREASURY)
    testCases.print("US TREASURY Yield To Maturity", ytm)

    fullPrice = bond.fullPriceFromYTM(settlementDate, ytm)
    testCases.print("Full Price", fullPrice)

    cleanPrice = bond.cleanPriceFromYTM(settlementDate, ytm)
    testCases.print("Clean Price", cleanPrice)

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

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

    duration = bond.dollarDuration(settlementDate, ytm)
    testCases.print("Dollar Duration", duration)

    modifiedDuration = bond.modifiedDuration(settlementDate, ytm)
    testCases.print("Modified Duration", modifiedDuration)

    macauleyDuration = bond.macauleyDuration(settlementDate, ytm)
    testCases.print("Macauley Duration", macauleyDuration)

    conv = bond.convexityFromYTM(settlementDate, ytm)
    testCases.print("Convexity", conv)
def test_FinBondOptionAmericanConvergenceTWO():

    # Build discount curve
    settlementDate = FinDate(1, 12, 2019)
    discountCurve = FinDiscountCurveFlat(settlementDate, 0.05)

    # Bond details
    issueDate = FinDate(1, 12, 2015)
    maturityDate = settlementDate.addTenor("10Y")
    coupon = 0.05
    frequencyType = FinFrequencyTypes.SEMI_ANNUAL
    accrualType = FinDayCountTypes.ACT_ACT_ICMA
    bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType)
    expiryDate = settlementDate.addTenor("18m")
    face = 100.0

    spotValue = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve)
    testCases.header("LABEL", "VALUE")
    testCases.print("BOND PRICE", spotValue)

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

    sigma = 0.01
    a = 0.1
    hwModel = FinModelRatesHW(sigma, a)
    K = 102.0

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

    numStepsVector = range(100, 500, 100)

    for numSteps in numStepsVector:
        hwModel = FinModelRatesHW(sigma, a, numSteps)

        start = time.time()

        europeanCallBondOption = FinBondOption(bond, expiryDate, K, face,
                                               FinOptionTypes.EUROPEAN_CALL)

        v_ec = europeanCallBondOption.value(settlementDate, discountCurve,
                                            hwModel)

        americanCallBondOption = FinBondOption(bond, expiryDate, K, face,
                                               FinOptionTypes.AMERICAN_CALL)

        v_ac = americanCallBondOption.value(settlementDate, discountCurve,
                                            hwModel)

        europeanPutBondOption = FinBondOption(bond, expiryDate, K, face,
                                              FinOptionTypes.EUROPEAN_PUT)

        v_ep = europeanPutBondOption.value(settlementDate, discountCurve,
                                           hwModel)

        americanPutBondOption = FinBondOption(bond, expiryDate, K, face,
                                              FinOptionTypes.AMERICAN_PUT)

        v_ap = americanPutBondOption.value(settlementDate, discountCurve,
                                           hwModel)

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

        testCases.print(period, numSteps, 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(numStepsVector, vec_ac, label="American Call")
        plt.legend()

        plt.figure()
        plt.plot(numStepsVector, vec_ap, label="American Put")
        plt.legend()