Sortino vs Omega ratios
02 Apr 2015
To install Systematic Investor Toolbox (SIT) please visit About page.
Following is quick visual comparison of
Omega ratio vs
Sortino ratio
library ( SIT )
load.packages ( 'quantmod' )
#*****************************************************************
# Helper functions
#*****************************************************************
sortino.ratio = function ( R , MAR ) {
r = R [ R < MAR ]
( mean ( R ) - MAR ) / sqrt ( sum (( MAR - r ) ^ 2 ) / length ( r ) )
}
omega.ratio = function ( R , MAR ) {
#sum(pmax(R - MAR, 0)) / sum(pmax(MAR - R, 0))
r = R - MAR
- sum ( r [ r > 0 ]) / sum ( r [ r < 0 ])
}
#*****************************************************************
# check: Omega has a value of 1 at the mean of the distribution
#*****************************************************************
R = rnorm ( 100 )
MAR = mean ( R )
print ( list ( Sortino = sortino.ratio ( R , MAR ), Omega = omega.ratio ( R , MAR )))
$Sortino
[1] 0
$Omega
[1] 1
#*****************************************************************
# Plot Sortino vs Omega
# based on [R graph with two y-axes](http://robjhyndman.com/hyndsight/r-graph-with-two-y-axes/)
#*****************************************************************
plot.sortino.omega = function ( R , main = '' ) {
x = quantile ( R , c ( 0.05 , 0.95 ))
x = seq ( x [ 1 ], x [ 2 ], length.out = 100 )
par ( mar = c ( 5 , 4 , 4 , 5 ))
plot ( x , sapply ( x , function ( y ) sortino.ratio ( R , y )), xlab = 'MAR' , ylab = 'Sortino' ,
main = paste ( 'Sortino vs Omega' , main ), type = 'l' , col = 'red' )
par ( new = TRUE )
plot ( x , sapply ( x , function ( y ) omega.ratio ( R , y )), xaxt = "n" , yaxt = "n" , xlab = "" , ylab = '' , type = 'l' , col = 'blue' )
axis ( 4 )
mtext ( 'Omega' , side = 4 , line = 3 )
legend ( "topright" , col = c ( 'red' , 'blue' ), lty = 1 , legend = c ( 'Sortino' , 'Omega' ), bty = 'n' )
}
plot.sortino.omega ( R , ' based on random data' )
#*****************************************************************
# Load historical data
#*****************************************************************
data = env ()
getSymbols ( 'SPY' , src = 'yahoo' , from = '1970-01-01' , env = data , auto.assign = T )
price = Ad ( data $ SPY )
ret = diff ( log ( price ))
plot.sortino.omega ( last ( ret , 252 ), ' based on last year of SPY' )
Re-run Maximizing Omega Ratio
Please set threshold used in Omega calculations (i.e. MAR) to a small number.
Otherwise, optimizer will be forced to find corner solutions and result in not stable weights.
#--------------------------------------------------------------------------
# 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
# do not set threshold too high
ia $ parameters.omega = 1 / 100
# convert annual to monthly
ia $ parameters.omega = ia $ parameters.omega / 12
max.omega.portfolio ( ia , constraints )
[1] 0.000000e+00 7.255498e-02 1.688399e-01 1.097557e-16 0.000000e+00
[6] 2.661959e-01 0.000000e+00 4.924093e-01
# create efficient frontier(s)
ef.risk = portopt ( ia , constraints , 50 , 'Risk' )
#plot.ef(ia, list(ef.risk), portfolio.risk, T, T)
# 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 )
# portfolio
plot.ef ( ia , list ( ef.risk ), portfolio.omega , T , T )
#--------------------------------------------------------------------------
# Create Efficient Frontier in Omega Ratio framework
#--------------------------------------------------------------------------
# Create maximum Omega Efficient Frontier
ef.omega = portopt.omega ( ia , constraints , 50 )
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
i = 11
i = 12
i = 13
i = 14
i = 15
i = 16
i = 17
i = 18
i = 19
i = 20
i = 21
i = 22
i = 23
i = 24
i = 25
i = 26
i = 27
i = 28
i = 29
i = 30
i = 31
i = 32
i = 33
i = 34
i = 35
i = 36
i = 37
i = 38
i = 39
i = 40
i = 41
i = 42
i = 43
i = 44
i = 45
i = 46
i = 47
i = 48
i = 49
i = 50
# 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 )
#plot.omega(ef.omega$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 )
#--------------------------------------------------------------------------
# Compare Risk and Omega frontiers
#--------------------------------------------------------------------------
# Plot multiple Efficient Frontiers and Transition Maps
layout ( matrix ( 1 : 4 , nrow = 2 ) )
plot.ef ( ia , list ( ef.risk , ef.omega ), portfolio.risk , F )
plot.ef ( ia , list ( ef.risk , ef.omega ), portfolio.omega , F )
plot.transition.map ( ef.risk )
plot.transition.map ( ef.omega )
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.
#' @export
target.omega.portfolio <- function
(
target.omega ,
type = 'mixed'
)
{
target.omega = target.omega
function
(
ia , # input assumptions
constraints # constraints
)
{
ia $ parameters.omega = target.omega
max.omega.portfolio ( ia , constraints , type )
}
}
#*****************************************************************
# Load historical data
#*****************************************************************
library ( SIT )
load.packages ( 'quantmod' )
# load saved Proxies Raw Data, data.proxy.raw, to extend DBC and SHY
# please see http://systematicinvestor.github.io/Data-Proxy/ for more details
load ( 'data/data.proxy.raw.Rdata' )
tickers = '
LQD + VWESX
DBC + CRB
VTI +VTSMX # (or SPY)
ICF + VGSIX # (or IYR)
CASH = SHY + TB3Y
'
data <- new.env ()
getSymbols.extra ( tickers , src = 'yahoo' , from = '1970-01-01' , env = data , raw.data = data.proxy.raw , set.symbolnames = T , auto.assign = T )
for ( i in data $ symbolnames ) data [[ i ]] = adjustOHLC ( data [[ i ]], use.Adjusted = T )
#print(bt.start.dates(data))
bt.prep ( data , align = 'remove.na' , fill.gaps = T )
#*****************************************************************
# Code Strategies
#******************************************************************
obj = portfolio.allocation.helper ( data $ prices ,
periodicity = 'months' , lookback.len = 60 ,
min.risk.fns = list (
EW = equal.weight.portfolio ,
RP = risk.parity.portfolio (),
MD = max.div.portfolio ,
MV = min.var.portfolio ,
MVE = min.var.excel.portfolio ,
MO = target.omega.portfolio ( 0 / 100 , 'lp' ),
MC = min.corr.portfolio ,
MCE = min.corr.excel.portfolio ,
MC2 = min.corr2.portfolio ,
MS = max.sharpe.portfolio ()
),
silent = T
)
commission = list ( cps = 0.01 , fixed = 10.0 , percentage = 0.0 )
models = create.strategies ( obj , data , dates = '1997::' , commission = commission , silent = T ) $ models
#*****************************************************************
# Create Report
#*****************************************************************
#strategy.performance.snapshoot(models, T)
plotbt ( models , plotX = T , log = 'y' , LeftMargin = 3 , main = NULL )
mtext ( 'Cumulative Performance' , side = 2 , line = 1 )
print ( plotbt.strategy.sidebyside ( models , make.plot = F , return.table = T , perfromance.fn = engineering.returns.kpi ))
EW
RP
MD
MV
MVE
MO
MC
MCE
MC2
MS
Period
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Cagr
6.41
4.06
3.88
3.15
3.13
4.2
4.04
4.02
4.06
4.43
Sharpe
0.65
1.26
1.19
1.73
1.47
0.72
1.25
1.22
1.32
0.76
DVR
0.6
1.21
1.1
1.61
1.36
0.61
1.18
1.16
1.26
0.63
R2
0.93
0.96
0.92
0.93
0.93
0.84
0.94
0.95
0.96
0.84
Volatility
10.51
3.2
3.26
1.8
2.12
5.95
3.21
3.27
3.07
5.99
MaxDD
-40.68
-12.11
-8.74
-2.88
-2.97
-19.4
-7.97
-7.57
-8.67
-17.97
Exposure
99.98
99.98
99.98
99.98
99.98
99.98
99.98
99.98
99.98
99.98
Now let’s do monthly
data = bt.change.periodicity ( data , periodicity = 'months' )
#*****************************************************************
# Code Strategies
#******************************************************************
obj = portfolio.allocation.helper ( data $ prices ,
periodicity = 'months' , lookback.len = 24 ,
min.risk.fns = list (
EW = equal.weight.portfolio ,
RP = risk.parity.portfolio (),
MD = max.div.portfolio ,
MV = min.var.portfolio ,
MVE = min.var.excel.portfolio ,
MO = target.omega.portfolio ( 0 / 100 , 'lp' ),
MC = min.corr.portfolio ,
MCE = min.corr.excel.portfolio ,
MC2 = min.corr2.portfolio ,
MS = max.sharpe.portfolio ()
),
silent = T
)
models = create.strategies ( obj , data , dates = '1997::' , commission = commission , silent = T ) $ models
#*****************************************************************
# Create Report
#*****************************************************************
#strategy.performance.snapshoot(models, T)
plotbt ( models , plotX = T , log = 'y' , LeftMargin = 3 , main = NULL )
mtext ( 'Cumulative Performance' , side = 2 , line = 1 )
print ( plotbt.strategy.sidebyside ( models , make.plot = F , return.table = T , perfromance.fn = engineering.returns.kpi ))
EW
RP
MD
MV
MVE
MO
MC
MCE
MC2
MS
Period
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Jan1997 - Apr2015
Cagr
5.71
3.63
2.73
2.74
2.68
3.29
3.28
3.28
3.47
3.38
Sharpe
0.66
1.05
0.96
1.47
1.25
1.13
1.06
1.03
1.09
1.1
DVR
0.61
0.99
0.9
1.34
1.16
1.07
0.98
0.96
1.02
1.03
R2
0.93
0.94
0.94
0.91
0.93
0.94
0.93
0.93
0.93
0.94
Volatility
8.97
3.44
2.83
1.84
2.12
2.88
3.08
3.15
3.16
3.06
MaxDD
-37.17
-12.8
-7.54
-3.17
-2.59
-3.22
-6.56
-6.54
-9.92
-3.38
Exposure
91.82
91.82
91.82
91.82
91.82
91.82
91.82
91.82
91.82
91.82
(this report was produced on: 2015-04-10)