# Maximizing Omega Ratio

November 3, 2011
By

[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.

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

$\Omega(L) = \frac{E\left [ max(\sum_{i=1}^{n}r_{ij}x_{i} - L, 0) \right ]}{E\left [ max(L - \sum_{i=1}^{n}r_{ij}x_{i}, 0) \right ]}$

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

$\Omega^{*}(L) = max_{x,u,d}\frac{\frac{1}{T} \sum_{i=1}^{n}u_{i}}{\frac{1}{T} \sum_{i=1}^{n}d_{i}} \newline\newline \sum_{i=1}^{n}r_{ij}x_{i} - u_{j}+d_{j} = L, j=1,...,T \newline\newline u_{j},d_{j}\geq 0, j=1,...,T \newline\newline u_{j}*d_{j} = 0, j=1,...,T$

It can be formulated as a linear programming problem with following transformation

$t=\frac{1}{\frac{1}{T} \sum_{i=1}^{n}u_{i}} \newline\newline \Omega^{*}(L) = max_{\tilde{x},\tilde{u},\tilde{d},t}\frac{1}{T} \sum_{i=1}^{n}\tilde{u}_{i} \newline\newline \sum_{i=1}^{n}r_{ij}\tilde{x}_{i} - \tilde{u}_{j}+\tilde{d}_{j} = L, j=1,...,T \newline\newline \frac{1}{T}\sum_{i=1}^{n}\tilde{d}_{i} = 1 \newline\newline \tilde{u}_{j},\tilde{d}_{j}\geq 0, j=1,...,T$

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 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  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 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.

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.

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Tags: , , ,