Discussion:
[Quantlib-users] YTC for all call dates given price
Prescott Nasser
2017-06-28 22:58:34 UTC
Permalink
Hey all -

I'm struggling with something I think should be pretty basic. I'm actually using QLNet (the dotnet port), so the code is C# below, but hopefully that doesn't slow anyone down. Given a price, I'm attempting to calculate the Yield for each call date (and add maturity date as the final call date)

I have the following GetFixedRateBond method (taken from the docs):

public static FixedRateBond GetFixedRateBond(double redemption, double coupon,
Date datedDate, Date maturityDate, Date settlementDate,
DayCounter dayCounter, Frequency frequency)
{

Settings.setEvaluationDate(new TARGET().adjust(settlementDate));

var schedule = new Schedule(
datedDate,
maturityDate,
new Period(frequency),
new UnitedStates(UnitedStates.Market.GovernmentBond),
BusinessDayConvention.Unadjusted,
BusinessDayConvention.Unadjusted,
DateGeneration.Rule.Forward,
false);

var bondHelper = new FixedRateBondHelper(
new RelinkableHandle<Quote>(),
0,
_bondFaceAmount,
schedule,
new List<double>() { coupon / 100.0 },
dayCounter,
BusinessDayConvention.Unadjusted,
redemption);

var curve = new PiecewiseYieldCurve<Discount, LogLinear>(
settlementDate,
new List<RateHelper>() { bondHelper },
dayCounter);

var termStructure = new RelinkableHandle<YieldTermStructure>(curve);
var engine = new DiscountingBondEngine(termStructure);

var fixedRateBond = bondHelper.fixedRateBond();
fixedRateBond.setPricingEngine(engine);

return fixedRateBond;
}

Given above, I loop through a collection of call events ( Date, Call Redemption):

var e = new List<CalcEvent>();
foreach (var callEvent in _callEvents)
{

var bond = GetFixedRateBond((double)callEvent.Price, Coupon, IssueDate,
callEvent.Date, SettlementDate, DayCounter, Frequency);


var transform = new CalcEvent
{
Date = callEvent.Date,
RedemptionPrice = callEvent.Price,
};

//Here price is the given price we contemplate buying the bond for.
transform.Yield = bond.yield(price, DayCounter, _compounding, Frequency, SettlementDate, _precision) * 100;
e.Add(transform);
}

From the list of all the call events, I take the last call event (maturity) and put that yield as YTM - which seems to work consistently well. The YTW however (selecting the call with the lowest yield), fails when compared to Bloomberg, off by .03 or so.

Give the following:
Cusip: 24880ACS9
Price: 100.652
Expected YTW: .803 ***@100
YTM: 4.792
SettlementDate: 2017-07-03

Maturity: 2027-09-01
Issue: 2008-06-25
DayCount: Thirty360
Frequency: SemiAnnually

Test Case:
YTW Expected 0.803, was 0.815686458817721, diff: 0.0126864588177211

I'm not really sure where to look at this point, any help would be appreciated

