| 
					
	
	 
		
Hi
 
				I’m very new to Quantlib - about a week in (quite amazed so far!), but I have managed to get some bonds working in Python 2.7, using SWIG. QL v 1.9. 
I have set up a bond and the schedule is correct. When I calculate the clean price by inputting a yield (using BondFunctions.cleanPrice(…pass in yield)), this is correct (and yield from clean price), accrued is also correct and duration is fine
 as yield is not far out. 
However, when I attach a yield curve (flat forward) with the same yield, I get a fractionally different / price yield calc. Dates in the schedule are unadjusted, not modified following. 
Results: 
Clean Price Expected                     : 179.03 
Clean Price BondFunctions.cleanPrice()   : 179.03 
Clean Price bond.cleanPrice()            : 179.09 
Difference                               : 0.0626431535518 
Yield Expected                           : -0.0145461 
Yield BondFunctions.BondYield()          : -0.0145461 
Yield bond.bondYield()                   : -0.01455624 
Difference                               : 1.01382016107e-05 
Duration Expected                        : 34.52 
Duration BondFunctions.duration()        : 34.52 
Accrued Expected                         : 0.0483425414365 
Accrued BondFunctions.accruedAmount()    : 0.0483425414365 
Accrued bond.accruedAmount()             : 0.0483425414365 
Program ended with exit code: 0 
As you can see the calculated clean price from bond.cleanPrice() is 6 cents different (incorrect)..and it’s been driving me mad!! The
 yield is different from the 5th decimal place. 
This is a real bond and the input numbers have been verified using a manual calc in excel, they match the officially published numbers
 from the UK debt management office (negative yield 
 is the real yield for an inflation linked gilt, i.e. the quote of 179.03 is the market quote (clean) for the UKTI 52’s, before the index
 ratio is applied). 
In this example the price is the closing price for 30th Nov and settlement date is 1st Dec, 2016. 
If anyone can point out where I have gone wrong it would be much appreciated. 
Code is below. 
Many thanks  
Nick 
import QuantLib
as ql 
import datetime
as dt 
calendar = ql.UnitedKingdom() 
coupons=[0.0025] 
exCouponPeriod=ql.Period(6,ql.Days) 
calendarCoupon=ql.UnitedKingdom() 
faceValue=100 
businessConvention = ql.Unadjusted 
businessConventionCoupon=ql.Unadjusted 
today = ql.Date(30,11,2016) 
evaluationDate = calendar.adjust(today) 
issue_date = calendar.advance(evaluationDate,-1,
 ql.Years) 
