Showing posts with label financial markets. Show all posts
Showing posts with label financial markets. Show all posts

Thursday, 10 September 2015

Expected Shortfall for a Canadian ETF Portfolio: September 2015

August was a volatile month for world equity markets. Broad equity markets in North America and Europe started August in a narrow trading range before taking steep drops in the middle of the month and then rebounding slightly. Historically, August can be a bad month for equities because many traders in North America and Europe take vacations. As a result, there is less volume which tends to magnify bad events.

In this post I look at the damage this volatility did to a Canadian ETF portfolio. The approach is to calculate expected shortfall (ES) for a balanced portfolio of Canadian ETFs. This is an update on an earlier post that I did. ES calculates the average expected loss over a particular time period for a given confidence interval.

I use a portfolio of five broad asset classes: Canadian equities, Canadian REITs, US equities, Europe and Far East (EAFE) equities, and Canadian bonds. I use daily data sourced from Yahoo Finance. The ticker symbols and asset classes are as follows.

  "XIU.TO", # Canadian equities,
  "XRE.TO", # Canadian REITS,
  "XSP.TO", # US equities (SP500),
  "XIN.TO", # EAFE equities,
  "XBB.TO"  # Canada bonds,


The portfolio weights are:
XIU 30%
XRE 10%
XSP 20%
XIN 10%
XBB 30%

Here is how each of the ETFs have performed over the past 100 trading days.



Even Canadian bonds (XBB.TO) got hit! For Canadian investors, there was no where to run and no where to hide.

Here are what the updated expected shortfall values look like. For the ES calculations I calculate one day ES at a 99% confidence interval.

To the right of the chart ES violations are evident for each of the three ES values. Lets take a closer look at the last 30 trading days.



               Portfolio  Historical    Gaussian    Modified hit_hist hit_mod
2015-07-28  0.0045591063 -0.02057457 -0.01388825 -0.02011961        0       0
2015-07-29  0.0072440550 -0.02057457 -0.01388926 -0.02011382        0       0
2015-07-30  0.0021083012 -0.01961036 -0.01372071 -0.01958061        0       0
2015-07-31  0.0049846131 -0.01961036 -0.01369486 -0.01959875        0       0
2015-08-04 -0.0001214745 -0.01727665 -0.01329163 -0.01802837        0       0
2015-08-05 -0.0002307325 -0.01727665 -0.01308706 -0.01716631        0       0
2015-08-06 -0.0046951243 -0.01727665 -0.01304780 -0.01708168        0       0
2015-08-07 -0.0013375814 -0.01727665 -0.01293413 -0.01674055        0       0
2015-08-10  0.0048423110 -0.01727665 -0.01293624 -0.01674833        0       0
2015-08-11 -0.0027925194 -0.01727665 -0.01292721 -0.01670386        0       0
2015-08-12 -0.0029878816 -0.01727665 -0.01290819 -0.01665256        0       0
2015-08-13 -0.0025982336 -0.01727665 -0.01291542 -0.01668199        0       0
2015-08-14  0.0019287368 -0.01621678 -0.01273006 -0.01731595        0       0
2015-08-17  0.0008568045 -0.01621678 -0.01268098 -0.01726896        0       0
2015-08-18 -0.0022049060 -0.01621678 -0.01268081 -0.01727367        0       0
2015-08-19 -0.0054502305 -0.01621678 -0.01260506 -0.01695646        0       0
2015-08-20 -0.0156635244 -0.01621678 -0.01262080 -0.01699182        0       0
2015-08-21 -0.0169691849 -0.01639901 -0.01267554 -0.01696590        1       1
2015-08-24 -0.0272985615 -0.01668715 -0.01276972 -0.01695727        1       1
2015-08-25  0.0007662231 -0.01797793 -0.01297351 -0.01555675        0       0
2015-08-26  0.0161247653 -0.01797793 -0.01297354 -0.01555796        0       0
2015-08-27  0.0173129171 -0.01797793 -0.01302212 -0.01568852        0       0
2015-08-28  0.0011453308 -0.01797793 -0.01307287 -0.01584518        0       0
2015-08-31 -0.0050855477 -0.01797793 -0.01303772 -0.01572148        0       0
2015-09-01 -0.0176022569 -0.01797793 -0.01304444 -0.01575105        0       1
2015-09-02  0.0068626662 -0.01822957 -0.01311513 -0.01578005        0       0
2015-09-03  0.0035217033 -0.01822957 -0.01311116 -0.01577722        0       0
2015-09-04 -0.0086586215 -0.01822957 -0.01303865 -0.01570228        0       0
2015-09-08  0.0099768929 -0.01822957 -0.01305171 -0.01570694        0       0
2015-09-09 -0.0055476529 -0.01822957 -0.01306676 -0.01569068        0       0