Thanks for your time,
~Prescott
Ali Hassani
2017-06-29 00:20:32 UTC
Permalink
Looked at this very quickly but I think the date generation rule should be
backward. Check the dates of the schedule they should pay every March 1st and
Sep 1st. Seems like you might be counting forward from the issue date.
Post by Prescott Nasser
Hey all -
I'm struggling with something I think should be pretty basic. I'm actually
using QLNet (the dotnet port), so the code is C# below, but hopefully that
doesn't slow anyone down. Given a price, I'm attempting to calculate the
Yield for each call date (and add maturity date as the final call date)
public static FixedRateBond GetFixedRateBond(double redemption, double
coupon, Date datedDate, Date maturityDate, Date settlementDate, DayCounter
dayCounter, Frequency frequency)
{
Settings.setEvaluationDate(new TARGET().adjust(settlementDate));
var schedule = new Schedule(
datedDate,
maturityDate,
new Period(frequency),
new UnitedStates(UnitedStates.Market.GovernmentBond),
BusinessDayConvention.Unadjusted,
BusinessDayConvention.Unadjusted,
DateGeneration.Rule.Forward,
false);
var bondHelper = new FixedRateBondHelper(
new RelinkableHandle<Quote>(),
0,
_bondFaceAmount,
schedule,
new List<double>() { coupon / 100.0 },
dayCounter,
BusinessDayConvention.Unadjusted,
redemption);
var curve = new PiecewiseYieldCurve<Discount, LogLinear>(
settlementDate,
new List<RateHelper>() { bondHelper },
dayCounter);
var termStructure = new
RelinkableHandle<YieldTermStructure>(curve); var engine = new
DiscountingBondEngine(termStructure);
var fixedRateBond = bondHelper.fixedRateBond();
fixedRateBond.setPricingEngine(engine);
return fixedRateBond;
}
var e = new List<CalcEvent>();
foreach (var callEvent in _callEvents)
{
var bond = GetFixedRateBond((double)callEvent.Price, Coupon,
IssueDate, callEvent.Date, SettlementDate, DayCounter, Frequency);
var transform = new CalcEvent
{
Date = callEvent.Date,
RedemptionPrice = callEvent.Price,
};
//Here price is the given price we contemplate buying the
bond for. transform.Yield = bond.yield(price, DayCounter, _compounding,
Frequency, SettlementDate, _precision) * 100; e.Add(transform);
}
From the list of all the call events, I take the last call event (maturity)
and put that yield as YTM - which seems to work consistently well. The YTW
however (selecting the call with the lowest yield), fails when compared to
Bloomberg, off by .03 or so.
Cusip: 24880ACS9
Price: 100.652
YTM: 4.792
SettlementDate: 2017-07-03
Maturity: 2027-09-01
Issue: 2008-06-25
DayCount: Thirty360
Frequency: SemiAnnually
YTW Expected 0.803, was 0.815686458817721, diff: 0.0126864588177211
I'm not really sure where to look at this point, any help would be appreciated
Thanks for your time,
~Prescott
Prescott Nasser
2017-06-29 08:25:27 UTC
Permalink
Well - well done. That seemed to fix it. Do you mind explaining a little bit more what was going on with that? I don't quite understand what that means backwards vs forwards - or when I'd never toggle between them.

Thanks very much for you help!

-----Original Message-----
From: ***@hassani.global [mailto:***@hassani.global]
Sent: Wednesday, June 28, 2017 5:21 PM
To: quantlib-***@lists.sourceforge.net
Cc: Prescott Nasser <***@hotmail.com>
Subject: Re: [Quantlib-users] YTC for all call dates given price

Looked at this very quickly but I think the date generation rule should be backward. Check the dates of the schedule they should pay every March 1st and Sep 1st. Seems like you might be counting forward from the issue date.
Post by Prescott Nasser
Hey all -
I'm struggling with something I think should be pretty basic. I'm
actually using QLNet (the dotnet port), so the code is C# below, but
hopefully that doesn't slow anyone down. Given a price, I'm attempting
to calculate the Yield for each call date (and add maturity date as
the final call date)
public static FixedRateBond GetFixedRateBond(double redemption, double
coupon, Date datedDate, Date maturityDate, Date settlementDate,
DayCounter dayCounter, Frequency frequency)
{
Settings.setEvaluationDate(new
TARGET().adjust(settlementDate));
var schedule = new Schedule(
datedDate,
maturityDate,
new Period(frequency),
new UnitedStates(UnitedStates.Market.GovernmentBond),
BusinessDayConvention.Unadjusted,
BusinessDayConvention.Unadjusted,
DateGeneration.Rule.Forward,
false);
var bondHelper = new FixedRateBondHelper(
new RelinkableHandle<Quote>(),
0,
_bondFaceAmount,
schedule,
new List<double>() { coupon / 100.0 },
dayCounter,
BusinessDayConvention.Unadjusted,
redemption);
var curve = new PiecewiseYieldCurve<Discount, LogLinear>(
settlementDate,
new List<RateHelper>() { bondHelper },
dayCounter);
var termStructure = new
RelinkableHandle<YieldTermStructure>(curve); var engine = new
DiscountingBondEngine(termStructure);
var fixedRateBond = bondHelper.fixedRateBond();
fixedRateBond.setPricingEngine(engine);
return fixedRateBond;
}
var e = new List<CalcEvent>();
foreach (var callEvent in _callEvents)
{
var bond = GetFixedRateBond((double)callEvent.Price,
Coupon, IssueDate, callEvent.Date, SettlementDate, DayCounter,
Frequency);
var transform = new CalcEvent
{
Date = callEvent.Date,
RedemptionPrice = callEvent.Price,
};
//Here price is the given price we contemplate buying
the bond for. transform.Yield = bond.yield(price, DayCounter,
_compounding, Frequency, SettlementDate, _precision) * 100; e.Add(transform);
}
From the list of all the call events, I take the last call event
(maturity) and put that yield as YTM - which seems to work
consistently well. The YTW however (selecting the call with the lowest
yield), fails when compared to Bloomberg, off by .03 or so.
Cusip: 24880ACS9
Price: 100.652
YTM: 4.792
SettlementDate: 2017-07-03
Maturity: 2027-09-01
Issue: 2008-06-25
DayCount: Thirty360
Frequency: SemiAnnually
YTW Expected 0.803, was 0.815686458817721, diff: 0.0126864588177211
I'm not really sure where to look at this point, any help would be appreciated
Thanks for your time,
~Prescott
Luigi Ballabio
2017-06-30 09:27:29 UTC
Permalink
You had the issue date set as 2008-06-25 and the maturity set as 2027-09-01.
If you pass those to a Schedule constructor and tell it to generate dates
semiannually and forward, you'll get dates six months apart starting from
the issue date and going forward, so 2008-12-25, 2009-06-25 and so on until
2027-06-25, plus a short coupon from there to maturity. If you generate
dates backwards instead, the schedule starts from the maturity and goes
back by six months each time, so you get 2027-03-01, 2026-09-01, 2026-03-01
and so on until 2008-09-01 plus a short first coupon.

