I have bootstrapped a yield curve and I have managed to extract discount factors from this yield curve but the discount factors are referencing from the Evaluation Date. These discount factors are used to calculate the PV of the bond but they can not be used to calculate the Dirty Price of the bond if the Evaluation Date is different from the Bond Settlement Date. How do I extract the Discount Factors from the Bond Settlement Date instead of the Evaluation Date. Hoping that my question is clear.

Find below a part of the code that I have tried to use to extract the discount factors;

fields = ['accrualStartDate', 'accrualEndDate', 'date', 'nominal', 'rate',
          'amount', 'accrualDays', 'accrualPeriod']
BondCashflows = []
for cf in list(map(ql.as_fixed_rate_coupon, bond.cashflows()))[:-1]:
    row = {fld: eval(f"cf.{fld}()") for fld in fields}
    row['AccrualPeriod'] = round((row['accrualEndDate'] - row['accrualStartDate']) / 365, 4)
    if row['date'] >= today:
        row['ZeroRate (NPV)'] = round(curve.zeroRate(row['date'], day_count, ql.Compounded, ql.Annual).rate(), 9)
        row['ZeroRate (Dirty Price)'] = round(curve.forwardRate(bond.settlementDate(), row['date'], day_count, ql.Compounded, ql.Annual).rate(), 9)
        row['DiscFactor (NPV)'] = round(curve.discount(row['date']), 9)
        row['DiscFactor (Dirty Price)'] = round(curve.discount(bond.settlementDate(), row['date']), 9)
    else:
        row['ZeroRate (NPV)'] = 0
        row['ZeroRate (Dirty Price)'] = 0
        row['DiscFactor (NPV)'] = 0  # or any other appropriate handling for dates before today
        row['DiscFactor (Dirty Price)'] = 0  # or any other appropriate handling for dates before today
    row['NPV'] = round(row['DiscFactor (NPV)'] * row['amount'], 9)
    BondCashflows.append(row)

BondCashflows = pd.DataFrame(BondCashflows)

print(BondCashflows)
1

There are 1 answers

0
ccc On

Found a workaround of dividing the discount factors from evaluation date to accrual end date by the discount factor from evaluation date to bond settlement date as shown in the code below;

fields = ['accrualStartDate', 'accrualEndDate', 'date', 'nominal', 'rate',
          'amount', 'accrualDays', 'accrualPeriod']
BondCashflows = []
for cf in list(map(ql.as_fixed_rate_coupon, bond.cashflows()))[:-1]:
    row = {fld: eval(f"cf.{fld}()") for fld in fields}
    row['AccrualPeriod'] = round((row['accrualEndDate'] - row['accrualStartDate']) / 365, 4)
    if row['date'] >= today:
        row['ZeroRate (NPV)'] = round(curve.zeroRate(row['date'], day_count, ql.Compounded, ql.Annual).rate(), 9)
        row['ZeroRate (Dirty Price)'] = round(curve.forwardRate(bond.settlementDate(), row['date'], day_count, ql.Compounded, ql.Annual).rate(), 9)
        row['DiscFactor (NPV)'] = round(curve.discount(row['date']), 9)
        row['DiscFactor (Dirty Price)'] = round(curve.discount(row['date']) / curve.discount(bond.settlementDate()), 9)
    else:
        row['ZeroRate (NPV)'] = 0
        row['ZeroRate (Dirty Price)'] = 0
        row['DiscFactor (NPV)'] = 0  # or any other appropriate handling for dates before today
        row['DiscFactor (Dirty Price)'] = 0  # or any other appropriate handling for dates before today
    row['NPV'] = round(row['DiscFactor (NPV)'] * row['amount'], 9)
    row['Dirty Price'] = round(row['DiscFactor (Dirty Price)'] * row['amount'], 9)
    BondCashflows.append(row)

BondCashflows = pd.DataFrame(BondCashflows)

print(BondCashflows)