What’re the returns (XIRR) for my CPFIS Portfolio?
Every employee in Singapore is bounded by the same set of CPF rules.
As an ex-economist/ data geek who doesn’t shy away from having skin in the game. I asked myself this question back in 2015 when I was still a starry-eyed young man 2 years into the workforce - how do I set out to optimize my returns in my CPF OA with these given set of constraints,
- You cannot withdraw your CPF OA till you are 55 years old
- You can only invest CPF OA beyond 20k
- And of this delta, you can only invest 35% in non ETFs instruments OR 100% of it in ETFs
- CPF OA returns of 2.5% per annum
The last point is something that I wish to highlight. If I choose to invest, I would have to overcome the 2.5% hurdle rate from CPF OA.
Subscribing to Vanguard’s philosophy, a pioneeer & leader in the space of index funds - (https://personal.vanguard.com/pdf/s315.pdf) at least for my CPFIS portion, they advocate that lump sum investing proves to be superior than spacing out your investments (dollar cost averaging).
Since then - whenever I have 5-6k in my CPF OA beyond the 20k, I promptly allocated it to the market. In some periods, I invested with smaller amounts when POEMS brokerage offered some promotions on commission fees.
How did this strategy fare thus far?
XIRR- a metric used in assessing rate of returns with a given set of cashflows - came up to be around 5.7%! Note: This figure here accounts for the dividends received over the years.
Hurray! It’s more than twice the 2.5% hurdle rate in CPF OA. And even the 4% rate from SA. One could voluntarily transfer OA to SA, but you will lose the flexibility of using the OA for serving mortage in future
My thoughts
This is still an ongoing experiment in my ‘lab’. Apparently it seems to be working well! Going forward, I will continue this strategy.
If you are keen in the technicalities of computing XIRR (applied the function developed by someone else here –>#https://github.com/SunilVeeravalli/xirr)…
suppressMessages(source("./CPFOA/F_xirr.R"))
suppressMessages(source("./CPFOA/another_irr_eg.R"))
suppressPackageStartupMessages(library(tvm))
#Reading my dataset
cpf_contrib <- read_csv(file = "./CPFOA/jr_cpfis_contrib.csv", col_names = TRUE)
## Parsed with column specification:
## cols(
## Date = col_character(),
## num_stocks_cpf_port = col_double(),
## sti_px = col_double(),
## cpf_oa_port_val = col_double(),
## Dividends_per_share = col_double()
## )
#Formattting date
cpf_contrib$Date = as.Date(cpf_contrib$Date, format = "%m/%d/%y")
names(cpf_contrib)[which(names(cpf_contrib) == "Date")] = "dates"
#including ss
cpf_contrib$net_stocks_purchase = lead(cpf_contrib$num_stocks_cpf_port - lag(cpf_contrib$num_stocks_cpf_port))
#Contributions
cpf_contrib$stock_amt_purchase = cpf_contrib$net_stocks_purchase * cpf_contrib$sti_px
#Dividends amount
cpf_contrib$dividends = cpf_contrib$num_stocks_cpf_port * cpf_contrib$Dividends_per_share
cpf_contrib$dividends = ifelse(is.na(cpf_contrib$dividends), 0, cpf_contrib$dividends)
#Net cashflow
cpf_contrib = cpf_contrib %>%
mutate(net_cash_flow = dividends - stock_amt_purchase)
#Setting final cashflow
cpf_contrib$net_cash_flow[nrow(cpf_contrib)] = cpf_contrib$cpf_oa_port_val[nrow(cpf_contrib)]
#Computing the xirr
xirr(cpf_contrib[, c("dates","net_cash_flow")])
## [1] "XIRR is 5.775%"
print(xirr2(cpf_contrib$net_cash_flow, cpf_contrib$dates))
## [1] 0.05777714
Final dataset on dividends, purchases, cashflows, portfolio values
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(kableExtra))
kable(cpf_contrib, caption = "Final data-frame of dividends, purchase, cashflows, portfolio values")
dates | num_stocks_cpf_port | sti_px | cpf_oa_port_val | Dividends_per_share | net_stocks_purchase | stock_amt_purchase | dividends | net_cash_flow |
---|---|---|---|---|---|---|---|---|
2015-05-01 | 0 | 3.350 | 0 | NA | 1800 | 6030.0 | 0.0 | -6030.0 |
2015-06-01 | 1800 | 3.240 | 5562 | NA | 1000 | 3240.0 | 0.0 | -3240.0 |
2015-07-15 | 2800 | 2.970 | 8372 | 0.049 | 1000 | 2970.0 | 137.2 | -2832.8 |
2015-08-12 | 3800 | 2.850 | 10564 | NA | 2000 | 5700.0 | 0.0 | -5700.0 |
2015-09-13 | 5800 | 3.040 | 15486 | NA | 0 | 0.0 | 0.0 | 0.0 |
2015-10-10 | 5800 | 2.920 | 16530 | NA | 0 | 0.0 | 0.0 | 0.0 |
2015-11-11 | 5800 | 2.950 | 15892 | NA | 1000 | 2950.0 | 0.0 | -2950.0 |
2015-12-12 | 6800 | 2.630 | 18768 | NA | 0 | 0.0 | 0.0 | 0.0 |
2016-01-12 | 6800 | 2.690 | 16728 | NA | 700 | 1883.0 | 0.0 | -1883.0 |
2016-02-03 | 7500 | 2.860 | 19275 | 0.107 | 400 | 1144.0 | 802.5 | -341.5 |
2016-03-21 | 7900 | 2.870 | 21567 | NA | 400 | 1148.0 | 0.0 | -1148.0 |
2016-04-12 | 8300 | 2.840 | 22742 | NA | 900 | 2556.0 | 0.0 | -2556.0 |
2016-05-12 | 9200 | 2.880 | 24932 | NA | 600 | 1728.0 | 0.0 | -1728.0 |
2016-06-10 | 9800 | 2.880 | 26950 | NA | 400 | 1152.0 | 0.0 | -1152.0 |
2016-07-12 | 10200 | 2.860 | 28050 | NA | 400 | 1144.0 | 0.0 | -1144.0 |
2016-08-12 | 10600 | 2.910 | 29362 | 0.084 | 1000 | 2910.0 | 890.4 | -2019.6 |
2016-09-10 | 11600 | 2.860 | 32712 | NA | 700 | 2002.0 | 0.0 | -2002.0 |
2016-10-12 | 12300 | 2.950 | 34071 | NA | 0 | 0.0 | 0.0 | 0.0 |
2016-11-12 | 12300 | 2.940 | 35178 | NA | 0 | 0.0 | 0.0 | 0.0 |
2016-12-09 | 12300 | 3.110 | 35055 | NA | 0 | 0.0 | 0.0 | 0.0 |
2017-01-12 | 12300 | 3.100 | 37023 | NA | 1600 | 4960.0 | 0.0 | -4960.0 |
2017-02-25 | 13900 | 3.190 | 41700 | 0.053 | 600 | 1914.0 | 736.7 | -1177.3 |
2017-03-25 | 14500 | 3.200 | 45530 | NA | 800 | 2560.0 | 0.0 | -2560.0 |
2017-04-24 | 15300 | 3.260 | 48195 | NA | 0 | 0.0 | 0.0 | 0.0 |
2017-05-24 | 15300 | 3.270 | 49113 | NA | 0 | 0.0 | 0.0 | 0.0 |
2017-06-22 | 15300 | 3.320 | 49266 | NA | 800 | 2656.0 | 0.0 | -2656.0 |
2017-07-21 | 16100 | 3.320 | 52647 | 0.048 | 0 | 0.0 | 772.8 | 772.8 |
2017-08-24 | 16100 | 3.250 | 53452 | NA | 400 | 1300.0 | 0.0 | -1300.0 |
2017-09-24 | 16500 | 3.420 | 53625 | NA | 1100 | 3762.0 | 0.0 | -3762.0 |
2017-10-25 | 17600 | 3.480 | 60192 | NA | 0 | 0.0 | 0.0 | 0.0 |
2017-11-24 | 17600 | 3.450 | 61072 | NA | 0 | 0.0 | 0.0 | 0.0 |
2017-12-23 | 17600 | 3.580 | 60544 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-01-24 | 17600 | 3.520 | 64416 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-02-22 | 17600 | 3.430 | 61952 | 0.053 | 0 | 0.0 | 932.8 | 932.8 |
2018-03-23 | 17600 | 3.637 | 60368 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-04-24 | 17600 | 3.500 | 63184 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-05-17 | 17600 | 3.321 | 63008 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-06-24 | 17600 | 3.388 | 58960 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-07-12 | 17600 | 3.251 | 58432 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-08-10 | 17600 | 3.299 | 58080 | 0.060 | 1700 | 5608.3 | 1056.0 | -4552.3 |
2018-09-12 | 19300 | 3.061 | 60795 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-10-12 | 19300 | 3.156 | 60216 | NA | 1300 | 4102.8 | 0.0 | -4102.8 |
2018-11-10 | 20600 | 3.100 | 64272 | NA | 0 | 0.0 | 0.0 | 0.0 |
2018-12-12 | 20600 | 3.247 | 63860 | NA | 0 | 0.0 | 0.0 | 0.0 |
2019-01-11 | 20600 | 3.218 | 67362 | NA | 0 | 0.0 | 0.0 | 0.0 |
2019-02-19 | 20600 | 3.191 | 66332 | 0.056 | 2000 | 6382.0 | 1153.6 | -5228.4 |
2019-03-12 | 22600 | 3.210 | 72388 | NA | NA | NA | 0.0 | 72388.0 |