QuantLib icon indicating copy to clipboard operation
QuantLib copied to clipboard

Matching Bloomberg's CDSO using quantlib CdsOption

Open laj007 opened this issue 3 years ago • 6 comments
trafficstars

Hello - I'm trying to use CdsOption in order to price CDS payer/receiver options. Been through pretty much everything online, but still can't match what I see in BBG's CDSO function.

For instance, with valuation date 4/1/2022, reference spread 66bps, strike 75bps, expiry 6/15/2022, and vol 50%, one should see a price in the 0.1687 area. The way I do it (see below) gets me closer to 0.1272 (NPV). Similarly my forward spread is off too (~65.4bps vs BBG's ~68.2bps).

I'm using all usual input (e.g. discount curve) that prices/matches the underlying CDS perfectly, so am quite sure the issue is not on that front, but rather in the logic I'm using.

For instance, I get a little confused as to how to specify the strike given it's not an explicit input in CdsOption. Another potential source of issue is that CdsOption seems to only take CDS defined on a running-spread basis rather than conventional pricing.

Code below.

Thanks so much for the help !

side= 'Pay'
ref = 65
cpn = 100
recovery = 0.4
tradeDate = ql.Date(1, 4, 2022)   
expiry = ql.Date(15,  6, 2022) 
tenor = 5
vol = 0.5
strike = 75

ref /= 1e4
cpn /= 1e4
strike /= 1e4


if side == 'Pay':
    
    sideCDS = ql.Protection.Buyer

elif side == 'Rec': 
    
    sideCDS = ql.Protection.Seller

termDate    = cdsMat(tenor,runDate)

ql.Settings.instance().setEvaluationDate(tradeDate)


# underlying cds to get probabilityCurve

cdsSchedule = ql.Schedule(tradeDate, termDate,
                          3*ql.Period(ql.Monthly),
                          ql.WeekendsOnly(),
                          ql.Following, ql.Unadjusted,
                          ql.DateGeneration.CDS, False)

quotedTrade = ql.CreditDefaultSwap( ql.Protection.Seller, 100, 0, ref, cdsSchedule,
                                    ql.Following,ql.Actual360(),True,True,tradeDate+1,
                                    ql.WeekendsOnly().advance(tradeDate,3*ql.Period(ql.Daily)),
                                    ql.FaceValueClaim(), ql.Actual360(True))

h = quotedTrade.impliedHazardRate(0, # target NPV
                                  discCurve,
                                  ql.Actual365Fixed(), # dayCounter
                                  recovery,
                                  1e-10, # accuracy
                                  ql.CreditDefaultSwap.ISDA) # model

probabilityCurve = ql.RelinkableDefaultProbabilityTermStructureHandle()

probabilityCurve.linkTo(ql.FlatHazardRate(0,ql.WeekendsOnly(),
                        ql.QuoteHandle(ql.SimpleQuote(h)),
                        ql.Actual365Fixed()))

engine = ql.IsdaCdsEngine(probabilityCurve,recovery,discCurve)

quotedTrade.setPricingEngine(engine)


# underlying CDS - for option pricer (using strike as spread ?)

cds = ql.CreditDefaultSwap(sideCDS, 100, strike, cdsSchedule, ql.Following, ql.Actual365Fixed())
engine = ql.IsdaCdsEngine(probabilityCurve,recovery,discCurve)
cds.setPricingEngine(engine)

vol = ql.QuoteHandle(ql.SimpleQuote(vol))
expiry = ql.Date(expiry.day,expiry.month,expiry.year) 
exercise = ql.EuropeanExercise(expiry)

cds_option = ql.CdsOption(cds, exercise, knocksOut=True)
cds_option.setPricingEngine((ql.BlackCdsOptionEngine(probabilityCurve, recovery, discCurve, vol)))

cds_option.NPV()
cds_option.atmRate()*1e4

laj007 avatar Apr 03 '22 20:04 laj007

Thanks for posting! It might take a while before we look at your issue, so don't worry if there seems to be no feedback. We'll get to it.

boring-cyborg[bot] avatar Apr 03 '22 20:04 boring-cyborg[bot]

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

github-actions[bot] avatar Jun 03 '22 02:06 github-actions[bot]

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

github-actions[bot] avatar Aug 03 '22 02:08 github-actions[bot]

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

github-actions[bot] avatar Oct 03 '22 02:10 github-actions[bot]

what you get using mathworks. https://www.mathworks.com/help/fininst/cdsoptprice.html Click Button "Try This example" https://www.mathworks.com/help/fininst/cdsoptprice.html#cdsoptprice_example1

qmarsun avatar Oct 17 '22 03:10 qmarsun

I think you should be using knocksOut=False. There is no knockout for indices.

thrasibule avatar Mar 17 '23 20:03 thrasibule