|
From: Philippe H. <phi...@ex...> - 2020-05-31 13:47:55
|
I am pricing a corporate bond from a US treasury curve shifted by a credit
z-spread with the following steps:
1. Build a US Treasury curve via traditional helpers based on 6 UST bond
clean prices (2/3/5/7/10/30y), with ql.QuoteHandle() for each bond price
input
ust_crv = ql.PiecewiseFlatForward(settle_date, helpers, day_count)
2. Build a shifted curve handle as follows:
corp_spread = ql.SimpleQuote(shift)
corp_spreadh = ql.QuoteHandle(corp_spread)
ust_crvh = ql.RelinkableYieldTermStructureHandle(ust_crv)
corp_crv = ql.ZeroSpreadedTermStructure(ust_crvh, corp_spreadh)
corp_crv_handle = ql.RelinkableYieldTermStructureHandle(corp_crv)
3. Create a corporate fixed rate bond corp_bond via ql.Bond() and set its
pricing engine as follows:
transEngine = ql.DiscountingBondEngine(corp_crv_handle)
corp_bond.setPricingEngine(transEngine)
4. get the base dirty price of the bond via corp_bond.NPV(), acknowledging
that since the UST curve ust_crv is built from helpers that have US
treasury bond price inputs based on ql.QuoteHandle() then corp_bond.NPV()
should inherit lazy NPV property from the base ust_crv. in other words,
when I change any US treasury bond input price, corp_bond.NPV() should
change. The latter behavior is satisfied.
Here is my problem:
I am trying to write a module to compute the key rate 01 (KR01) to the UST
curve, keeping the corporate spread constant, whereby I shift each of the 6
bond inputs by a price shift corresponding to one yield basis point
converted to a price shift via the bond's respective dv01. My approach is
therefore to use the lazy NPv() whereby via the curve dependencies,
perturbing one input in the UST curve would propagate to the shifter
corporate curve, thence impact the corporate bond price via lazy NPV.
So I do a loop as follows:
def key_rate_dv01(corp_bond, helpers):
base_npv = corp_bond.NPV()
for helper in helpers:
helper_base_value = helper.bond().cleanPrice()
quote = helper.quote
'''here I do some bond math to compute the dv01 of the helper
based on ql bond math
but didn't include code to simplify'''
quote.setValue(helper_base_value + helper_dv01)
deal_dv01 = corp_bond.NPV() - base_npv
print(f'{helper}:{deal_dv01}')
quote.setValue(helper_base_value)
The code above does "something", because for each iteration, I get a
non-zero deal_dv01. However, the results are not correct, when compared to
a "brute force" approach whereby I simply rebuild the base curve by
perturbing the bond price input to the curve directly. the results differ
by about 10% relative, which is clearly wrong.
So I am wondering if there is any flaw in my logic above?
Regards
Philippe
--
Brokerage services offered through Exos Securities LLC, member of
SIPC <http://www.sipc.org/> / FINRA <http://www.finra.org/>. For important
disclosures, click here <https://www.exosfinancial.com/disclosures>.
|