3
$\begingroup$

i'm puzzled by the way Quantlib handles the evaluation date in the yield term structure classes. I have the following code as example:

import QuantLib as ql
import pandas as pd


#Curve
def build_termstruc(curve_date):
    helpers = []
    handle = ql.YieldTermStructureHandle()
    tenors = [1,3,6,9,12,18,2,3,4,5,6,7,8,9,10,15,20]
    swap_rates = [2.75,2.875,2.99,3.12,3.25,3.5,3.61,3.795,3.925,4.025,4.115,4.195,4.265,4.335,4.4,4.555,4.68]

    fixing_days = 0
    calendar = ql.NullCalendar()
    settlement_days = 0
    day_counter = ql.Actual360()
    index = ql.OvernightIndex("index", settlement_days,ql.CLPCurrency(),calendar,day_counter)
    for i in range(len(tenors)):
        if i == 0:
            helpers += [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(swap_rates[i]/100)),
                            ql.Period(1,ql.Days),
                            fixing_days,
                            calendar,
                            ql.Unadjusted,
                            False,
                            ql.Actual360())]
            continue
        elif i < 6 and i > 0:
            period = ql.Period(tenors[i], ql.Months)
            frequency = ql.Months
        elif i >=6:
            period = ql.Period(tenors[i], ql.Years)
            frequency = ql.Years

        helpers += [ql.OISRateHelper(settlement_days,
                        period,
                        ql.QuoteHandle(ql.SimpleQuote(swap_rates[i]/100)),
                        index,
                        handle,
                        False,
                        0,
                        ql.Following,
                        frequency)]
    return ql.PiecewiseFlatForward(curve_date, helpers, ql.Actual360())
def build_bond():
    #Bond
    issue_date = ql.Date(1,6,2015)
    maturity_date = ql.Date(1,6,2020)
    calendar = ql.NullCalendar()
    coupon_day_count = ql.Unadjusted
    payment_convention = ql.Following
    date_generation = ql.DateGeneration.Forward
    month_end = False
    settlement_days = 0
    int_day_count = ql.Thirty360()
    notional = 100
    coupons = [4.5/100]
    #non static variables
    schedule = ql.Schedule (issue_date,
                            maturity_date,
                            ql.Period(ql.Semiannual),
                            calendar,
                            coupon_day_count,
                            payment_convention,
                            date_generation,
                            month_end)

    return ql.FixedRateBond(settlement_days, notional, schedule, coupons, int_day_count)

def test1():
    curve_date = ql.Date(14,11,2018)
    ql.Settings.instance().evaluationDate = curve_date
    ts = build_termstruc(curve_date)

    bond = build_bond()
    bond_IIR = ql.InterestRate(3.78/100, ql.Actual365Fixed(), ql.Compounded, ql.Annual)
    npv = ql.CashFlows.npv(bond.cashflows(), bond_IIR, False)
    spread = ql.CashFlows.zSpread(bond.cashflows(), npv, ts, ql.Actual360(), ql.Compounded, ql.Annual, True)*100
    print('NPV: ', npv,'Spread: ', spread)

def test2():
    curve_date = ql.Date(14,11,2018)
    ts = build_termstruc(curve_date)
    ql.Settings.instance().evaluationDate = curve_date

    bond = build_bond()
    bond_IIR = ql.InterestRate(3.78/100, ql.Actual365Fixed(), ql.Compounded, ql.Annual)

    npv = ql.CashFlows.npv(bond.cashflows(), bond_IIR, False)
    spread = ql.CashFlows.zSpread(bond.cashflows(), npv, ts, ql.Actual360(), ql.Compounded, ql.Annual, True)*100
    print('NPV: ', npv,'Spread: ', spread)

if __name__ == '__main__':
    test1()
    test2()

The idea of the code is that the first two methods build a term structure and a bond and the other two (test1 and test2) only change the position where the evaluationDate is set. The result is the following:

NPV:  103.15824069057247 Spread:  0.18307250901326033 
NPV:  103.15824069057247 Spread:  0.18307250901326033

I don't get why i'm getting different z-spreads if im setting the curve reference date.

$\endgroup$

1 Answer 1

4
$\begingroup$

Your spread definitions are different. In Def Test2(), it is multiplied by 100. That's the cause of the decimal shift in the spread.

$\endgroup$
1
  • 1
    $\begingroup$ bah, i have a bug in another code and did this script to show it, but now i can't replicate the problem and i didn't notice because i hadn't multiply by 100 (the numbers didn't look equal). My bad, i guess this question can be removed. $\endgroup$ Nov 18, 2018 at 0:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.