Luigi
Post by Prescott Nasser
Well - well done. That seemed to fix it. Do you mind explaining a little
bit more what was going on with that? I don't quite understand what that
means backwards vs forwards - or when I'd never toggle between them.
Thanks very much for you help!
-----Original Message-----
Sent: Wednesday, June 28, 2017 5:21 PM
Subject: Re: [Quantlib-users] YTC for all call dates given price
Looked at this very quickly but I think the date generation rule should be
backward. Check the dates of the schedule they should pay every March 1st
and Sep 1st. Seems like you might be counting forward from the issue date.
Post by Prescott Nasser
Hey all -
I'm struggling with something I think should be pretty basic. I'm
actually using QLNet (the dotnet port), so the code is C# below, but
hopefully that doesn't slow anyone down. Given a price, I'm attempting
to calculate the Yield for each call date (and add maturity date as
the final call date)
public static FixedRateBond GetFixedRateBond(double redemption, double
coupon, Date datedDate, Date maturityDate, Date settlementDate,
DayCounter dayCounter, Frequency frequency)
{
Settings.setEvaluationDate(new
TARGET().adjust(settlementDate));
var schedule = new Schedule(
datedDate,
maturityDate,
new Period(frequency),
new UnitedStates(UnitedStates.Market.GovernmentBond),
BusinessDayConvention.Unadjusted,
BusinessDayConvention.Unadjusted,
DateGeneration.Rule.Forward,
false);
var bondHelper = new FixedRateBondHelper(
new RelinkableHandle<Quote>(),
0,
_bondFaceAmount,
schedule,
new List<double>() { coupon / 100.0 },
dayCounter,
BusinessDayConvention.Unadjusted,
redemption);
var curve = new PiecewiseYieldCurve<Discount, LogLinear>(
settlementDate,
new List<RateHelper>() { bondHelper },
dayCounter);
var termStructure = new
RelinkableHandle<YieldTermStructure>(curve); var engine = new
DiscountingBondEngine(termStructure);
var fixedRateBond = bondHelper.fixedRateBond();
fixedRateBond.setPricingEngine(engine);
return fixedRateBond;
}
var e = new List<CalcEvent>();
foreach (var callEvent in _callEvents)
{
var bond = GetFixedRateBond((double)callEvent.Price,
Coupon, IssueDate, callEvent.Date, SettlementDate, DayCounter,
Frequency);
var transform = new CalcEvent
{
Date = callEvent.Date,
RedemptionPrice = callEvent.Price,
};
//Here price is the given price we contemplate buying
the bond for. transform.Yield = bond.yield(price, DayCounter,
_compounding, Frequency, SettlementDate, _precision) * 100;
e.Add(transform);
Post by Prescott Nasser
}
From the list of all the call events, I take the last call event
(maturity) and put that yield as YTM - which seems to work
consistently well. The YTW however (selecting the call with the lowest
yield), fails when compared to Bloomberg, off by .03 or so.
Cusip: 24880ACS9
Price: 100.652
YTM: 4.792
SettlementDate: 2017-07-03
Maturity: 2027-09-01
Issue: 2008-06-25
DayCount: Thirty360
Frequency: SemiAnnually
YTW Expected 0.803, was 0.815686458817721, diff: 0.0126864588177211
I'm not really sure where to look at this point, any help would be appreciated
Thanks for your time,
~Prescott
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
QuantLib-users mailing list
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Loading...