ES calculated using the historical method results in hits (portfolio return less than ES) on August 21 and 24. ES calculated using the modified approach results in hits on August 21,24, and September 1. The ES is calculated using a confidence interval of 99%. So 99% of the time the actual loss should be no larger than the ES value. There is a 1% chance of losing more than the ES value. For daily data this works out to a "hit" or exceedance once every 100 days. According to the modified ES calculation we have had 3 hits in the past 30 days. Poisson clumping? Perhaps, but certainly beyond what the models predicted.


Here is the R code.

#########################################################
#  Economic forecasting and analysis
#  Perry Sadorsky
#  ES for a Canadian portfolio
#  September 2015
##########################################################

rm(list=ls())
library(fpp)
library(quantmod)
library(PerformanceAnalytics)




symbols = c(
  "XIU.TO", # Canadian equities,
  "XRE.TO", # Canadian REITS,
  "XSP.TO", # US equities (SP500),
  "XIN.TO", # EAFE equities,
  "XBB.TO"  # Canada bonds,
)



getSymbols(symbols, from="1970-01-01")
m = length(symbols)
Y = Ad(XIU.TO)
for (i in 2:m) Y = cbind(Y, Ad(get(symbols[i])))
head(Y)
tail(Y)



par(mfrow = c(3, 2))
for (i in 1:m) plot(tail (Y[, i], 100),  main = symbols[i])
par(mfrow = c(1, 1))



## returns
y.ret <-  (na.omit(1 * diff(log(Y)) ))


par(mfrow = c(3, 2))
for (i in 1:m) {qqnorm(y.ret[, i],  main = c("QQ Normal Plot",symbols[i]))
                qqline(y.ret[, i])}
par(mfrow = c(1, 1))


head(y.ret)
tail(y.ret)
weights <- c(0.3, 0.1, 0.2, 0.1, 0.3)
##########################################################


w.e = 1000
p.v = 0.99
port.ret = weights[1]*y.ret[,1] + weights[2]*y.ret[,2] + weights[3]*y.ret[,3]+ weights[4]*y.ret[,4] + weights[5]*y.ret[,5]
names(port.ret) = c("Portfolio")



## create custom function
bt_p_ES <- function(x, p, w) {
  modified.ES = as.numeric  ( ES(x, p=p, method="modified", portfolio_method = "component", weights = w)$MES)
  historical.ES = as.numeric  (ES(x, p=p, method="historical", portfolio_method="component", weights = w)$`-r_exceed/c_exceed`)
  gaussian.ES = as.numeric  ( ES(x, p=p, method="gaussian",  portfolio_method = "component", weights = w)$ES)
  ans = c(historical.ES, gaussian.ES, modified.ES)
  names(ans) = c("Historical", "Gaussian", "Modified")
  return(ans)
}


## rolling analysis
tic <- Sys.time()
ret.es_1 <- rollapply(y.ret, width = w.e, FUN = bt_p_ES, p=p.v, w=weights, by.column = FALSE,
                      align = "right"  )
toc <- Sys.time()
toc - tic

View(ret.es_1)
tail(ret.es_1)


## all three together with actual portfolio returns
ES.results = lag(ret.es_1, k=1)
chart.TimeSeries(merge(port.ret, -ES.results), legend.loc="topright")
tail(-ES.results)

