eddelbuettel / rquantlib

R interface to the QuantLib library
119 stars 50 forks source link

matching australian bond asx pricing #121

Closed cedelkraut closed 5 years ago

cedelkraut commented 5 years ago

Hi,

I am trying to match the asx pricing with quantlib (https://www.asx.com.au/asx/research/bondCalculator.do). With the below code I get a dirty price of 118.46141 and accrued interest of 0.25278 but I would expect 118.47 and 0.259 (see attached screenshot). I included also pricing over jrvFinance which matched the asx calculator besides rounding.

I am using rquantlib 1.12.1.

Is there a setting I am missing?

Thanks

library(RQuantLib)
library(lubridate)
library(jrvFinance)

yield     <- 0.01369
coupon    <- 0.0325
maturity  <- as.Date('2029/04/21')
tradeDate <- as.Date('2018/11/15')

# price a fixed rate coupon bond
calc=list(dayCounter='ActualActual',
          compounding='Compounded',
          freq='Semiannual',
          durationType='Modified')
bonds <- list(settlementDays=2,
              issueDate=as.Date('2016/11/21'), #needs settlement period adjust
              faceAmount=100,
              accrualDayCounter='ActualActual',
              paymentConvention='Following')
schedule <- list(effectiveDate=as.Date('2016/11/15'),
                 maturityDate=as.Date('2029/04/21'),
                 period='Semiannual',
                 calendar='Australia',
                 businessDayConvention='Unadjusted',
                 terminationDateConvention='Unadjusted',
                 dateGeneration='Backward',
                 compounding='Compounded',
                 endOfMonth=0)
coupon.rate <- coupon
setEvaluationDate(tradeDate)

#Same bond calculated from yield rather than from the discount curve
bond_res <- FixedRateBond(bonds, coupon.rate, schedule, calc, yield=yield)
bond_res
summary(bond_res)

convention <- "ACT/ACT"

b_price <- bond.price(settle=bond_res$settlementDate, mature=maturity, coupon=coupon.rate, freq = 2,           yield = yield , convention , comp.freq = 2)
b_tcf <-   bond.TCF(settle=bond_res$settlementDate, mature=maturity, coupon=coupon.rate, freq = 2,
           convention)

b_tcf$accrued
b_price+b_tcf$accrued

asx calc

eddelbuettel commented 5 years ago

I get

R> summary(bond_res)
Detailed summary of valuation for FixedRateBond 
          NPV    cleanPrice    dirtyPrice accruedCoupon         yield 
          NaN     118.20864     118.46141       0.25278       0.01369 
with parameters
NULL
R> 

with the current QuantLib and RQuantLib which seems correct -- but I can't help you with details. You may have to try QuantLib for the issue -- RQuantLib just passes things through.

cedelkraut commented 5 years ago

I get the same result which is slightly off in terms of dirty price and significantly in terms of accruedcoupon, but could be that I have one of the parameters not set correctly. I have no native quantlib environment available but will try to ask in the quantlib project. thanks

eddelbuettel commented 5 years ago

Cool -- If you have a better usage example / different parameters for the daycount feel free to share here.

But yes, your use of QL 1.12.1 may be an issue. Coincidentally I could use help from Windows user building QL 1.14 for use at CRAN. If you have spare cycles.

cedelkraut commented 5 years ago

Hi, happy to help if i can. I have a couple examples attached with the calculations and sources. I am still struggling with the accrual setting though. I have run through all possible accrual settings in the below code but the accrued interest seems unaffected. Currently i am trying to replicate the calc with the r-excel plug in.

examples

accrual test.xlsx

library(RQuantLib)
library(lubridate)
library(jrvFinance)

yield     <- 0.01369
coupon    <- 0.0325
maturity  <- as.Date('2029/04/21')
tradeDate <- as.Date('2018/11/15')

comp <- c('Actual360', 'ActualFixed', 'ActualActual', 'Business252', 'OneDayCounter', 'SimpleDayCounter', 'Thirty360', 'Actual365NoLeap', 'ActualActual.ISMA', 'ActualActual.Bond','ActualActual.ISDA', 'ActualActual.Historical', 'ActualActual.AFB', 'ActualActual.Euro')

schedule <- list(effectiveDate=as.Date('2016/11/15'),
                 maturityDate=as.Date('2029/04/21'),
                 period='Semiannual',
                 calendar='Australia',
                 businessDayConvention='Unadjusted',
                 terminationDateConvention='Unadjusted',
                 dateGeneration='Backward',
                 compounding='Compounded',
                 endOfMonth=0)
coupon.rate <- coupon
setEvaluationDate(tradeDate)

res <- matrix(0,length(comp),2)

for (i in 1:length(comp)) {
# price a fixed rate coupon bond
calc=list(dayCounter= comp[i],
          compounding='Compounded',
          freq='Semiannual',
          durationType='Modified')
bonds <- list(settlementDays=2,
              issueDate=as.Date('2016/11/21'), #needs settlement period adjust
              faceAmount=100,
              accrualDayCounter=comp[i],
              paymentConvention='Following')
#Same bond calculated from yield rather than from the discount curve
bond_res <- FixedRateBond(bonds, coupon.rate, schedule, calc, yield=yield)
 res[i,1] <- bond_res$accruedCoupon
 res[i,2] <- bond_res$dirtyPrice
#summary(bond_res)
}

res
eddelbuettel commented 5 years ago

Here is what I get:

R> res
          [,1]    [,2]
 [1,] 0.252778 118.247
 [2,] 0.252778 118.450
 [3,] 0.252778 118.461
 [4,] 0.252778 118.509
 [5,] 0.252778 111.207
 [6,] 0.252778 118.457
 [7,] 0.252778 118.457
 [8,] 0.252778 118.456
 [9,] 0.252778 118.460
[10,] 0.252778 118.460
[11,] 0.252778 118.461
[12,] 0.252778 118.461
[13,] 0.252778 118.456
[14,] 0.252778 118.456
R> 

(BTW you can comment-out / remove library(lubridate) and library(jrvFinance) which are not used in that snippet.)

cedelkraut commented 5 years ago

it seems a bit odd that the change of the day count convention for the accrual does not change the accrued coupon. In the excel plugin it does. Any ideas?

eddelbuettel commented 5 years ago

I don't know. I don't do much FI anymore. There was another mistake I only saw when I did summary -- you had 2016 and 2018 mixed up. If I set both 2018-11-15 I get

R> res
           [,1]    [,2]
 [1,] 0.0361111 118.031
 [2,] 0.0361111 118.235
 [3,] 0.0361111 118.246
 [4,] 0.0361111 118.294
 [5,] 0.0361111 110.990
 [6,] 0.0361111 118.241
 [7,] 0.0361111 118.241
 [8,] 0.0361111 118.240
 [9,] 0.0361111 118.245
[10,] 0.0361111 118.245
[11,] 0.0361111 118.246
[12,] 0.0361111 118.246
[13,] 0.0361111 118.240
[14,] 0.0361111 118.240
R> 
cedelkraut commented 5 years ago

no that setting is correct. its there to have a full coupon in the first period.

cedelkraut commented 5 years ago

i have now replicated everything in the excel plug in there i get the right results.

i am using qlBondAccruedAmount to get the accrued amount and qlBondCleanPriceFromYield to get the price

examples

accrual test.xlsx

eddelbuettel commented 5 years ago

Good. But as I don't use Excel, and as this repo is not about Excel --- could you possibly translate that into a call to RQuantLib?