On 11 Dec 2016, at 21:34, Nick Pierce <[hidden email]> wrote: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 counterbond.cleanPrice()= 179.099809062 <<<<this is the wrong oneBondFunctions.cleanPrice()= 179.029981553 <<<<correct when rounded to 2 decimal placesActual/Actual (ISDA) day counterbond.cleanPrice()= 179.028406531BondFunctions.cleanPrice()= 179.028406531Actual/365 (Fixed) day counterbond.cleanPrice()= 179.086145534BondFunctions.cleanPrice()= 179.086145534Actual/365 (NL) day counterbond.cleanPrice()= 179.023736844BondFunctions.cleanPrice()= 179.02373684430/360 (Bond Basis) day counterbond.cleanPrice()= 179.034435254BondFunctions.cleanPrice()= 179.034435254
On 9 Dec 2016, at 07:20, Ferdinando M. Ametrano <[hidden email]> wrote:
I cannot test it right now, but the issue might be solved if instead ofts_curve=ql.FlatForward(evaluationDate, inputYield, dayCount, ql.Compounded, ql.Semiannual)
you would usets_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:
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.05Clean Price BondFunctions.cleanPrice() : 167.05Clean Price bond.cleanPrice() : 167.06Difference : 0.00866617031875
Yield Expected : 0.01835696Yield BondFunctions.BondYield() : 0.01836077Yield bond.bondYield() : 0.01835696Difference : 3.81175596394e-06
using
dayCount=ql.Thirty360()Clean Price Expected : 167.05Clean Price BondFunctions.cleanPrice() : 167.05Clean Price bond.cleanPrice() : 167.06Difference : 0.00935696611168
Yield Expected : 0.01835696Yield BondFunctions.BondYield() : 0.01836097Yield bond.bondYield() : 0.01835696Difference : 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
On 6 Dec 2016, at 19:55, Peter Caspers <[hidden email]> wrote:
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
Free forum by Nabble | Disable Popup Ads | Edit this page |