Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/paper_analysis/R_interpretation/performanceanalysis.R
1433 views
1
2
# ----------------------------------------------------------------------------------
3
# In this script the out-of-sample returns of the optimized portfolios is analyzed
4
#
5
# ----------------------------------------------------------------------------------
6
7
setwd("c:/Documents and Settings/Administrator/Desktop/risk budget programs")
8
9
# Optimized portfolio you want to analyse out-of-sample performance through (Component) Sharpe ratios
10
11
12
estyears = 8;
13
frequency = "quarterly" ;yearly = F;
14
CC = TRUE
15
# Load additional programs to interpret the data
16
17
library(zoo); library("PerformanceAnalytics"); source("R_interpretation/pfolioreturn.R");
18
library(reldist) ; library(sandwich); library(zoo);
19
source("R_Allocation/estimators.R")
20
histVaR = function( series ){ return(-quantile(series,probs=0.05) ) }
21
histCVaR = function( series ){ series = as.numeric(series) ; q = as.numeric(histVaR(series)) ; return( -mean( series[series<(-q)] )) }
22
23
# Define optimization criteria
24
25
names = c( "EqualWeight" , "MinRisk" , "MinRisk_PositionLimit" , "MinRisk_RiskLimit" ,
26
"MinRiskConc" , "MinRiskConc_PositionLimit", "EqualRisk" ,
27
"MinRisk_ReturnTarget", "MinRiskConc_ReturnTarget" )
28
if(CC){ names= paste( names, "_CC", sep="") }
29
30
namelabels = c( "Equal Weight" , "Min CVaR" , "Min CVaR + Position Limit" , "Min CVaR + CVaR Alloc Limit" ,
31
"Min CVaR Conc" , "Min CVaR Conc + 40% Position Limit", "Min CVaR + ERC constraint" , "Min CVaR + Return Target" , "Min CVaR Conc + Return Target" )
32
33
sel = c(1,2:4,7,5:6)
34
names = names[sel]; namelabels = namelabels[sel];
35
36
37
####################################################################
38
39
for( mincriterion in c( "mES" , "StdDev" ) ){
40
41
criteria = paste( rep("weights/",length(names) ) , rep(mincriterion,length(names) ) , "/", names , sep="")
42
criteria[ criteria == "weights/StdDev/EqualWeight" ] = "weights/mES/EqualWeight"
43
44
# Load the data
45
firstyear = 1976 ; firstquarter = 1; lastyear = 2010; lastquarter = 2;
46
data = read.table( file= paste("data/","data.txt",sep="") ,header=T)
47
date = as.Date(data[,1],format="%Y-%m-%d")
48
49
nominalreturns = T;
50
if(nominalreturns){ monthlyR = zoo( data[,2:ncol(data)] , order.by = date ) }else{
51
monthlyR = zoo( data[,2:(ncol(data)-1)] , order.by = date ) - zoo( data[,ncol(data)] , order.by = date )
52
}
53
monthlyR = monthlyR[,1:4]
54
55
# Define rebalancing periods:
56
57
ep = endpoints(monthlyR,on='quarters')
58
# select those for estimation period
59
ep.start = ep[(1+estyears*4):(length(ep)-1)]+1
60
from = time(monthlyR)[ep.start]
61
from = seq( as.Date( paste( as.character(firstyear+estyears),"-01-01",sep="")), as.Date("2010-04-01"), by="3 month")
62
ep.end = ep[(1+estyears*4):(length(ep)-1)]+3
63
to = time(monthlyR)[ep.end]
64
65
# Compute daily out of sample returns, accounting for compounding effects
66
67
Returns.rebalancing( R = monthlyR , criteria = criteria, from = from, to = to , folder="/oosreturns/" )
68
oosdates = time( window (monthlyR , start = from[1] , end = to[ length(to) ] ) )
69
70
load(paste(getwd(),"/oosreturns/", "simplereturns",".Rdata" ,sep="") )
71
save(simplereturns, file=paste(getwd(),"/","/oosreturns/", "simplereturns_",mincriterion ,".Rdata" ,sep="") )
72
}
73
74
############################################################################################################################
75
76
77
# Bear periods
78
sp500 = window (monthlyR , start = from[1] , end = to[ length(to) ] )[,2]
79
bear = c(1:length(sp500))[sp500<mean(sp500)]
80
bear = c(1:length(sp500))[sp500<(-0.12)]
81
m.bear.dates = list();
82
i=1;
83
for( b in bear){
84
m.bear.dates[[i]] = c( b-0.5, b+0.5)
85
i = i + 1;
86
}
87
88
# http://www.aheadofthecurve-thebook.com/charts.html
89
# Vertical yellow bars in most charts denote bear markets (declines in the S&P 500 Index of 12% or more).
90
# IMPORTANT: The leading edge (left side) of the vertical yellow bars are thus stock market peaks,
91
# and the trailing edge (right side) are stock market troughs.
92
93
#source( paste(getwd(),"/R_interpretation/findDrawdowns.R",sep="") )
94
out = table.Drawdowns(sp500,top=10)
95
start.bear = out$From[out$Depth<(-0.12)]
96
end.bear = out$Trough[out$Depth<(-0.12)]
97
start.bear.index = c(1:length(sp500))[ time(sp500) ]
98
m.bear.dates = list()
99
v.bear.dates = c()
100
for( i in 1:length(start.bear) ){
101
m.bear.dates[[i]] = c( as.yearmon(start.bear[i]) , as.yearmon(end.bear[i]) )
102
v.bear.dates = c( v.bear.dates , seq(start.bear[i],end.bear[i],"days") )
103
}
104
v.bear.dates = as.Date( v.bear.dates )
105
106
# Mean, Standard Deviation, CVaR
107
histVaR = function( series ){ return(-quantile(series,probs=0.05) ) }
108
histCVaR = function( series ){ series = as.numeric(series) ; q = as.numeric(histVaR(series)) ; return( -mean( series[series<(-q)] )) }
109
110
############################################################################################################################
111
112
mincriterion = "StdDev" # "mES" , "StdDev"
113
load(paste(getwd(),"/","/oosreturns/", "simplereturns_",mincriterion ,".Rdata" ,sep="") )
114
115
criteria = paste( rep("weights/",length(names) ) , rep(mincriterion,length(names) ) , "/", names , sep="")
116
criteria[ criteria == "weights/StdDev/EqualWeight" ] = "weights/mES/EqualWeight"
117
118
colnames(simplereturns) = names
119
date = time(simplereturns)
120
121
makeChart = FALSE
122
123
if(makeChart){
124
# Chart of relative performance strategies vs Equal-Weight
125
if(CC){
126
postscript( file="RelPerf_EW_CC.eps" )
127
}else{
128
postscript( file="RelPerf_EW.eps" )
129
}
130
# zelf opslaan anders worden de cijfers niet gedraaid in de y-as
131
par( mfrow = c(2,1) , mar =c(2,5,2,2), cex.axis = 0.7 , cex.main=0.7 )
132
# EqualWeight, MinCVaR, MinCVaRConcentration
133
chart.RelativePerformance( simplereturns[,c(2,3,4)] , simplereturns[,c(1)] ,
134
main = "" , lty=c("solid","solid","solid") , ylab="Relative performance vs equal-weight", xlab="",
135
col=c("black","darkgray","darkgray") , las=1, lwd=c(2,2,5) ,
136
auto.grid = TRUE, minor.ticks = FALSE ,ylim=c(0.7,1.65),
137
period.areas = m.bear.dates , period.color="lightgray",
138
date.format.in = "%Y-%m-%d",date.format = "%b %Y")
139
legend("topleft", legend = c("Min CVaR","Min CVaR + 40% Position Limit", "Min CVaR + 40% Risk Allocation Limit"),
140
col=c("black","darkgray","darkgray"), lty=c("solid","solid","solid"), lwd=c(2,2,5) ,cex=0.7)
141
142
chart.RelativePerformance( simplereturns[,c(5,6,7)] , simplereturns[,c(1)] ,
143
main = "" , lty=c("solid","solid","solid") , ylab="Relative performance vs equal-weight",
144
col=c("black","darkgray","darkgray") , lwd=c(2,2,5), las=1 ,
145
auto.grid = TRUE, minor.ticks = FALSE , ylim=c(0.7,1.65),
146
period.areas = m.bear.dates , period.color="lightgray",
147
date.format.in = "%Y-%m-%d",date.format = "%b %Y")
148
149
legend("topleft", legend = c("Min CVaR Concentration","Min CVaR Concentration + 40% Position Limit", "Min CVaR + ERC constraint"),
150
col=c("black","darkgray","darkgray"), lty=c("solid","solid","solid"), lwd=c(2,2,5) ,cex=0.7)
151
dev.off()
152
}
153
154
# Table of summary statistics on out-of-sample returns
155
156
library(PerformanceAnalytics)
157
library(zoo)
158
oosreturns = zoo(simplereturns[,c(1:length(names))],order.by = seq.Date(as.Date(from[1])+31, as.Date(tail(to,1)) + 1, by ="month") - 1)
159
160
v.nobear.dates = as.Date(setdiff( time(oosreturns) , v.bear.dates ))
161
162
oosreturns = window(oosreturns , start=as.Date("1984-01-01") , end=tail(time(oosreturns),1) )
163
Tstart = 1+(8-estyears)*4
164
#Tstart = 1
165
166
out_full = out_bear = out_bull = c()
167
168
print("Full period") #median, skew; exkur; histVaR
169
out_full = rbind( out_full , apply( oosreturns , 2 , 'mean' )*100*12 ) ;
170
out_full = rbind( out_full , apply( oosreturns , 2 , 'sd' )*100*sqrt(12))
171
out_full = rbind( out_full , apply( oosreturns , 2 , 'skewness' ))
172
out_full = rbind( out_full , apply( oosreturns , 2 , 'kurtosis' ))
173
out_full = rbind( out_full , 100*apply( oosreturns , 2 , 'histCVaR'))
174
#out_full = rbind( out_full , -100*apply( oosreturns , 2 , 'ES') )
175
176
oosreturns_bear = oosreturns[ v.bear.dates ]; oosreturns_bull = oosreturns[ v.nobear.dates ]
177
178
print("Bear market")
179
out_bear = rbind( out_bear , apply( oosreturns_bear , 2 , 'mean' )*100*12);
180
out_bear = rbind( out_bear , apply( oosreturns_bear , 2 , 'sd' )*100*sqrt(12))
181
out_bear = rbind( out_bear , apply( oosreturns_bear , 2 , 'skewness' ))
182
out_bear = rbind( out_bear , apply( oosreturns_bear , 2 , 'kurtosis' ))
183
out_bear = rbind( out_bear , 100*apply( oosreturns_bear , 2 , 'histCVaR'))
184
#out_bear = rbind( out_bear , -100*apply( oosreturns_bear , 2 , 'ES'))
185
186
print("Bull market")
187
out_bull = rbind( out_bull , apply( oosreturns_bull , 2 , 'mean' )*100*12 ) ;
188
out_bull = rbind( out_bull , apply( oosreturns_bull , 2 , 'sd' )*100*sqrt(12))
189
out_bull = rbind( out_bull , apply( oosreturns_bull , 2 , 'skewness' ))
190
out_bull = rbind( out_bull , apply( oosreturns_bull , 2 , 'kurtosis' ))
191
out_bull = rbind( out_bull , 100*apply( oosreturns_bull , 2 , 'histCVaR'))
192
#out_bull = rbind( out_bull , -100*apply( oosreturns_bull , 2 , 'ES'))
193
194
# Portfolio turnover per strategy:
195
196
pfgini = c();
197
turnover = c();
198
199
# Compute for each rebalancing period, the cumulative return:
200
201
cumR = c()
202
oosR = window (monthlyR , start = from[1] , end = to[ length(to) ] )
203
cRebalancing = length(from)
204
205
for( i in 1:cRebalancing ){
206
sel = seq( (i-1)*3+1 , i*3 )
207
cumR = rbind( cumR , apply((1+oosR[sel,]),2,'cumprod')[3,] )
208
}
209
210
# Load portfolio weights:
211
212
for( strat in 1:length(criteria) ){
213
criterion = criteria[strat];
214
wstart = read.csv( file = paste( criterion,".csv",sep=""),header = TRUE, sep = ",", na.strings = "NA", dec = ".")
215
wend = (wstart[Tstart:cRebalancing,]*cumR)/rowSums( wstart[Tstart:cRebalancing,]*cumR )
216
# out = (1/nrow(wstart))*sum( abs( wstart[(Tstart+1):cRebalancing,]-wend[Tstart:(cRebalancing-1),] ))
217
out = rowSums( abs( wstart[(Tstart+1):cRebalancing,]-wend[Tstart:(cRebalancing-1),] ))
218
turnover = cbind( turnover , out )
219
pfgini = c( pfgini , mean(apply( wstart, 1 , 'gini' )) )
220
}
221
222
pfturnover = colMeans( turnover )
223
out_full = rbind( out_full , pfgini , pfturnover*100 )
224
225
library(xtable)
226
xtable(out_full); xtable(out_bear); xtable(out_bull)
227
228
save( turnover , file=paste(getwd(),"/","/oosreturns/", "turnover_" , mincriterion ,".Rdata" ,sep="") )
229
230
# DRAWDOWNS
231
232
for( i in 1:length(criteria) ){ # Print the drawdowns
233
print( namelabels[i] )
234
out = table.Drawdowns(oosreturns[,i],top=10)
235
out = out[out$Depth<=(-0.1),]
236
print( out )
237
}
238
239
# Risk concentration
240
241
outnumber = outloss = outriskconc = c();
242
243
for( strat in 1:length(criteria) ){
244
criterion = criteria[strat];
245
#print( criterion );
246
weightedR = c(); portfolioVaR = c();
247
weights = read.csv( file = paste( criterion,".csv",sep=""),header = TRUE, sep = ",", na.strings = "NA", dec = ".")
248
249
# Step 1: compute for each optimal weight the corresponding historical quantile
250
251
for (row in 1:length(from)){
252
# For the determination of the historical quantile all returns preceding the rebalancing period are taken
253
previousR = window(monthlyR, start = time(monthlyR)[1] , end = as.Date(from[row]-1)) ;
254
pfoosR = rowSums( matrix( rep( as.numeric(weights[row,]),nrow(previousR)) , nrow = nrow(previousR) )*previousR )
255
# The weighted returns need the returns of the rebalancing period
256
Rrebalperiod = window(monthlyR, start = as.Date(from[row]) , end = as.Date(to[row])) ;
257
weightedR = rbind( weightedR , matrix( rep( as.numeric(weights[row,]),nrow(Rrebalperiod)) , nrow = nrow(Rrebalperiod) )*Rrebalperiod );
258
portfolioVaR = c( portfolioVaR , histVaR( pfoosR ) ) ;
259
}
260
261
# Step 2: compute the mean squared weighted return over months with beyond VaR losses
262
263
series = rowSums(weightedR) ;
264
#out = mean(weightedR[series<(-portfolioVaR),]^2);
265
downsidelosses = weightedR[series<(-portfolioVaR),]
266
#downsidelosses = weightedR[series<=-0.10,]
267
vES = rowSums(downsidelosses)
268
269
outnumber = c( outnumber , nrow(downsidelosses) )
270
#print("Total portfolio loss")
271
out = apply( -downsidelosses , 1 , 'sum')
272
outloss = cbind( outloss , c( median(out) , max(out) ) )
273
#print("Max percentage loss")
274
out = apply( downsidelosses/ apply( downsidelosses , 1 , 'sum') , 1 , 'max')
275
# outriskconc = cbind( outriskconc , c( median(out) , max(out) ) )
276
outriskconc = cbind( outriskconc , c( mean(out) , max(out) ) )
277
}
278
279
outnumber
280
xtable(outloss)
281
xtable(outriskconc)
282
283
284
############################################################################################################################
285
286
# Test significance of difference
287
288
mincriterion = "mES"
289
load(paste(getwd(),"/","/oosreturns/", "simplereturns_",mincriterion ,".Rdata" ,sep="") )
290
mES_simplereturns = simplereturns
291
colnames(mES_simplereturns) = names ; date = time(mES_simplereturns)
292
293
mincriterion = "StdDev"
294
load(paste(getwd(),"/","/oosreturns/", "simplereturns_",mincriterion ,".Rdata" ,sep="") )
295
StdDev_simplereturns = simplereturns
296
colnames(StdDev_simplereturns) = names ; date = time(StdDev_simplereturns)
297
298
#
299
300
301
for( col in 2:ncol(simplereturns) ){
302
rdata = cbind( StdDev_simplereturns[,col] , mES_simplereturns[,col])
303
colnames( rdata ) = c( "y" , "x" )
304
fm = lm( y~x , data =rdata )
305
tstat = fm$coef[1]/sqrt(NeweyWest( fm )[1,1])
306
print( (1-pnorm( abs(tstat) ))*2 )
307
}
308
309
for( col in 2:ncol(simplereturns) ){
310
rdata = cbind( StdDev_simplereturns[,col] , mES_simplereturns[,col])
311
colnames( rdata ) = c( "y" , "x" )
312
fm = lm( y^2~x^2 , data =rdata )
313
tstat = fm$coef[1]/sqrt(NeweyWest( fm )[1,1])
314
print( (1-pnorm( abs(tstat) ))*2 )
315
}
316
317
source("R_interpretation/Sharpe_functions_Wolf.R")
318
319
for( col in 2:ncol(simplereturns) ){
320
out = hac.inference(ret = cbind( as.numeric(StdDev_simplereturns[,col]) , as.numeric(mES_simplereturns[,col])) )$p.Values
321
print(out)
322
}
323
324
325
326
327