Select Cheapest-to-Deliver Bond Using BondFuture
Instrument
This example shows how to select the cheapest-to-deliver (CTD) bond for Treasury bond future contracts using a BondFuture
instrument. It demonstrates two workflows for selecting the CTD bond:
When a Treasury bond future contract matures, the party that is in the short position of the contract can deliver the underlying bond to the party that is in the long position of the contract. Typically, there can be many different bonds that satisfy the terms of the contract during the delivery month. For example, you can meet the delivery obligation for a 30-year US Treasury bond future contract with any US Treasury bond that has at least 15 years to maturity at the time of delivery. Furthermore, these deliverable bonds can have different coupons and maturities. Since the party in the short position has the option to choose which bond to deliver from these deliverable bonds, it is in the interest of that party to select the CTD bond that minimizes the delivery cost. You can select the CTD bond at the time of delivery during the delivery month of the future contract using the current market prices. Alternatively, you can predict the CTD bond several months before the delivery month based on the current zero curve.
Select CTD Bond at Time of Delivery
In this workflow, you determine the delivery cost by comparing the invoice price that the short position receives from the long position against the price of the deliverable bond. For a particular deliverable bond, the invoice price that the short position receives from the long position is:
InvoicePrice = (QuotedFuturePrice x ConversionFactor + AccruedInterest)/BondPrincipal x FutureNotional
For example, in the 30-year US Treasury bond futures market, typically, BondPrincipal
is $100 and FutureNotional
is $100,000. In return, the short position delivers the bond to the long position by buying the deliverable bond that has the following purchase cost in the market:
PurchaseCost = (SpotPrice + AccruedInterest)/BondPrincipal x FutureNotional
Here, SpotPrice
is the clean market price of the bond at the time of delivery. From this purchase cost, subtracting the invoice amount to be received by the short position from the long position gives the following formula for the overall delivery cost:
OverallDeliveryCost = (SpotPrice - QuotedFuturePrice x ConversionFactor)/BondPrincipal x FutureNotional
You can compute the delivery cost for every deliverable bond and determine the CTD bond by selecting the bond with the lowest delivery cost. The OverallDeliveryCost
formula applies only at the time of delivery. This method is equivalent to using the cashsettle
method of the BondFuture
instrument at the time of delivery. To demonstrate this workflow, the following example uses fictitious data, and selects the CTD bond using the BondFuture
instrument on the delivery day of a hypothetical 30-year US Treasury bond future contract maturing in December 2021.
% Create a zero curve. Settle = datetime(2021,12,21); ZeroDates = Settle + [calmonths([1 2 3 6]) calyears([1 2 3 5 7 10 20 30])]'; ZeroRates = [0.06 0.04 0.06 0.07 0.21 0.60 0.95 1.34 1.60 1.69 2.15 2.05]'./100; ZeroCurve = ratecurve("zero",Settle,ZeroDates,ZeroRates,Compounding=2); % Define the data for the deliverable bonds. ReferenceDate = datetime(2021,12,1); BondMaturity = datetime(datevec(["2/15/2045","2/15/2037","8/15/2040",... "5/15/2041","5/15/2037","2/15/2042","11/15/2043","11/15/2044",... "5/15/2038","2/15/2041"],'mm/dd/yyyy')); CouponRate = [2.5 4.75 3.875 2.25 5.0 3.125 3.75 3.0 4.5 4.75]'/100; IssueDate = datetime(datevec(["2/17/2015","2/15/2007","8/16/2010",... "6/1/2021","8/15/2007","2/15/2012","11/15/2013","11/17/2014",... "8/15/2008","2/15/2011"],'mm/dd/yyyy')); SpotPrice = [109.06;140.78;130.60;104.04;144.02;119.03;131.05;118.23;138.08;145.25]; NumBonds = length(BondMaturity); BondID = (1:NumBonds)'; % Use convfactor to compute the conversion factors. ConversionFactor = convfactor(ReferenceDate,BondMaturity,CouponRate)
ConversionFactor = 10×1
0.5664
0.8775
0.7645
0.5752
0.9009
0.6677
0.7286
0.6302
0.8456
0.8594
% Create a vector of FixedBond instruments. BondPrincipal = 100; DeliverableBonds = fininstrument("FixedBond",Maturity=BondMaturity,... CouponRate=CouponRate,IssueDate=IssueDate,Principal=BondPrincipal)
DeliverableBonds=10×1 FixedBond array with properties:
CouponRate
Period
Basis
EndMonthRule
Principal
DaycountAdjustedCashFlow
BusinessDayConvention
Holidays
IssueDate
FirstCouponDate
LastCouponDate
StartDate
Maturity
Name
% Create a vector of BondFuture instruments. FutureMaturity = datetime(2021,12,21); QuotedFuturePrice = 159.53; FutureNotional = 100000; BondFutureContracts = fininstrument("BondFuture",Maturity=FutureMaturity,... QuotedPrice=QuotedFuturePrice,Bond=DeliverableBonds,... ConversionFactor=ConversionFactor,Notional=FutureNotional)
BondFutureContracts=10×1 BondFuture array with properties:
Maturity
QuotedPrice
Bond
ConversionFactor
Notional
Name
To compute the delivery cost, use the cashsettle
method of the BondFuture
instrument to compute the delivery cost because this method estimates the undiscounted net cash settlement amount that could be paid by the short position to the long position at future maturity instead of physical delivery.
% Use the cashsettle method to compute the delivery costs. DeliveryCost = nan(NumBonds,1); for k=1:NumBonds outCS = cashsettle(BondFutureContracts(k), SpotPrice(k), ZeroCurve); DeliveryCost(k) = outCS.CashSettleAmount; end % List the deliverable bonds and delivery costs in a table. DeliverableBondTable = table(BondID, BondMaturity, IssueDate, ... CouponRate, SpotPrice, ConversionFactor, DeliveryCost)
DeliverableBondTable=10×7 table
BondID BondMaturity IssueDate CouponRate SpotPrice ConversionFactor DeliveryCost
______ ____________ ___________ __________ _________ ________________ ____________
1 15-Feb-2045 17-Feb-2015 0.025 109.06 0.56643 18697
2 15-Feb-2037 15-Feb-2007 0.0475 140.78 0.8775 792.87
3 15-Aug-2040 16-Aug-2010 0.03875 130.6 0.76447 8643.6
4 15-May-2041 01-Jun-2021 0.0225 104.04 0.57524 12272
5 15-May-2037 15-Aug-2007 0.05 144.02 0.9009 299.73
6 15-Feb-2042 15-Feb-2012 0.03125 119.03 0.66773 12508
7 15-Nov-2043 15-Nov-2013 0.0375 131.05 0.72859 14818
8 15-Nov-2044 17-Nov-2014 0.03 118.23 0.63022 17690
9 15-May-2038 15-Aug-2008 0.045 138.08 0.84558 3185.1
10 15-Feb-2041 15-Feb-2011 0.0475 145.25 0.85942 8146.4
Once you have computed the delivery costs for all of the deliverable bonds, you can determine the CTD bond by selecting the bond with the lowest delivery cost.
% Determine the CTD bond with the lowest delivery cost.
[~,CTDBondIdx] = min(DeliverableBondTable.DeliveryCost);
CTDBondTableDecember2021 = DeliverableBondTable(CTDBondIdx,:)
CTDBondTableDecember2021=1×7 table
BondID BondMaturity IssueDate CouponRate SpotPrice ConversionFactor DeliveryCost
______ ____________ ___________ __________ _________ ________________ ____________
5 15-May-2037 15-Aug-2007 0.05 144.02 0.9009 299.73
BondFutureContracts(CTDBondIdx)
ans = BondFuture with properties: Maturity: 21-Dec-2021 QuotedPrice: 159.5300 Bond: [1x1 fininstrument.FixedBond] ConversionFactor: 0.9009 Notional: 100000 Name: ""
Among the ten deliverable bonds, the CTD bond with the lowest delivery cost for the December 2021 future contract is the bond with a 5% coupon rate maturing on May 15, 2037. This CTD bond is determined at the time of delivery on December 21, 2021.
Since the delivery costs in this example are computed at the time of delivery, the delivery costs computed by the cashsettle
method of the BondFuture
instrument for this future contract are in agreement with those computed using the following formula for the overall delivery cost at delivery:
OverallDeliveryCost = (SpotPrice - QuotedFuturePrice x ConversionFactor)/BondPrincipal x FutureNotional
% Compare calculated delivery cost using cashsettle with the delivery cost formula. DeliveryCostFormula = ... (SpotPrice - QuotedFuturePrice.*ConversionFactor)/BondPrincipal*FutureNotional; table(DeliveryCostFormula, DeliveryCost)
ans=10×2 table
DeliveryCostFormula DeliveryCost
___________________ ____________
18697 18697
792.87 792.87
8643.6 8643.6
12272 12272
299.73 299.73
12508 12508
14818 14818
17690 17690
3185.1 3185.1
8146.4 8146.4
Select CTD Bond Months Before Delivery Month
The previous overall delivery cost formula applies only at the time of delivery. However, if a current zero curve is available, you can still compute the estimated delivery cost using the cashsettle
method of the BondFuture
instrument, even when it is several months before the delivery month. In the following example, you select the CTD bond using the BondFuture
instrument in November 2021 for a hypothetical 30-year US Treasury bond future contract maturing several months later in June 2022. The overall workflow is similar to the workflow in Select CTD Bond at Time of Delivery, except that you select the CTD bond several months before the delivery month and the overall delivery cost formula no longer applies.
% Create a zero curve. Settle = datetime(2021,11,22); ZeroDates = Settle + [calmonths([1 2 3 6]) calyears([1 2 3 5 7 10 20 30])]'; ZeroRates = [0.07 0.04 0.05 0.07 0.20 0.63 0.95 1.34 1.57 1.65 2.09 2.01]'./100; ZeroCurve = ratecurve("zero",Settle,ZeroDates,ZeroRates,Compounding=2); % Define the data for the deliverable bonds. ReferenceDate = datetime(2022,6,1); BondMaturity = datetime(datevec(["11/15/2046","2/15/2038","11/15/2040",... "11/15/2041","5/15/2044","5/15/2042","5/15/2045","8/15/2041",... "8/15/2043","8/15/2039"],'mm/dd/yyyy')); CouponRate = [2.875 4.375 4.25 3.125 3.375 3.0 3.0 1.75 3.625 4.5]'/100; IssueDate = datetime(datevec(["11/15/2016","2/15/2008","11/15/2010",... " 11/15/2011","5/15/2014","5/15/2012","5/15/2015","8/31/2021",... "8/15/2013","8/17/2009"],'mm/dd/yyyy')); SpotPrice = [117.84;137.13;137.53;119.17;125.03;117.34;119.03;95.97;128.84;140.56]; NumBonds = length(BondMaturity); BondID = 10+(1:NumBonds)'; % Use convfactor to compute the conversion factors. ConversionFactor = convfactor(ReferenceDate,BondMaturity,CouponRate)
ConversionFactor = 10×1
0.6033
0.8375
0.8074
0.6743
0.6834
0.6555
0.6302
0.5220
0.7185
0.8415
% Create a vector of FixedBond instruments. BondPrincipal = 100; DeliverableBonds = fininstrument("FixedBond",Maturity=BondMaturity, ... CouponRate=CouponRate,IssueDate=IssueDate,Principal=BondPrincipal)
DeliverableBonds=10×1 FixedBond array with properties:
CouponRate
Period
Basis
EndMonthRule
Principal
DaycountAdjustedCashFlow
BusinessDayConvention
Holidays
IssueDate
FirstCouponDate
LastCouponDate
StartDate
Maturity
Name
% Create a vector of BondFuture instruments. FutureMaturity = datetime(2022,6,21); QuotedFuturePrice = 160.31; FutureNotional = 100000; BondFutureContracts = fininstrument("BondFuture",Maturity=FutureMaturity, ... QuotedPrice=QuotedFuturePrice,Bond=DeliverableBonds, ... ConversionFactor=ConversionFactor,Notional=FutureNotional)
BondFutureContracts=10×1 BondFuture array with properties:
Maturity
QuotedPrice
Bond
ConversionFactor
Notional
Name
% Use the cashsettle method to compute the delivery costs. DeliveryCost = nan(NumBonds,1); for k=1:NumBonds outCS = cashsettle(BondFutureContracts(k), SpotPrice(k), ZeroCurve); DeliveryCost(k) = outCS.CashSettleAmount; end % List the deliverable bonds and delivery costs in a table. DeliverableBondTable = table(BondID, BondMaturity, IssueDate, ... CouponRate, SpotPrice, ConversionFactor, DeliveryCost)
DeliverableBondTable=10×7 table
BondID BondMaturity IssueDate CouponRate SpotPrice ConversionFactor DeliveryCost
______ ____________ ___________ __________ _________ ________________ ____________
11 15-Nov-2046 15-Nov-2016 0.02875 117.84 0.60331 19515
12 15-Feb-2038 15-Feb-2008 0.04375 137.13 0.8375 409.62
13 15-Nov-2040 15-Nov-2010 0.0425 137.53 0.80741 5695.6
14 15-Nov-2041 15-Nov-2011 0.03125 119.17 0.67433 9314.9
15 15-May-2044 15-May-2014 0.03375 125.03 0.68337 13582
16 15-May-2042 15-May-2012 0.03 117.34 0.65551 10574
17 15-May-2045 15-May-2015 0.03 119.03 0.63022 16318
18 15-Aug-2041 31-Aug-2021 0.0175 95.97 0.52204 11320
19 15-Aug-2043 15-Aug-2013 0.03625 128.84 0.71855 11618
20 15-Aug-2039 17-Aug-2009 0.045 140.56 0.84151 3125.4
% Determine the CTD bond with the lowest delivery cost.
[~,CTDBondIdx] = min(DeliverableBondTable.DeliveryCost);
CTDBondTableJune2022 = DeliverableBondTable(CTDBondIdx,:)
CTDBondTableJune2022=1×7 table
BondID BondMaturity IssueDate CouponRate SpotPrice ConversionFactor DeliveryCost
______ ____________ ___________ __________ _________ ________________ ____________
12 15-Feb-2038 15-Feb-2008 0.04375 137.13 0.8375 409.62
BondFutureContracts(CTDBondIdx)
ans = BondFuture with properties: Maturity: 21-Jun-2022 QuotedPrice: 160.3100 Bond: [1x1 fininstrument.FixedBond] ConversionFactor: 0.8375 Notional: 100000 Name: ""
Among the ten deliverable bonds, the CTD bond with the lowest delivery cost for the June 2022 future contract is the bond with a 4.375% coupon rate maturing on February 15, 2038. This CTD bond is predicted using the zero curve available on November 22, 2021, which is several months before the delivery month in June 2022.
See Also
Functions
finmodel
|finpricer
|convfactor
|BondFuture
|ratecurve
|cashsettle