# identify exceedances
hit_hist = port.ret < -ES.results[,1]
hit_mod  = port.ret < -ES.results[,3]

colnames(hit_hist) = "hit_hist"
colnames(hit_mod)  = "hit_mod"

tail(merge(port.ret, -ES.results, hit_hist, hit_mod),30)


Thursday, 9 July 2015

Expected Shortfall for a Canadian ETF Portfolio

In the past few weeks we have seen a lot of volatility in the financial markets. Greece is on the verge of a bailout, leaving the Euro currency, or something in between. China's stock markets, after an impressive run up over the past year have come crashing down. At times like these it is always a good idea to quantify portfolio risk. I take the position of  a Canadian investor who invests in a portfolio of broad based ETFs who wants to know their risk exposure as measured by expected shortfall (ES). ES is related to value at risk (VaR) but whereas VaR provides a measure of the minimum loss for a particular time period and coverage, ES calculates the average expected loss and is therefore closer to what an investor might expect to loose on average.
 
I use a portfolio of five broad asset classes: Canadian equities, Canadian REITs, US equities, Europe and Far East (EAFE) equities, and Canadian bonds. I use daily data sourced from Yahoo Finance. The ticker symbols and asset classes are as follows.

  "XIU.TO", # Canadian equities,
  "XRE.TO", # Canadian REITS,
  "XSP.TO", # US equities (SP500),
  "XIN.TO", # EAFE equities,
  "XBB.TO"  # Canada bonds,

Here is how each of the ETFs have performed.



Except for XBB, the other ETFs experienced large drops during the 2008 - 2009 financial crisis. The Canadian bond market, however, just kept on chugging along.

Here are what the QQ plots look like for the daily continuously compounded returns.


The plots indicate heavy tails for each of the asset returns. This would indicate that assuming normally distributed returns is probably not the best assumption to make when measuring risk.

Now on to calculating expected shortfall (ES). For comparison purposes, ES is calculated three ways (Historical, Gaussian, Modified). ES is calculated using a fixed width moving window of 1000 days. At the end of the day, the current ES is shifted forward by one day to provide a forecast for the next day's shortfall. Coverage is set at 99% which means that ES is calculated as the average loss over the first percentile of the return distribution. As we have seen from the QQ plots, the Gaussian approach is likely to lead to underestimating the expected shortfall because it does not account for heavy tails. In these situations, Modified often works well because it takes into account skewness and excess kurtosis.

The first portfolio I consider is a diversified portfolio with the following portfolio weights.

XIU 30%
XRE 10%
XSP 20%
XIN 10%
XBB 30%




Expected shortfall calculated from the Historical or Modified versions is very similar. In comparison, ES calculated from the Gaussian approach results in more violations.

Here are what the recent daily ES values look like.


           Historical Gaussian Modified
2015-06-30   -0.02057 -0.01398 -0.02016
2015-07-02   -0.02057 -0.01398 -0.02016
2015-07-03   -0.02057 -0.01398 -0.02016
2015-07-06   -0.02057 -0.01397 -0.02016
2015-07-07   -0.02057 -0.01395 -0.02018
2015-07-08   -0.02057 -0.01395 -0.02017



The ES modified value for July 8, 2015 indicates that on that day there was a 1% chance of loosing an average of 2.017% of the portfolio. In other words, the average daily loss on a $100,000 portfolio is $2017.

For comparison purposes, I also estimate expected shortfall for a traditional 60/40 portfolio (60% XIU and 40% XBB).


As in the previous case, the Historical and Modified ES values are similar while the Gaussian ES values lead to more rejections. The most recent value for the Modified ES indicates an average portfolio loss of 1.676% at 99% coverage. The average loss on a $100,000 portfolio is $1676. Notice that the ES values from the 60/40 portfolio are smaller in absolute value than those from the 5 asset portfolio. Interestingly, the Canadian 60/40 portfolio provides less risk than the diversified five asset portfolio.



           Historical Gaussian Modified
