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.