maturity_date = ql.Date(22,3,2052) 
settlementDays=1 
settlementDate=today+1 
dayCount=ql.ActualActual(ql.ActualActual.ISMA) 
ql.Settings.instance().setEvaluationDate(evaluationDate) 
#input values to be checked 
inputYield=-0.014546100 
inputCleanPrice=179.03 
inputDuration=34.52 
inputAccrued=0.0483425414365 
#create schedule 
fixedSchedule = ql.Schedule(issue_date,maturity_date,ql.Period(ql.Semiannual),calendar,ql.Unadjusted,ql.Unadjusted,ql.DateGeneration.Backward,False) 
#create bond 
fixed_rate_bond = ql.FixedRateBond(settlementDays,faceValue,fixedSchedule,coupons,dayCount,businessConvention,100,issue_date,calendar,exCouponPeriod,calendarCoupon,businessConventionCoupon,False) 
#curve 
ts_curve=ql.FlatForward(evaluationDate, inputYield, dayCount, ql.Compounded, ql.Semiannual) 
#curve handle 
ts_handle = ql.YieldTermStructureHandle(ts_curve) 
#create bond engine 
bond_engine = ql.DiscountingBondEngine(ts_handle)#set bond engine 
#set pricing engine 
fixed_rate_bond.setPricingEngine(bond_engine) 
#calculate yield from clean price 
#calculations using BondFunctions 
bf_gry=ql.BondFunctions.bondYield(fixed_rate_bond,inputCleanPrice,dayCount,ql.Compounded,ql.Semiannual,settlementDate) 
bf_cp=ql.BondFunctions.cleanPrice(fixed_rate_bond,bf_gry,dayCount,ql.Compounded,ql.Semiannual,settlementDate) 
bf_ai=ql.BondFunctions.accruedAmount(fixed_rate_bond,settlementDate) 
bf_md=ql.BondFunctions.duration(fixed_rate_bond,bf_gry,dayCount,ql.Compounded,ql.Semiannual,ql.Duration.Modified,settlementDate) 
#Calculations using bond 
b_gry=fixed_rate_bond.bondYield(dayCount,ql.Compounded,ql.Semiannual) 
b_cp=fixed_rate_bond.cleanPrice() 
b_ai=fixed_rate_bond.accruedAmount() 
print
"Clean Price Expected                     :",inputCleanPrice 
print
"Clean Price BondFunctions.cleanPrice()   :",round(bf_cp,2) 
print
"Clean Price bond.cleanPrice()            :",round(b_cp,2) 
print
"Difference                               :",b_cp-bf_cp 
print
"" 
print
"Yield Expected                           :",round(inputYield,8) 
print
"Yield BondFunctions.BondYield()          :",round(bf_gry,8) 
print
"Yield bond.bondYield()                   :",round(b_gry,8) 
print
"Difference                               :",bf_gry-b_gry 
print
"" 
print
"Duration Expected                        :",inputDuration 
print
"Duration BondFunctions.duration()        :",round(bf_md,2) 
print
"Accrued Expected                         :", inputAccrued 
print
"Accrued BondFunctions.accruedAmount()    :", bf_ai 
print
"Accrued bond.accruedAmount()             :", b_ai 
------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/xeonphi _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| 
					
	
	 
		Hi Nick,
 
				I am not sure but it might have to do with the way your flat forward yield term structure and the yield-based bond functions measure the time between the settlement date and the cashflow payment dates effectively for the calculation of forward discount factors. The former does dayCounter(evalDate, cashflowDate) - dayCounter(evalDate, settlementDate) whereas the latter dayCounter(settlementDate, cashflowDate) which might be different in your case for one or several cashflows. I don't know the exact market convention for this but apparently the latter is matching in your case and the former is slightly wrong. You could check by replacing the day counter with another one for which the two expressions above are identical for all cashflow dates (of course the results get "wrong" then, but should be identical for the different methods then). Kind Regards Peter On 6 December 2016 at 19:39, Nick Pierce <[hidden email]> wrote: > Hi > > I’m very new to Quantlib - about a week in (quite amazed so far!), but I > have managed to get some bonds working in Python 2.7, using SWIG. QL v 1.9. > > I have set up a bond and the schedule is correct. When I calculate the clean > price by inputting a yield (using BondFunctions.cleanPrice(…pass in yield)), > this is correct (and yield from clean price), accrued is also correct and > duration is fine as yield is not far out. > > However, when I attach a yield curve (flat forward) with the same yield, I > get a fractionally different / price yield calc. Dates in the schedule are > unadjusted, not modified following. > > Results: > > Clean Price Expected : 179.03 > Clean Price BondFunctions.cleanPrice() : 179.03 > Clean Price bond.cleanPrice() : 179.09 > Difference : 0.0626431535518 > > Yield Expected : -0.0145461 > Yield BondFunctions.BondYield() : -0.0145461 > Yield bond.bondYield() : -0.01455624 > Difference : 1.01382016107e-05 > > Duration Expected : 34.52 > Duration BondFunctions.duration() : 34.52 > Accrued Expected : 0.0483425414365 > Accrued BondFunctions.accruedAmount() : 0.0483425414365 > Accrued bond.accruedAmount() : 0.0483425414365 > Program ended with exit code: 0 > > As you can see the calculated clean price from bond.cleanPrice() is 6 cents > different (incorrect)..and it’s been driving me mad!! The yield is different > from the 5th decimal place. > > This is a real bond and the input numbers have been verified using a manual > calc in excel, they match the officially published numbers from the UK debt > management office (negative yield > is the real yield for an inflation linked gilt, i.e. the quote of 179.03 is > the market quote (clean) for the UKTI 52’s, before the index ratio is > applied). > > In this example the price is the closing price for 30th Nov and settlement > date is 1st Dec, 2016. > > If anyone can point out where I have gone wrong it would be much > appreciated. > > Code is below. > > Many thanks > > Nick > > import QuantLib as ql > import datetime as dt > calendar = ql.UnitedKingdom() > coupons=[0.0025] > exCouponPeriod=ql.Period(6,ql.Days) > calendarCoupon=ql.UnitedKingdom() > faceValue=100 > businessConvention = ql.Unadjusted > businessConventionCoupon=ql.Unadjusted > > today = ql.Date(30,11,2016) > evaluationDate = calendar.adjust(today) > issue_date = calendar.advance(evaluationDate,-1, ql.Years) > maturity_date = ql.Date(22,3,2052) > > settlementDays=1 > settlementDate=today+1 > dayCount=ql.ActualActual(ql.ActualActual.ISMA) > > > ql.Settings.instance().setEvaluationDate(evaluationDate) > > #input values to be checked > inputYield=-0.014546100 > inputCleanPrice=179.03 > inputDuration=34.52 > inputAccrued=0.0483425414365 > > > #create schedule > fixedSchedule = > ql.Schedule(issue_date,maturity_date,ql.Period(ql.Semiannual),calendar,ql.Unadjusted,ql.Unadjusted,ql.DateGeneration.Backward,False) > > #create bond > fixed_rate_bond = > ql.FixedRateBond(settlementDays,faceValue,fixedSchedule,coupons,dayCount,businessConvention,100,issue_date,calendar,exCouponPeriod,calendarCoupon,businessConventionCoupon,False) > > #curve > ts_curve=ql.FlatForward(evaluationDate, inputYield, dayCount, ql.Compounded, > ql.Semiannual) > > #curve handle > ts_handle = ql.YieldTermStructureHandle(ts_curve) > > #create bond engine > bond_engine = ql.DiscountingBondEngine(ts_handle)#set bond engine > > #set pricing engine > fixed_rate_bond.setPricingEngine(bond_engine) > > #calculate yield from clean price > #calculations using BondFunctions > bf_gry=ql.BondFunctions.bondYield(fixed_rate_bond,inputCleanPrice,dayCount,ql.Compounded,ql.Semiannual,settlementDate) > bf_cp=ql.BondFunctions.cleanPrice(fixed_rate_bond,bf_gry,dayCount,ql.Compounded,ql.Semiannual,settlementDate) > bf_ai=ql.BondFunctions.accruedAmount(fixed_rate_bond,settlementDate) > bf_md=ql.BondFunctions.duration(fixed_rate_bond,bf_gry,dayCount,ql.Compounded,ql.Semiannual,ql.Duration.Modified,settlementDate) > > #Calculations using bond > b_gry=fixed_rate_bond.bondYield(dayCount,ql.Compounded,ql.Semiannual) > b_cp=fixed_rate_bond.cleanPrice() > b_ai=fixed_rate_bond.accruedAmount() > > print "Clean Price Expected :",inputCleanPrice > print "Clean Price BondFunctions.cleanPrice() :",round(bf_cp,2) > print "Clean Price bond.cleanPrice() :",round(b_cp,2) > print "Difference :",b_cp-bf_cp > print "" > print "Yield Expected :",round(inputYield,8) > print "Yield BondFunctions.BondYield() :",round(bf_gry,8) > print "Yield bond.bondYield() :",round(b_gry,8) > print "Difference :",bf_gry-b_gry > print "" > > print "Duration Expected :",inputDuration > print "Duration BondFunctions.duration() :",round(bf_md,2) > > print "Accrued Expected :", inputAccrued > print "Accrued BondFunctions.accruedAmount() :", bf_ai > print "Accrued bond.accruedAmount() :", b_ai > > ------------------------------------------------------------------------------ > Developer Access Program for Intel Xeon Phi Processors > Access to Intel Xeon Phi processor-based developer platforms. > With one year of Intel Parallel Studio XE. > Training and support from Colfax. > Order your platform today.http://sdm.link/xeonphi > _______________________________________________ > QuantLib-users mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/quantlib-users > ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/xeonphi _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| 
					
	
	 Hi Peter 