2015-06-30    -0.0164 -0.01278 -0.01682
2015-07-02    -0.0164 -0.01278 -0.01681
2015-07-03    -0.0164 -0.01278 -0.01680
2015-07-06    -0.0164 -0.01278 -0.01680
2015-07-07    -0.0164 -0.01277 -0.01676
2015-07-08    -0.0164 -0.01277 -0.01676



While the most recent volatility in the financial markets has been a concern, there has been no breaching of the Historical or Modified expected shortfall values in either the five asset portfolio or the 60/40 portfolio.


The R code is provided below. It takes about 12 minutes to complete one rolling ES calculation.

#########################################################
#  Economic forecasting and analysis
#  Perry Sadorsky
#  ES for a Canadian portfolio
#  July 2015
##########################################################

rm(list=ls())
library(fpp)
library(quantmod)




symbols = c(
  "XIU.TO", # Canadian equities,
  "XRE.TO", # Canadian REITS,
  "XSP.TO", # US equities (SP500),
  "XIN.TO", # EAFE equities,
  "XBB.TO"  # Canada bonds,
)



getSymbols(symbols, from="1970-01-01")
m = length(symbols)
Y = Ad(XIU.TO)
for (i in 2:m) Y = cbind(Y, Ad(get(symbols[i])))
head(Y)
tail(Y)



par(mfrow = c(3, 2))
for (i in 1:m) plot(Y[, i],  main = symbols[i])
par(mfrow = c(1, 1))



## returns
y.ret <-  (na.omit(1 * diff(log(Y)) ))


par(mfrow = c(3, 2))
for (i in 1:m) {qqnorm(y.ret[, i],  main = c("QQ Normal Plot",symbols[i]))
                qqline(y.ret[, i])}
par(mfrow = c(1, 1))


head(y.ret)
tail(y.ret)
weights <- c(0.3, 0.1, 0.2, 0.1, 0.3)
##########################################################


w.e = 1000
p.v = 0.99
port.ret = weights[1]*y.ret[,1] + weights[2]*y.ret[,2] + weights[3]*y.ret[,3]+ weights[4]*y.ret[,4] + weights[5]*y.ret[,5]
names(port.ret) = c("Portfolio")



## create custom function
bt_p_ES <- function(x, p, w) {
  modified.ES = as.numeric  ( ES(x, p=p, method="modified", portfolio_method = "component", weights = w)$MES)
  historical.ES = as.numeric  (ES(x, p=p, method="historical", portfolio_method="component", weights = w)$`-r_exceed/c_exceed`)
  gaussian.ES = as.numeric  ( ES(x, p=p, method="gaussian",  portfolio_method = "component", weights = w)$ES)
  ans = c(historical.ES, gaussian.ES, modified.ES)
  names(ans) = c("Historical", "Gaussian", "Modified")
  return(ans)
}


## rolling analysis
tic <- Sys.time()
ret.es_1 <- rollapply(y.ret, width = w.e, FUN = bt_p_ES, p=p.v, w=weights, by.column = FALSE,
                      align = "right"  )
toc <- Sys.time()
toc - tic

View(ret.es_1)
tail(ret.es_1)


## all three together with actual portfolio returns
ES.results = lag(ret.es_1, k=1)
chart.TimeSeries(merge(port.ret, -ES.results), legend.loc="topright")
tail(-ES.results)


##########################################################
##### comparison with 60/40 portfolio
##########################################################
port.ret.b = 0.6*y.ret[,1]  + 0.4*y.ret[,5]
names(port.ret.b) = c("Portfolio 60/40")
y.ret.b = y.ret[,c(1,5)]
tail(y.ret.b)



## rolling analysis
tic <- Sys.time()
ret.es_1.b <- rollapply(y.ret.b, width = w.e, FUN = bt_p_ES, p=p.v, w=c(.6,.4), by.column = FALSE,
                      align = "right"  )
toc <- Sys.time()
toc - tic

View(ret.es_1.b)
tail(ret.es_1.b)


## all three together with actual portfolio returns
ES.results.b = lag(ret.es_1.b, k=1)
chart.TimeSeries(merge(port.ret.b, -ES.results.b), legend.loc="topright")
tail(-ES.results.b)