Site icon R-bloggers

Expected shortfall (CVaR) and Conditional Drawdown at Risk (CDaR) risk measures

[This article was first published on Systematic Investor » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

In the Maximum Loss and Mean-Absolute Deviation risk measures post I started the discussion about alternative risk measures we can use to construct efficient frontier. Another alternative risk measures I want to discuss are Expected shortfall (CVaR) and Conditional Drawdown at Risk (CDaR). I will use methods presented in Comparative Analysis of Linear Portfolio Rebalancing Strategies: An Application to Hedge Funds by Krokhmal, P., S. Uryasev, and G. Zrazhevsky (2001) and Portfolio Optimization Using Conditional Value-At-Risk and Conditional Drawdown-At-Risk by Enn Kuutanpapers to construct optimal portfolios.

Let x.i, i= 1,…,n be weights of instruments in the portfolio. We suppose that j= 1,…,T scenarios of returns with equal probabilities are available. I will use historical assets returns as scenarios. Let us denote by r.ij the return of i-th asset in the scenario j. The portfolio’s Conditional Value at Risk (CVaR) (page 30-32) can be written as

It can be formulated as a linear programming problem

This linear programming problem can be easily implemented

min.cvar.portfolio (
	ia,			# input assumptions
	constraints		# constraints
)
{
	n = ia$n
	nt = nrow(ia$hist.returns)

	# objective : Conditional Value at Risk (CVaR)
	#  E + 1/(1-a) * 1/T * [ SUM  w.j ]
	f.obj = c( rep(0, n), (1/(1-alpha))* (1/nt) * rep(1, nt), 1 )

	# adjust prior constraints, add w.j, E
	f.con = rbind( constraints$A, matrix(0, (nt + 1), ncol(constraints$A) ) )
	f.dir = c(rep('=', constraints$meq), rep('>=', len(constraints$b) - constraints$meq))
	f.rhs = constraints$b

	#  -E - [ SUM  r.ij * x.i ] < w.j, for each j = 1,...,T
	a1 = rbind( matrix(0, n, nt), diag(nt), 1)
	b1 = rep(0, nt)
		a1[1:n0,] = t(ia$hist.returns) 	

	f.con = cbind( f.con, a1 )
	f.dir = c(f.dir, rep('>=', nt))
	f.rhs = c(f.rhs, b1)

	# find optimal solution
	x = NA
	min.x.bounds = c( rep(-100, n), rep(0, nt), -100 )
	sol = try(solve.LP.bounds('min', f.obj, t(f.con), f.dir, f.rhs, lb = min.x.bounds), TRUE)

	if(!inherits(sol, 'try-error')) {
		x = sol$solution[1:n]
	}

	return( x )
}

The portfolio’s Conditional Drawdown at Risk (CDaR) (page 32-33) concept is very similar to CVaR. Instead of using portfolio returns to determine shortfall, we use portfolio drawdowns. The Conditional Drawdown at Risk (CDaR) can be written as

It can be formulated as a linear programming problem

min.cdar.portfolio (
	ia,			# input assumptions
	constraints		# constraints
)
{
	n = ia$n
	nt = nrow(ia$hist.returns)

	# objective : Conditional Drawdown at Risk (CDaR)
	#  E + 1/(1-a) * 1/T * [ SUM  w.j ]
	f.obj = c( rep(0, n), (1/(1-alpha))* (1/nt) * rep(1, nt), 1, rep(0, nt) )

	# adjust prior constraints, add w.j, E, u.j
	f.con = rbind( constraints$A, matrix(0, (2 * nt + 1), ncol(constraints$A) ) )
	f.dir = c(rep('=', constraints$meq), rep('>=', len(constraints$b) - constraints$meq))
	f.rhs = constraints$b

	#  u.j - [ SUM  [ SUM  r.ij ] * x.i ] - E < w.j, for each j = 1,...,T
	a1 = rbind( matrix(0, n, nt), diag(nt), 1, -diag(nt))
	b1 = rep(0, nt)
		a1[1:n0,] = t(apply( t(ia$hist.returns), 1, cumsum)) 		 	

	f.con = cbind( f.con, a1 )
	f.dir = c(f.dir, rep('>=', nt))
	f.rhs = c(f.rhs, b1)

	#  [ SUM  [ SUM  r.ij ] * x.i ] < u.j, for each j = 1,...,T
	a1 = rbind( matrix(0, n, nt), 0*diag(nt), 0, diag(nt))
	b1 = rep(0, nt)
		a1[1:n0,] = -t(apply( t(ia$hist.returns), 1, cumsum)) 	

	f.con = cbind( f.con, a1 )
	f.dir = c(f.dir, rep('>=', nt))
	f.rhs = c(f.rhs, b1)

	#  u.j-1 < u.j, for each j = 1,...,T
	temp = diag(nt)
		temp[-nt,-1]=-diag((nt-1))
	diag(temp) = 1		 	 	

	a1 = rbind( matrix(0, n, nt), 0*diag(nt), 0, temp)
	b1 = rep(0, (nt-1))
		a1 = a1[,-1] 	

	f.con = cbind( f.con, a1 )
	f.dir = c(f.dir, rep('>=', (nt-1)))
	f.rhs = c(f.rhs, b1)

	# find optimal solution
	x = NA
	min.x.bounds = c( rep(-100, n), rep(0, nt), -100, rep(-100, nt) )
	sol = try(solve.LP.bounds('min', f.obj, t(f.con), f.dir, f.rhs, lb = min.x.bounds), TRUE)

	if(!inherits(sol, 'try-error')) {
		x = sol$solution[1:n]
	}

	return( x )
}

Let’s examine efficient frontiers computed under different risk measures using historical input assumptions presented in the Introduction to Asset Allocation post:

# load Systematic Investor Toolbox
setInternet2(TRUE)
source(gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb')))

#--------------------------------------------------------------------------
# Create Efficient Frontier
#--------------------------------------------------------------------------
	ia = aa.test.create.ia()
	n = ia$n		

	# 0 <= x.i <= 0.8
	constraints = new.constraints(n, lb = 0, ub = 0.8)

	# SUM x.i = 1
	constraints = add.constraints(rep(1, n), 1, type = '=', constraints)		

	# Alpha for used for CVaR and CDaR
	# http://www.investopedia.com/articles/04/092904.asp
	ia$parameters.alpha = 0.95

	# create efficient frontier(s)
	ef.risk = 		portopt(ia, constraints, 50, 'Risk')
	ef.cvar = 		portopt(ia, constraints, 50, 'CVaR', 	min.cvar.portfolio)
	ef.cdar = 		portopt(ia, constraints, 50, 'CDaR', 	min.cdar.portfolio)

	# Plot multiple Efficient Frontiers
	layout( matrix(1:4, nrow = 2) )
	plot.ef(ia, list(ef.risk, ef.cvar, ef.cdar), portfolio.risk, F)
	plot.ef(ia, list(ef.risk, ef.cvar, ef.cdar), portfolio.cvar, F)
	plot.ef(ia, list(ef.risk, ef.cvar, ef.cdar), portfolio.cdar, F)	

	# Plot multiple Transition Maps
	layout( matrix(1:4, nrow = 2) )
	plot.transitopn.map(ef.risk)
	plot.transitopn.map(ef.cvar)
	plot.transitopn.map(ef.cdar)

The efficient frontiers constructed under Expected shortfall (CVaR) and Standard Deviation risk measures look similar. The efficient frontier constructed under Conditional Drawdown at Risk (CDaR) is superior to the other risk measures in controlling drawdowns.

In the next post, I will discuss how to combine multiple risk measures during construction of efficient frontier.

To view the complete source code for this example, please have a look at the aa.cvar.test() function in aa.test.r at github.


To leave a comment for the author, please follow the link and comment on their blog: Systematic Investor » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.