Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
The Omega Ratio was introduced by Keating and Shadwick in 2002. It measures the ratio of average portfolio wins over average portfolio losses for a given target return L.
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 Omega Ratio can be written as
I will use methods presented in Optimizing Omega by H. Mausser, D. Saunders, L. Seco (2006) paper to construct optimal portfolios that maximize Omega Ratio.
The maximization problem (pages 5-6) can be written as
It can be formulated as a linear programming problem with following transformation
This method will only work for
max.omega.portfolio <- function
(
ia, # input assumptions
constraints # constraints
)
{
n = ia$n
nt = nrow(ia$hist.returns)
constraints0 = constraints
omega = ia$parameters.omega
#--------------------------------------------------------------------------
# Linear Programming, Omega > 1, Case
#--------------------------------------------------------------------------
# objective : Omega
# [ SUM <over j> 1/T * u.j ]
f.obj = c(rep(0, n), (1/nt) * rep(1, nt), rep(0, nt), 0)
# adjust constraints, add u.j, d.j, t
constraints = add.variables(2*nt + 1, constraints, lb = c(rep(0,2*nt),-Inf))
# Transformation for inequalities
# Aw < b => Aw1 - bt < 0
constraints$A[n + 2*nt + 1, ] = -constraints$b
constraints$b[] = 0
# Transformation for Lower/Upper bounds, use same transformation
index = which( constraints$ub[1:n] < +Inf )
if( len(index) > 0 ) {
a = rbind( diag(n), matrix(0, 2*nt, n), -constraints$ub[1:n])
constraints = add.constraints(a[, index], rep(0, len(index)), '<=', constraints)
}
index = which( constraints$lb[1:n] > -Inf )
if( len(index) > 0 ) {
a = rbind( diag(n), matrix(0, 2*nt, n), -constraints$lb[1:n])
constraints = add.constraints(a[, index], rep(0, len(index)), '>=', constraints)
}
constraints$lb[1:n] = -Inf
constraints$ub[1:n] = Inf
# [ SUM <over i> r.ij * x.i ] - u.j + d.j - L * t = 0, for each j = 1,...,T
a = rbind( matrix(0, n, nt), -diag(nt), diag(nt), -omega)
a[1 : n, ] = t(ia$hist.returns)
constraints = add.constraints(a, rep(0, nt), '=', constraints)
# [ SUM <over j> 1/T * d.j ] = 1
constraints = add.constraints(c( rep(0,n), rep(0,nt), (1/nt) * rep(1,nt), 0), 1, '=', constraints)
# setup linear programming
f.con = constraints$A
f.dir = c(rep('=', constraints$meq), rep('>=', len(constraints$b) - constraints$meq))
f.rhs = constraints$b
# find optimal solution
x = NA
sol = try(solve.LP.bounds('max', f.obj, t(f.con), f.dir, f.rhs,
lb = constraints$lb, ub = constraints$ub), TRUE)
if(!inherits(sol, 'try-error')) {
x0 = sol$solution[1:n]
u = sol$solution[(1+n):(n+nt)]
d = sol$solution[(n+nt+1):(n+2*nt)]
t = sol$solution[(n+2*nt+1):(n+2*nt+1)]
# Reverse Transformation
x = x0/t
}
#--------------------------------------------------------------------------
# NonLinear Programming, Omega > 1, Case
#--------------------------------------------------------------------------
# Check if any u.j * d.j != 0 or LP solver encounter an error
if( any( u*d != 0 ) || sol$status !=0 ) {
require(Rdonlp2)
constraints = constraints0
# compute omega ratio
fn <- function(x){
portfolio.returns = x %*% t(ia$hist.returns)
mean(pmax(portfolio.returns - omega,0)) / mean(pmax(omega - portfolio.returns,0))
}
# control structure, fnscale - set -1 for maximization
cntl <- donlp2.control(silent = T, fnscale = -1, iterma =10000, nstep = 100, epsx = 1e-10)
# lower/upper bounds
par.l = constraints$lb
par.u = constraints$ub
# intial guess
if(!is.null(constraints$x0)) p = constraints$x0
# linear constraints
A = t(constraints$A)
lin.l = constraints$b
lin.u = constraints$b
lin.u[ -c(1:constraints$meq) ] = +Inf
# find solution
sol = donlp2(p, fn, par.lower=par.l, par.upper=par.u,
A=A, lin.u=lin.u, lin.l=lin.l, control=cntl)
x = sol$par
}
return( x )
}
First let’s examine how the traditional mean-variance efficient frontier looks like in the Omega Ratio framework.
# 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)
# Omega - http://en.wikipedia.org/wiki/Omega_ratio
ia$parameters.omega = 13/100
ia$parameters.omega = 12/100
# convert annual to monthly
ia$parameters.omega = ia$parameters.omega / 12
# create efficient frontier(s)
ef.risk = portopt(ia, constraints, 50, 'Risk')
# Plot Omega Efficient Frontiers and Transition Maps
layout( matrix(1:4, nrow = 2, byrow=T) )
# weights
rownames(ef.risk$weight) = paste('Risk','weight',1:50,sep='_')
plot.omega(ef.risk$weight[c(1,10,40,50), ], ia)
# assets
temp = diag(n)
rownames(temp) = ia$symbols
plot.omega(temp, ia)
# mean-variance efficient frontier in the Omega Ratio framework
plot.ef(ia, list(ef.risk), portfolio.omega, T, T)
Portfolio returns and Portfolio Omega Ratio are monotonically increasing as we move along the traditional mean-variance efficient frontier in the Omega Ratio framework. The least risky portfolios (Risk_weight_1, Risk_weight_10) have lower Omega Ratio for 13% threshold (target return) and the most risky portfolios (Risk_weight_40, Risk_weight_50) have higher Omega Ratio.
To create efficient frontier in the Omega Ratio framework, I propose first to compute range of returns in the mean-variance framework. Next split this range into # Portfolios equally spaced points. For each point, I propose to find portfolio that has expected return less than given point’s expected return and maximum Omega Ratio.
#--------------------------------------------------------------------------
# Create Efficient Frontier in Omega Ratio framework
#--------------------------------------------------------------------------
# Create maximum Omega Efficient Frontier
ef.omega = portopt.omega(ia, constraints, 50, 'Omega')
# Plot Omega Efficient Frontiers and Transition Maps
layout( matrix(1:4, nrow = 2, byrow=T) )
# weights
plot.omega(ef.risk$weight[c(1,10,40,50), ], ia)
# weights
rownames(ef.omega$weight) = paste('Omega','weight',1:50,sep='_')
plot.omega(ef.omega$weight[c(1,10,40,50), ], ia)
# portfolio
plot.ef(ia, list(ef.omega, ef.risk), portfolio.omega, T, T)
The Omega Ratio efficient frontier looks similar to the traditional mean-variance efficient frontier for expected returns greater than 13% threshold (target return). However, there is a big shift in allocation and increase in Omega Ratio for portfolios with expected returns less than 13% threshold.
The Omega Ratio efficient frontier looks very inefficient in the Risk framework for portfolios with expected returns less than 13% threshold. But remember that goal of this optimization was to find portfolios that maximize Omega Ratio for given user constraints. Overall I find results a bit radical for portfolios with expected returns less than 13% threshold, and this results defiantly call for more investigation.
To view the complete source code for this example, please have a look at the aa.omega.test() function in aa.test.r at github.
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.