Thanks for the quick response, much appreciated. 
Yes I think you are correct… 
using 
dayCount=ql.ActualActual(ql.ActualActual.ISDA) 
Clean Price Expected                     : 167.05 
Clean Price BondFunctions.cleanPrice()   : 167.05 
Clean Price bond.cleanPrice()            : 167.06 
Difference                               : 0.00866617031875 
Yield Expected                           : 0.01835696 
Yield BondFunctions.BondYield()          : 0.01836077 
Yield bond.bondYield()                   : 0.01835696 
Difference                               : 3.81175596394e-06 
using 
dayCount=ql.Thirty360() 
Clean Price Expected                     : 167.05 
Clean Price BondFunctions.cleanPrice()   : 167.05 
Clean Price bond.cleanPrice()            : 167.06 
Difference                               : 0.00935696611168 
Yield Expected                           : 0.01835696 
Yield BondFunctions.BondYield()          : 0.01836097 
Yield bond.bondYield()                   : 0.01835696 
Difference                               : 4.01397533715e-06 
So in short the BondFunctions call is unaffected by the change in dayCounter and correct in all cases. 
However, the bond.cleanPrice() changes with the change in dayCounter and is ironically closer (less than 1 cent out) versus the original 6 cents. 
..so my next daft question is… 
Is there anyway to fix this and should they be consistent???  
Thanks again. 
Regards 
Nick 
 ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/xeonphi _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| 
					
	
	 I cannot test it right now, but the issue might be solved if instead of ts_curve=ql.FlatForward( you would use ts_curve=ql.FlatForward(settlementDate, inputYield, dayCount, ql.Compounded, ql.Semiannual) as the latter is the proper way to set the time origin in your case On Tue, Dec 6, 2016 at 9:17 PM, Nick Pierce <[hidden email]> wrote: 
 ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/xeonphi _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| 
					
	
	 Thanks Ferdinando 
I made the change as you suggested, but alas it didn’t solve the problem, so I took a different approach and ran the same bond set up with a number of day counts in the curve and bond, as opposed to just the curve (using settlementDate). 
The results are below (different bond, but generically the same problem): 
The bond.cleanPrice() and BondFunctions.cleanPrice() return the same value in every case except the ActualAcual.ISMA. 
I also changed the schedule generation and bond set up to be modified following instead of unadjusted, just in case it was a weekend problem, but it made no difference. 
Does this suggest there is a bug in the ISMA generation of a curve?? 
Any further help much appreciated. 
Thanks 
Nick 
The result we are expecting is 179.03 (round to 2 d.p), using ISMA. 
Actual/Actual (ISMA) day counter 
bond.cleanPrice()=           179.099809062 <<<<this is the
 wrong one 
BondFunctions.cleanPrice()=  179.029981553 <<<<correct when rounded to 2 decimal places 
Actual/Actual (ISDA) day counter 
bond.cleanPrice()=           179.028406531 
BondFunctions.cleanPrice()=  179.028406531 
Actual/365 (Fixed) day counter 
bond.cleanPrice()=           179.086145534 
BondFunctions.cleanPrice()=  179.086145534 
Actual/365 (NL) day counter 
bond.cleanPrice()=           179.023736844 
BondFunctions.cleanPrice()=  179.023736844 
30/360 (Bond Basis) day counter 
bond.cleanPrice()=           179.034435254 
BondFunctions.cleanPrice()=  179.034435254 
 ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/xeonphi _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| 
					
	
	 
		I didn’t test anything either, but I guess the difference comes ultimately from the telescopic construction of discount factors in Cashflows::npv(…, yield, …) which is different from the reference date based discount factor calculation in YieldTermStructure for day counters with non-additive year fractions, look into cashflows.cpp L834: 
				    Real CashFlows::npv(const Leg& leg,                         const InterestRate& y, ... ) { ... /*  !!! telescopic construction of discount factors !!! */             DiscountFactor b = y.discountFactor(lastDate, couponDate,                                                 refStartDate, refEndDate);             discount *= b;             lastDate = couponDate; ... 
 ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/xeonphi _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| 
					
	
	 I'm in the didn't-test crowd too, but I think it might be the same issue as <http://quant.stackexchange.com/questions/12707/pricing-a-fixedratebond-in-quantlib-yield-vs-termstructure>. There's a longer explanation there. Luigi On Mon, Dec 12, 2016 at 8:57 AM Peter Caspers <[hidden email]> wrote: 
 ------------------------------------------------------------------------------ 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 [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users  | 
			
| Free forum by Nabble | Edit this page | 
	
	
		