Open amir656 opened 3 years ago
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.
The issue appears to take into affect within 120 days of maturity. I expanded on my example above to create some plots
# Setup bond
start_date = ql.Date(24, 5, 2011)
maturity_date = ql.Date(24, 5, 2021)
tenor = ql.Period(ql.Semiannual)
calendar = ql.UnitedStates()
payment_rescheduling=4
is_monthend=False
first_coupon_date = ql.Date(24, 11, 2011)
penultimate_coupon_date = ql.Date(24,11,2020)
settleDate=ql.Date(20, 5, 2021)
payment_schedule = ql.Schedule(start_date, maturity_date, tenor, calendar, payment_rescheduling, payment_rescheduling, ql.DateGeneration.Backward, is_monthend, first_coupon_date, penultimate_coupon_date)
settlement_days = 2
face_amount=100.00
coupon = [8.25 / 100]
accrual_daycount = ql.Thirty360()
bond = ql.FixedRateBond(settlement_days,
face_amount,
payment_schedule,
coupon,
accrual_daycount)
# Yield arguments
dc = accrual_daycount
clean_px = 16.25
compounded = 1
simpleThenCompounded = 3
freq = 2
acc = 1e-8
max_evals = 100
# Sometimes yield fails even with 1000 evals
def try_bond_yield(clean_px, dc, comp, freq, settleDate, acc, max_evals):
try:
return bond.bondYield(clean_px, dc, comp, freq, settleDate, acc, max_evals)
except:
return np.nan
Some plotting logic
def ql2pddate(dt):
return pd.to_datetime(pd.datetime(dt.year(), dt.month(), dt.dayOfMonth()))
def plot_yield_curve(clean_px, comp, first, last, plot=True):
# plots
yield_curve_1000_eval = [(maturity_date - i, try_bond_yield(clean_px, dc, comp, freq, maturity_date - i, acc, 1000)) for i in range(180)]
x_1000s, y_1000s = [ql2pddate(y[0]) for y in yield_curve_1000_eval], [y[1] for y in yield_curve_1000_eval]
if plot:
plt.plot(x_1000s[first:last], y_1000s[first:last], marker='*')
return y_1000s[first:last]
def plot_simple_vs_compounded(px, start, stop):
fig = plt.figure(figsize=(8, 6))
fig.suptitle('%d - %d days from Mat at px %d' % (stop, start, px))
ySimple = plot_yield_curve(px, simpleThenCompounded, start, stop)
yComp = plot_yield_curve(px, compounded, start, stop)
print('%d - %d days from Mat at px %d, \nSimple, Compounded: %s' % (stop, start, px, zip(ySimple, yComp)))
for px in [100 / 4, 100/3, 100/2, 100 / 1.1]:
for s in range(0, 151, 30):
plot_simple_vs_compounded(px, s, s+30)
Results at px of 25
30 - 0 days from Mat at px 25,
Simple, Compounded: [(0.0, 0.0), (928.0521153930413, 9.007373981992987e+99), (464.5336008072691, 1.4408049693914344e+50), (310.02796300788884, 3.630421486687343e+33), (232.77554534862855, 1.8224059781154334e+25), (186.42441652523542, 1.910151094587377e+20), (155.5239327326953, 9.148661915185024e+16), (133.4523895120958, 389173291773368.0), (116.89893463296846, nan), (104.02420575420334, nan), (93.72458543338414, nan), (85.29777172144429, 2609928229.3713245), (78.2755632582976, nan), (72.33382069675642, 105628711.91714627), (67.24101588834068, 29963844.071501397), (62.82736156825105, 10054819.060280109), (58.965517234418236, 3867514.1315884525), (55.55810492035721, 1664596.7816048036), (52.529386153709765, 786808.338447464), (49.8195674422999, 402427.63535591634), (47.380813948609166, 220103.22725215848), (45.17440229598184, 127504.1680811393), (43.16864966114176, 77620.70543839353), (41.337383319835254, 49337.11494631205), (39.658792652946254, 32566.354062425376), (38.114556725926874, 22222.598372822657), (36.68917324637504, 15616.534031912346), (35.36943652622516, 11264.685232095877), (34.14402741743858, 8317.276915165425), (33.00318803919287, 6270.782553833916)]
60 - 30 days from Mat at px 25,
Simple, Compounded: [(31.938461544082877, 4817.606685586468), (30.942482307339546, 3764.5903017404444), (30.0088054040111, 2987.3599341044037), (29.131767116930376, 2403.983359318566), (28.306370027256712, 1959.3483781126315), (27.528187889155483, 1615.6667457929266), (26.793286218811204, 1346.568124126999), (26.09815591612784, 1133.3486608270705), (25.439657248333724, 962.5413281458281), (24.81497249389394, 824.3136914556432), (24.22156573704633, 711.3934854585416), (23.657148427098853, 618.3368126092073), (23.119649995028382, 541.0224082267935), (22.607192478354712, 476.2973563800693), (22.118068661674208, 421.7257255122738), (21.650723030880016, 375.40808508491995), (21.203735376668313, 335.8504550827832), (20.775806348316493, 301.868140039999), (20.365744874650183, 272.51445633452596), (19.97245710176118, 247.02741090697677), (19.59493671264297, 224.78945455381904), (19.232256277673727, 205.29684755236315), (18.883559759163468, 188.13615575964855), (18.548055676424944, 172.96608066519372), (18.204573156833284, 159.0617117383212), (18.22501120829758, 159.50331191956795), (17.913746816069846, 147.51143636135657), (17.61363150864227, 136.79218673689508), (17.324078564179416, 127.17849337447367), (17.044541734392745, 118.528935117048)]
90 - 60 days from Mat at px 25,
Simple, Compounded: [(16.774511817731444, 110.72328233036238), (16.51351351162849, 103.65889794455187), (16.261102736647402, 97.247816256273), (16.016864052251904, 91.41436018846929), (15.78040835316584, 86.09318849462142), (15.55137089106412, 81.22768806406195), (15.32940938252228, 76.76864475065649), (15.114202230869308, 72.67313948510531), (14.905447088332405, 68.9036283229319), (14.702859380881664, 65.4271723792076), (14.506171011632787, 62.21479103126028), (14.315129232916041, 59.240916794438036), (14.129495514122338, 56.482933996953435), (13.949044579575524, 53.92078753038206), (13.773563522959213, 51.53664950803581), (13.602850910569433, 49.31463467903293), (13.436716077191274, 47.24055667771487), (13.27497837705718, 45.30171858083502), (13.11746655711104, 43.486732479243855), (12.964018146272537, 41.785363664317835), (12.814478906717422, 40.1883957009084), (12.668702283379446, 38.68751320813839), (12.526549011556167, 37.27519995268258), (12.387886566212988, 35.944649801415565), (12.252588831499725, 34.68968903934742), (11.865710784398482, 31.324716584972194), (11.742725731213444, 30.320804086606557), (11.622558193426578, 29.368980115410043), (11.50511325980683, 28.46568825345328), (11.390300229604868, 27.60766765315281)]
120 - 90 days from Mat at px 25,
Simple, Compounded: [(11.27803238933187, 26.791924397288923), (11.16822680543035, 26.0157060283607), (11.06080410161854, 25.276478764828504), (10.955688276439375, 24.571907260378744), (10.852806539431601, 23.89983638629925), (10.752089136635945, 23.25827502333044), (10.653469165485529, 22.64538140121145), (10.55688249324282, 22.059450002113522), (10.462267545619984, 21.49889977957441), (10.36956521934464, 20.962263455664377), (10.278718758182883, 20.448177938440626), (10.189673636584235, 19.9553756785206), (10.102377421040256, 19.482676739498856), (10.016779730364785, 19.028981733926056), (9.93283208830766, 18.593265325881156), (9.850487826548285, 18.174570401388856), (9.769702043114194, 17.7720026663146), (9.69043152742395, 17.384725879052127), (9.61263458306265, 17.01195733038631), (9.53627109304303, 16.65296385387051), (9.461302361083803, 16.307058089674015), (9.387691065977311, 15.973595155244624), (9.315401227941681, 15.65196951576882), (9.233687183981981, 15.317970688388897), (9.24439812340771, 15.341612142587442), (9.174648226757485, 15.041987947576079), (9.106119169993903, 14.752593382023942), (9.03877970198084, 14.472954184614931), (8.972599624962449, 14.202623452570336), (8.90754975633492, 13.94117970243611)]
150 - 120 days from Mat at px 25,
Simple, Compounded: [(8.843601894148462, 13.688225199405869), (8.780728761622512, 13.443384360124575), (8.718903952202927, 13.20630229631919), (8.658101975413011, 12.976643437604313), (8.598298116834396, 12.754090331362686), (8.539468468346698, 12.53834244863333), (8.481589868397808, 12.32911510187548), (8.424639915512008, 12.126138484783517), (8.368596886292032, 11.929156765629166), (8.31343970852777, 11.737927154725327), (8.25914802415685, 11.552219166984415), (8.20570202441319, 11.371813878443135), (8.15308254272761, 11.196503249715011), (8.10127099733065, 11.026089418927091), (8.050249314377762, 10.860384187028636), (8.00000000455426, 10.699208416756658), (7.950506064376465, 10.54239148582451), (7.901750991281004, 10.3897708850252), (7.853718789154392, 10.241191660617186), (7.806393869968472, 10.096506066734317), (7.759761135106775, 9.955573171733699), (7.71380590885786, 9.818258393605198), (7.66851390683653, 9.684433272092683), (7.623871253056724, 9.553975065270892), (7.570927707631011, 9.414104197631199), (7.579864475915971, 9.426766453785536), (7.5364804437245505, 9.302695266406019), (7.493706422207487, 9.181654242622399), (7.45152999720737, 9.063540694514227), (7.409939081982592, 8.948256345435144)]
180 - 150 days from Mat at px 25,
Simple, Compounded: [(7.368921949425173, 8.835707098925965), (7.32846714819052, 8.72580274418203), (7.288563574534567, 8.618456912834581), (7.249200346731892, 8.513586707260227), (7.210366949394391, 8.411112684207989), (7.172053079311627, 8.310958600451912), (7.1342487382267965, 8.213051288814365), (7.096944151360821, 8.117320477592887), (7.06012982143935, 8.023698694678613), (7.023796477709125, 7.9321211257299336), (6.98793507809798, 7.842525425033883), (6.95253682732572, 7.754851728521137), (6.917593119286002, 7.669042391775722), (6.883095596163194, 7.585042013576893), (6.84903605586492, 7.502797261537635), (6.815406552781466, 7.42225679553526), (6.782199311075668, 7.343371155797666), (6.749406707155613, 7.26609277134539), (6.717021358185754, 7.190375715421114), (6.68503602582619, 7.116175812096162), (6.653443646871658, 7.043450428254403), (6.6222373393540614, 6.972158438658729), (6.591410333459605, 6.902260221353808), (6.5609560872227135, 6.833717533220607), (6.530868164638099, 6.76649341590255), (6.501140275393793, 6.700552275799206), (6.471766315271987, 6.635859677230215), (6.4427402505611315, 6.572382382974624), (6.414056265387728, 6.510088274501678), (6.385708605268885, 6.448946343919088)]
Results at px of 90
30 - 0 days from Mat at px 90,
Simple, Compounded: [(0.0, 0.0), (38.34399699420778, 163331394.74780124), (19.220514643214067, 18472.373753445343), (12.846036282009969, 891.4521293474448), (9.658808927576413, 194.48220789723712), (7.7464819983141275, 77.19090811928143), (6.471605261945843, 41.209326099979556), (5.560985814778549, 26.031809652524284), (4.878027143105639, 18.26314950225768), (4.346842344100015, 13.742880859775694), (3.9218992661669168, 10.864309569003993), (3.5742228882805422, 8.905214703582985), (3.2844965435632445, 7.502569565630651), (3.039347128396753, 6.45760116734708), (2.8292224831148602, 5.653875114759684), (2.6471176278139246, 5.019367213562171), (2.4877788696380074, 4.507478965913142), (2.3471886465836884, 4.086907526807911), (2.2222222166570584, 3.7359439897373763), (2.110412673283045, 3.4391153773988963), (2.0097864719733396, 3.1851286861770896), (1.9187460051361902, 2.9655687931282064), (1.8359841218193136, 2.7740494251916785), (1.7604210093676875, 2.605644597342208), (1.69115682889564, 2.4564992213613164), (1.62743569061313, 2.323556748651331), (1.5686180478284828, 2.204365034726947), (1.5141590400254477, 2.096935778647352), (1.4635916727566038, 1.9996410085098373), (1.4165133843439501, 1.9111358528545086)]
60 - 30 days from Mat at px 90,
Simple, Compounded: [(1.3725752519414538, 1.8303002722295503), (1.3314733950520075, 1.7561943936948987), (1.2929419053741622, 1.6880240437655245), (1.2567471333964035, 1.625113834629777), (1.2226828881904641, 1.5668859897627443), (1.1905665581526872, 1.5128434474549373), (1.1602358000089756, 1.4625563431798878), (1.1315458634364481, 1.4156511927691642), (1.1043671869304585, 1.3718019597395439), (1.0785835413083285, 1.3307228081527103), (1.0540902968098722, 1.2921621743304579), (1.0307930336998288, 1.2558977653385197), (1.0086063165161603, 1.2217325337554064), (0.9874526740008637, 1.189491117740306), (0.9672616668388727, 1.1590170470440833), (0.9479691187685241, 1.130170207496747), (0.9295164399298516, 1.102824838617277), (0.911850026736205, 1.076867708609766), (0.8949207254642579, 1.052196607825512), (0.8786834102632298, 1.028719048731669), (0.8630965710138429, 1.006351172463495), (0.84812194872504, 0.98501672695048), (0.8337242067077054, 0.964646249847683), (0.8198706960669762, 0.9451763320231238), (0.8046879108010615, 0.924143522945377), (0.8065311947041024, 0.9265489731092563), (0.7936776681264655, 0.9087110291185153), (0.7812840605076422, 0.8916136967523771), (0.7693261799691119, 0.8752120997736063), (0.7577814945093001, 0.8594648964127601)]
90 - 60 days from Mat at px 90,
Simple, Compounded: [(0.7466289924261929, 0.8443339469570911), (0.7358490583020797, 0.8297839853972464), (0.7254233701472381, 0.8157823888532607), (0.715334800129417, 0.802298928598682), (0.70556727355044, 0.7893055228430363), (0.6961057679583252, 0.7767760970202172), (0.6869361345226369, 0.7646863692176044), (0.6780451324770321, 0.753013726200899), (0.6694202591707504, 0.7417370737888086), (0.6610498066262818, 0.730836710269183), (0.6529226760547772, 0.7202941986706473), (0.6450284692834628, 0.7100923034158552), (0.6373573377505541, 0.7002148753467857), (0.6298999705911875, 0.690646736539258), (0.6226476044814022, 0.6813736746016205), (0.6155919208251714, 0.6723823057189026), (0.6087250561867952, 0.6636600631448019), (0.6020395577770952, 0.6551950936296024), (0.5955283437441112, 0.6469762344041526), (0.5891847394423724, 0.6389929679478252), (0.5830023712051153, 0.6312353418804705), (0.576975166344285, 0.6236939843776466), (0.5710974144860459, 0.6163600007840395), (0.5653636202348948, 0.6092250172304867), (0.559768603094506, 0.6022810559783215), (0.5437677605500459, 0.5825219914820909), (0.5386805298997641, 0.5762706105974913), (0.5337094770308735, 0.5701762663190686), (0.5288507069247964, 0.5642331087483337), (0.524100482800733, 0.5584356392141104)]
120 - 90 days from Mat at px 90,
Simple, Compounded: [(0.5194551962258578, 0.5527785673459293), (0.514911444599557, 0.5472568966236049), (0.5104659536691905, 0.5418658346040766), (0.5061155897152663, 0.5366008378441574), (0.5018573429507016, 0.5314575366309883), (0.4976883275208236, 0.5264317764557124), (0.49360579920799746, 0.5215196091858627), (0.4896071200223685, 0.5167172460306407), (0.4856897190167627, 0.5120210398362877), (0.48185118198440086, 0.5074275559046031), (0.47808916058661943, 0.5029334480605363), (0.4744013924066306, 0.49853556487996586), (0.47078573518421657, 0.4942308496222698), (0.46724008206841955, 0.49001639795172225), (0.4637624678453207, 0.485889395608592), (0.46035094500563145, 0.4818471807380438), (0.45700367170014566, 0.4778871684641123), (0.4537188614643336, 0.47400688512932776), (0.45049477754137524, 0.47020397875039593), (0.4473297916730166, 0.4664761449929476), (0.4442222933676352, 0.46282120119678977), (0.44117074043333526, 0.4592370405109645), (0.43817364757030014, 0.45572166231229305), (0.4343300078286887, 0.4513037551953078), (0.4352295912205418, 0.45227306597759726), (0.43233717468736177, 0.4488894279299975), (0.4294950681544543, 0.4455688891833543), (0.42670200344636444, 0.4423097500931978), (0.42395670214587455, 0.43911032871968747), (0.4212579659016652, 0.4359689785322428)]
150 - 120 days from Mat at px 90,
Simple, Compounded: [(0.41860464932544234, 0.4328841639742582), (0.41599560742834846, 0.4298543836182357), (0.41342978075716497, 0.42687816451385024), (0.41090607428834436, 0.4239541386584044), (0.40842349567477704, 0.4210809236549263), (0.40598105345718855, 0.41825721366832264), (0.4035777915855646, 0.4154817658262916), (0.4012127894191504, 0.4127533576672792), (0.39888513250349167, 0.41007079677236724), (0.3965939701620817, 0.4074329588500356), (0.39433845342695717, 0.4048387330315351), (0.392117779403472, 0.4022870532474756), (0.389931143539477, 0.39977687311589727), (0.3877777726580382, 0.39730723658678546), (0.38565694012570045, 0.3948771345818848), (0.38356791264698503, 0.3924856462034941), (0.3815099979116585, 0.3901318510678054), (0.37948248306214966, 0.3878148992669344), (0.37748474345104693, 0.3855339232740164), (0.3755161302434206, 0.38328807326681613), (0.37357601561872406, 0.38107658794624805), (0.3716637798238993, 0.37889867060396665), (0.3697788564018011, 0.37675357764551626), (0.3679206605880122, 0.37464054777181155), (0.3653656536053226, 0.3718108344798327), (0.3660886299307761, 0.3725589135920297), (0.3642822415943861, 0.3705079684702635), (0.36250094337108146, 0.3684870203766585), (0.3607442545833349, 0.36649546196868427), (0.35901166179687977, 0.3645326204704047)]
180 - 150 days from Mat at px 90,
Simple, Compounded: [(0.3573026692820787, 0.3625979293336631), (0.35561681671855455, 0.36069075119178295), (0.3539536437859297, 0.35881051949660775), (0.35231270786845675, 0.35695666769998075), (0.35069354864575863, 0.355128665152189), (0.3490957874043975, 0.3533259792467833), (0.34751896900715945, 0.35154806260778904), (0.345962703968305, 0.34979444169587093), (0.34442661645731015, 0.3480646087172148), (0.3429102923638582, 0.34635809689196323), (0.34141338361060625, 0.3446744400378525), (0.3399355073344946, 0.34301319150764975), (0.3384763365136887, 0.34137388458130363), (0.33703550666182047, 0.3397561240243674), (0.335612670083808, 0.3381594673862697), (0.3342075131771185, 0.3365835118391771), (0.33281972481733363, 0.3350278724498987), (0.3314489700391531, 0.3334921551479102), (0.33009495535380845, 0.331975983757329), (0.3287573682218956, 0.3304789864809274), (0.3274359323986769, 0.32900082693073757), (0.32613036181493765, 0.32754111560490135), (0.3248403628371, 0.32609955152471065), (0.3235656898680055, 0.32467576289293765), (0.3223060554526444, 0.32326946643550397), (0.3210612210622072, 0.32188030805981166), (0.3198309086259604, 0.3205080044917822), (0.31861488382604125, 0.3191522571607244), (0.31741289879763135, 0.3178127401592494), (0.3162247233805418, 0.31648919970283396)]
PDF: quantLibPlots.pdf
I did some digging myself. I believe it has do with how either the IRR objective function of newtonSafeSolver handles the corner case of being close to maturity and using the compounded
compounding convention.
Stack_trace:
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.
The problem here is that we need to get a discount factor of around 0.2 over a time as short as 10 days, or T = 0.0277. The discount formula for quarterly compounded rates, $B = 1 / \left(1 + y/4\right)^{4t}$, decreases too slowly as a function of the yield. Simple and continuous compounding decrease more steeply and get the target (the dotted red line) for more reasonable values — if you can call reasonable a yield of 5000% — but quarterly compounded just takes too long.
I'm not sure what we can do about this, or what kind of threshold we should add if we wanted to detect this and fall back on another calculation. I guess you can manually switch to SimpleThenCompounded as a workaround.
Hi! Hope you all are having a nice day:)
Summary
The bondYield function returns incorrectly large yields when using the
Compounded
interest rate convention near the maturity date for low-priced bonds.Example
Consider this bond which matures on
05-24-2021
and pays a semi-annual coupon of8.25
.Compounded interest is interacting with the solver in an outsized way when the price is low. The yield should be high for a bond trading at $16.25 and maturing in 2 weeks, but these values are way too high.
Validation
Estimating yield with this online calculator: https://dqydj.com/bond-yield-to-maturity-calculator/ We get a YTM of
3760.430
for 2 weeks from Maturity. Which is more in the ballpark given that we ~6X our money in 2 weeks (just considering the difference between clean_price and payment at maturity), so annualized, we’d have something like ~6*26 = 160x return. Not 3,414,330,317.53 for yield. For 1 week from Maturity, we get7506.667
for estimated yield which is roughly double of the previous number, which makes sense given that you get the same return over half the time span.Interestingly the website also utilizes a solver (the non-estimated value below) and the solver is getting outsized estimates similar to Quantlib For 2 weeks from Maturity: 3630247600369.387 from the compounded calc above: (Date(17,5,2021), 3414330317.5386267) For 1 week from Maturity: 6.58934881522009e+22 from the compounded calc above: (Date(17,5,2021), 4.742958503364403e+18)