Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/script.UW2012.R
1433 views
1
### For R/Finance workshop on Portfolio Analytics
2
# Chicago, 10 May 2012
3
# Peter Carl and Brian Peterson
4
5
### Load the necessary packages
6
# Include optimizer and multi-core packages
7
library(PortfolioAnalytics)
8
require(quantmod)
9
require(DEoptim)
10
require(foreach)
11
require(doMC)
12
registerDoMC(3)
13
require(TTR)
14
# Available on r-forge
15
require(FactorAnalytics) # development version > build
16
require(vcd) # for color palates
17
18
### Set up color palates
19
pal <- function(col, border = "light gray", ...){
20
n <- length(col)
21
plot(0, 0, type="n", xlim = c(0, 1), ylim = c(0, 1),
22
axes = FALSE, xlab = "", ylab = "", ...)
23
rect(0:(n-1)/n, 0, 1:n/n, 1, col = col, border = border)
24
}
25
# Use dark8equal for now?
26
27
# Qualitative color scheme by Paul Tol
28
tol1qualitative=c("#4477AA")
29
tol2qualitative=c("#4477AA", "#CC6677")
30
tol3qualitative=c("#4477AA", "#DDCC77", "#CC6677")
31
tol4qualitative=c("#4477AA", "#117733", "#DDCC77", "#CC6677")
32
tol5qualitative=c("#332288", "#88CCEE", "#117733", "#DDCC77", "#CC6677")
33
tol6qualitative=c("#332288", "#88CCEE", "#117733", "#DDCC77", "#CC6677","#AA4499")
34
tol7qualitative=c("#332288", "#88CCEE", "#44AA99", "#117733", "#DDCC77", "#CC6677","#AA4499")
35
tol8qualitative=c("#332288", "#88CCEE", "#44AA99", "#117733", "#999933", "#DDCC77", "#CC6677","#AA4499")
36
tol9qualitative=c("#332288", "#88CCEE", "#44AA99", "#117733", "#999933", "#DDCC77", "#CC6677", "#882255", "#AA4499")
37
tol10qualitative=c("#332288", "#88CCEE", "#44AA99", "#117733", "#999933", "#DDCC77", "#661100", "#CC6677", "#882255", "#AA4499")
38
39
####### Script WBS
40
# Parse data from EDHEC or HFRI
41
## Just load the data from packages
42
### See script.buildEDHEC.R and script.buildFactors.R
43
data(edhec)
44
# data(factors)
45
46
47
## Which styles?
48
### Relative value
49
#### FIA
50
#### Converts
51
#### EMN
52
#### Event driven
53
### Directional
54
#### US Eq LS
55
#### Macro
56
#### CTA
57
#### Distressed
58
59
# Drop some indexes and reorder
60
edhec.R = edhec[,c("Convertible Arbitrage", "Equity Market Neutral","Fixed Income Arbitrage", "Event Driven", "CTA Global", "Global Macro", "Long/Short Equity")]
61
62
########################################################################
63
# Performance analysis of EDHEC hedge fund indexes
64
########################################################################
65
# --------------------------------------------------------------------
66
# EDHEC Indexes Returns through time
67
# --------------------------------------------------------------------
68
#postscript(file="EDHEC-Cumulative-Returns.pdf", height=6, width=10, paper="special", horizontal=FALSE, onefile=FALSE)
69
png(filename="EDHEC-Cumulative-Returns.png", units="in", height=5.5, width=9, res=96)
70
par(cex.lab=.8) # should set these parameters once at the top
71
op <- par(no.readonly = TRUE)
72
layout(matrix(c(1, 2)), height = c(2, 1.3), width = 1)
73
par(mar = c(1, 4, 1, 2)) #c(bottom, left, top, right)
74
chart.CumReturns(edhec.R, main = "", xaxis = FALSE, legend.loc = "topleft", ylab = "Cumulative Return", colorset= rainbow8equal, ylog=TRUE, wealth.index=TRUE, cex.legend=.7, cex.axis=.6, cex.lab=.7)
75
par(mar = c(4, 4, 0, 2))
76
chart.Drawdown(edhec.R, main = "", ylab = "Drawdown", colorset = rainbow8equal, cex.axis=.6, cex.lab=.7)
77
par(op)
78
dev.off()
79
80
# --------------------------------------------------------------------
81
# EDHEC Indexes Risk
82
# --------------------------------------------------------------------
83
# postscript(file="EDHEC-BarVaR.eps", height=6, width=5, paper="special", horizontal=FALSE, onefile=FALSE)
84
png(filename="EDHEC-BarVaR.png", units="in", height=5.5, width=9, res=96)
85
# Generate charts of EDHEC index returns with ETL and VaR through time
86
par(mar=c(3, 4, 0, 2) + 0.1) #c(bottom, left, top, right)
87
# charts.BarVaR(edhec.R, p=(1-1/12), gap=36, main="", clean='boudt', show.cleaned=TRUE, show.greenredbars=TRUE, methods=c("ModifiedES", "ModifiedVaR"), show.endvalue=TRUE, colorset=rainbow8equal)
88
89
charts.BarVaR(edhec.R, p=(1-1/12), gap=36, main="", show.greenredbars=TRUE,
90
methods=c("ModifiedES", "ModifiedVaR"), show.endvalue=TRUE,
91
colorset=rep("Black",7), ylim=c(-.1,.15))
92
93
# charts.BarVaR(edhec.R, p=(1-1/12), gap=36, main="", show.greenredbars=TRUE, methods=c("ModifiedES", "ModifiedVaR"), show.endvalue=TRUE, colorset=rainbow8equal)
94
par(op)
95
dev.off()
96
97
# --------------------------------------------------------------------
98
# EDHEC Indexes Rolling Performance
99
# --------------------------------------------------------------------
100
png(filename="EDHEC-RollPerf.png", units="in", height=5.5, width=9, res=96)
101
# Generate charts of EDHEC index returns with ETL and VaR through time
102
par(mar=c(5, 4, 0, 2) + 0.1) #c(bottom, left, top, right)
103
charts.RollingPerformance(edhec.R, width=36, main="", colorset=rainbow8equal, legend.loc="topleft")
104
par(op)
105
dev.off()
106
107
# --------------------------------------------------------------------
108
# EDHEC Indexes Returns and Risk Scatter
109
# --------------------------------------------------------------------
110
png(filename="EDHEC-Scatter36m.png", units="in", height=5.5, width=4.5, res=96)
111
chart.RiskReturnScatter(last(edhec.R,36), main="EDHEC Index Trailing 36-Month Performance", colorset=rainbow8equal, ylim=c(0,.2), xlim=c(0,.12))
112
dev.off()
113
png(filename="EDHEC-ScatterSinceIncept.png", units="in", height=5.5, width=4.5, res=96)
114
chart.RiskReturnScatter(edhec.R, main="EDHEC Index Since Inception Performance", colorset=rainbow8equal, ylim=c(0,.2), xlim=c(0,.12))
115
dev.off()
116
117
# --------------------------------------------------------------------
118
## EDHEC Indexes Table of Return and Risk Statistics
119
# --------------------------------------------------------------------
120
require(Hmisc)
121
incept.stats = t(table.RiskStats(R=edhec.R, p=p, Rf=.03/12))
122
write.csv(incept.stats, file="inception-stats.csv")
123
png(filename="EDHEC-InceptionStats.png", units="in", height=5.5, width=9, res=96)
124
textplot(format.df(incept.stats, na.blank=TRUE, numeric.dollar=FALSE, cdec=c(3,3,1,3,1,3,3,1,3,3,1,1,3,3,1,0), rmar = 0.8, cmar = 1, max.cex=.9, halign = "center", valign = "top", row.valign="center", wrap.rownames=20, wrap.colnames=10, mar = c(0,0,4,0)+0.1))
125
dev.off()
126
# --------------------------------------------------------------------
127
## EDHEC Indexes Distributions
128
# --------------------------------------------------------------------
129
130
png(filename="EDHEC-Distributions.png", units="in", height=5.5, width=9, res=96)
131
op <- par(no.readonly = TRUE)
132
# c(bottom, left, top, right)
133
par(oma = c(5,0,2,1), mar=c(0,0,0,3))
134
layout(matrix(1:28, ncol=4, byrow=TRUE), widths=rep(c(.6,1,1,1),7))
135
# layout.show(n=21)
136
chart.mins=min(edhec.R)
137
chart.maxs=max(edhec.R)
138
row.names = sapply(colnames(RND.weights), function(x) paste(strwrap(x,10), collapse = "\n"), USE.NAMES=FALSE)
139
for(i in 1:7){
140
if(i==7){
141
plot.new()
142
text(x=1, y=0.5, adj=c(1,0.5), labels=row.names[i], cex=1.1)
143
chart.Histogram(edhec.R[,i], main="", xlim=c(chart.mins, chart.maxs), breaks=seq(-0.15,0.10, by=0.01), show.outliers=TRUE, methods=c("add.normal"))
144
abline(v=0, col="darkgray", lty=2)
145
chart.QQPlot(edhec.R[,i], main="", pch="*", envelope=0.95, col=c(1,"#005AFF"), ylim=c(chart.mins, chart.maxs))
146
abline(v=0, col="darkgray", lty=2)
147
chart.ECDF(edhec.R[,i], main="", xlim=c(chart.mins, chart.maxs), lwd=2)
148
abline(v=0, col="darkgray", lty=2)
149
}
150
else{
151
plot.new()
152
text(x=1, y=0.5, adj=c(1,0.5), labels=row.names[i], cex=1.1)
153
chart.Histogram(edhec.R[,i], main="", xlim=c(chart.mins, chart.maxs), breaks=seq(-0.15,0.10, by=0.01), xaxis=FALSE, yaxis=FALSE, show.outliers=TRUE, methods=c("add.normal"))
154
abline(v=0, col="darkgray", lty=2)
155
chart.QQPlot(edhec.R[,i], main="", xaxis=FALSE, yaxis=FALSE, pch="*", envelope=0.95, col=c(1,"#005AFF"), ylim=c(chart.mins, chart.maxs))
156
abline(v=0, col="darkgray", lty=2)
157
chart.ECDF(edhec.R[,i], main="", xlim=c(chart.mins, chart.maxs), xaxis=FALSE, yaxis=FALSE, lwd=2)
158
abline(v=0, col="darkgray", lty=2)
159
}
160
}
161
par(op)
162
dev.off()
163
164
# --------------------------------------------------------------------
165
# Correlation
166
# --------------------------------------------------------------------
167
require("corrplot")
168
col3 <- colorRampPalette(c("darkgreen", "white", "darkred"))
169
M <- cor(edhec.R)
170
colnames(M) = rownames(M) = row.names
171
order.hc2 <- corrMatOrder(M, order="hclust", hclust.method="complete")
172
M.hc2 <- M[order.hc2,order.hc2]
173
png(filename="EDHEC-cor-inception.png", units="in", height=5.5, width=4.5, res=96)
174
corrplot(M.hc2, tl.col="black", tl.cex=0.8, method="square", col=col3(8), cl.offset=.75, cl.cex=.7, cl.align.text="l", cl.ratio=.25)
175
corrRect.hclust(M.hc2, k=3, method="complete", col="blue")
176
dev.off()
177
178
M36 <- cor(last(edhec.R,36))
179
colnames(M36) = rownames(M36) = row.names
180
order36.hc2 <- corrMatOrder(M36, order="hclust", hclust.method="complete")
181
M36.hc2 <- M36[order36.hc2,order36.hc2]
182
png(filename="EDHEC-cor-tr36m.png", units="in", height=5.5, width=4.5, res=96)
183
corrplot(M36.hc2, tl.col="black", tl.cex=0.8, method="square", col=col3(8), cl.offset=.75, cl.cex=.7, cl.align.text="l", cl.ratio=.25)
184
corrRect.hclust(M36.hc2, k=3, method="complete", col="blue")
185
dev.off()
186
187
188
# --------------------------------------------------------------------
189
## Autocorrelation
190
# --------------------------------------------------------------------
191
# @TODO: This is frosting, do it last
192
193
runname='garch.sigma.and.mu'
194
195
#########################################################################
196
# Optimization starts here
197
########################################################################
198
199
# Set up objectives as buoys
200
## Equal contribution to
201
### Weight
202
### Variance
203
### Risk (mETL)
204
## Reward to Risk
205
### Mean-Variance
206
### Mean-mETL
207
## Minimum
208
### Variance
209
### Risk (mETL)
210
211
# Add constraints
212
## Box constraints - 5% to 30%?
213
## Rebalancing period - quarterly? annual?
214
## Turnover constraints
215
216
# Set up a starting portfolio
217
## Could use the equal weight
218
219
# Forecast returns
220
## Start with pamean but don't use it in the presentation
221
### Create a small weighted annualized trailing-period mean wrapper function
222
pamean <- function(n=12, R, weights, geometric=TRUE)
223
{ as.vector(sum(Return.annualized(last(R,n), geometric=geometric)*weights)) }
224
225
pameanLCL <- function(n=36, R, weights, scale=12)
226
{ as.vector(sum( scale*mean.LCL(last(R,n))*weights)) }
227
228
paEMA <- function(n=10, R, weights, ...)
229
{# call Exponential Moving Average from TTR, return the last observation
230
sum((12*last(apply(R,2,FUN=TTR::EMA,n=n)))*weights)
231
}
232
233
pasd <- function(R, weights){
234
as.numeric(StdDev(R=R, weights=weights)*sqrt(12)) # hardcoded for monthly data
235
# as.numeric(StdDev(R=R, weights=weights)*sqrt(4)) # hardcoded for quarterly data
236
}
237
238
pasd.garch<- function(R,weights,garch.sigma,...) {
239
#sigmas is an input of predicted sigmas on a date,
240
# presumably from a GARCH model
241
as.numeric(sum((garch.sigma[last(index(R)),]*weights)*sqrt(12)))
242
}
243
244
## Apply multi-factor model
245
## Show fit
246
## ADD MORE DETAIL HERE
247
248
# Forecast risk
249
## Historical realized
250
## GARCH(1,1) for vol? if daily data available...
251
252
# Run each of the objective portfolios as of a Date - Dec2010?
253
## Combined scatter with overlaid objectives, starting portfolio
254
### Mean-variance plot
255
256
# Construct objectives for buoy portfolios
257
258
# Select a rebalance period
259
rebalance_period = 'quarters' # uses endpoints identifiers from xts
260
clean = "boudt" #"none"
261
permutations = 4000
262
263
# A set of box constraints used to initialize ALL the bouy portfolios
264
init.constr <- constraint(assets = colnames(edhec.R),
265
min = .05, # minimum position weight
266
max = .3, #1, # maximum position weight
267
min_sum=0.99, # minimum sum of weights must be equal to 1-ish
268
max_sum=1.01, # maximum sum must also be about 1
269
weight_seq = generatesequence(by=.005)
270
)
271
# Add measure 1, annualized return
272
init.constr <- add.objective(constraints=init.constr,
273
type="return", # the kind of objective this is
274
name="pamean",
275
#name="pameanLCL",
276
enabled=TRUE, # enable or disable the objective
277
multiplier=0, # calculate it but don't use it in the objective
278
arguments = list(n=60) # for monthly
279
# arguments = list(n=12) # for quarterly
280
)
281
# Add measure 2, annualized standard deviation
282
init.constr <- add.objective(init.constr,
283
type="risk", # the kind of objective this is
284
name="pasd", # to minimize from the sample
285
#name='pasd.garch', # to minimize from the predicted sigmas
286
enabled=TRUE, # enable or disable the objective
287
multiplier=0, # calculate it but don't use it in the objective
288
arguments=list() # from inception for pasd
289
#arguments=list(sigmas=garch.sigmas) # from inception for pasd.garch
290
)
291
# Add measure 3, CVaR with p=(1-1/12)
292
293
# set confidence for VaR/ES
294
p=1-1/12 # for monthly
295
#p=.25 # for quarterly
296
297
init.constr <- add.objective(init.constr,
298
type="risk", # the kind of objective this is
299
name="CVaR", # the function to minimize
300
enabled=FALSE, # enable or disable the objective
301
multiplier=0, # calculate it but don't use it in the objective
302
arguments=list(p=p),
303
clean=clean
304
)
305
306
### Construct BUOY 1: Constrained Mean-StdDev Portfolio
307
MeanSD.constr <- init.constr
308
# Turn back on the return and sd objectives
309
MeanSD.constr$objectives[[1]]$multiplier = -1 # pamean
310
MeanSD.constr$objectives[[2]]$multiplier = 1 # pasd
311
312
### Construct BUOY 2: Constrained Mean-mETL Portfolio
313
MeanmETL.constr <- init.constr
314
# Turn on the return and mETL objectives
315
MeanmETL.constr$objectives[[1]]$multiplier = -1 # pamean
316
MeanmETL.constr$objectives[[3]]$multiplier = 1 # mETL
317
MeanmETL.constr$objectives[[3]]$enabled = TRUE # mETL
318
319
### Construct BUOY 3: Constrained Minimum Variance Portfolio
320
MinSD.constr <- init.constr
321
# Turn back on the sd objectives
322
MinSD.constr$objectives[[2]]$multiplier = 1 # StdDev
323
324
### Construct BUOY 4: Constrained Minimum mETL Portfolio
325
MinmETL.constr <- init.constr
326
# Turn back on the mETL objective
327
MinmETL.constr$objectives[[3]]$multiplier = 1 # mETL
328
MinmETL.constr$objectives[[3]]$enabled = TRUE # mETL
329
330
### Construct BUOY 5: Constrained Equal Variance Contribution Portfolio
331
EqSD.constr <- add.objective(init.constr, type="risk_budget", name="StdDev", enabled=TRUE, min_concentration=TRUE, arguments = list(p=(1-1/12)))
332
# Without a sub-objective, we get a somewhat undefined result, since there are (potentially) many Equal SD contribution portfolios.
333
EqSD.constr$objectives[[2]]$multiplier = 1 # min paSD
334
EqSD.constr$objectives[[1]]$multiplier = 0 # max pamean
335
336
### Construct BUOY 6: Constrained Equal mETL Contribution Portfolio
337
EqmETL.constr <- add.objective(init.constr, type="risk_budget", name="CVaR", enabled=TRUE, min_concentration=TRUE, arguments = list(p=(1-1/12), clean=clean))
338
EqmETL.constr$objectives[[3]]$multiplier = 1 # min mETL
339
EqmETL.constr$objectives[[3]]$enabled = TRUE # min mETL
340
EqmETL.constr$objectives[[1]]$multiplier = 0 # max pamean
341
342
### Construct BUOY 7: Equal Weight Portfolio
343
# There's only one, so construct weights for it. Rebalance the equal-weight portfolio at the same frequency as the others.
344
dates=index(edhec.R[endpoints(edhec.R, on=rebalance_period)])
345
weights = xts(matrix(rep(1/NCOL(edhec.R),length(dates)*NCOL(edhec.R)), ncol=NCOL(edhec.R)), order.by=dates)
346
colnames(weights)= colnames(edhec.R)
347
348
349
### Evaluate constraint objects
350
# Generate a single set of random portfolios to evaluate against all constraint set
351
print(paste('constructing random portfolios at',Sys.time()))
352
rp = random_portfolios(rpconstraints=init.constr, permutations=permutations)
353
print(paste('done constructing random portfolios at',Sys.time()))
354
355
### Choose our 'R' variable
356
R=edhec.R # for monthlies
357
#R=edhec.R.quarterly #to use the quarterlies
358
#R=garch.mu # to use the monthly quarter-ahead predictions from the garch
359
360
start_time<-Sys.time()
361
print(paste('Starting optimization at',Sys.time()))
362
### Evaluate BUOY 1: Constrained Mean-StdDev Portfolio
363
# MeanSD.RND<-optimize.portfolio(R=R,
364
# constraints=MeanSD.constr,
365
# optimize_method='random',
366
# search_size=1000, trace=TRUE, verbose=TRUE,
367
# rp=rp) # use the same random portfolios generated above
368
# plot(MeanSD.RND, risk.col="pasd.pasd", return.col="mean")
369
# Evaluate the objectives through time
370
### requires PortfolioAnalytics build >= 1864
371
MeanSD.RND.t = optimize.portfolio.rebalancing(R=R,
372
constraints=MeanSD.constr,
373
optimize_method='random',
374
search_size=permutations, trace=TRUE, verbose=TRUE,
375
rp=rp, # all the same as prior
376
rebalance_on=rebalance_period, # uses xts 'endpoints'
377
trailing_periods=NULL, # calculates from inception
378
training_period=36) # starts 3 years in to the data history
379
MeanSD.w = extractWeights.rebal(MeanSD.RND.t)
380
MeanSD=Return.rebalancing(edhec.R, MeanSD.w)
381
colnames(MeanSD) = "MeanSD"
382
save(MeanSD.RND.t,MeanSD.w,MeanSD,file=paste('MeanSD',Sys.Date(),runname,'rda',sep='.'))
383
384
print(paste('Completed meanSD optimization at',Sys.time(),'moving on to meanmETL'))
385
386
### Evaluate BUOY 2: Constrained Mean-mETL Portfolio
387
# MeanmETL.RND<-optimize.portfolio(R=R,
388
# constraints=MeanmETL.constr,
389
# optimize_method='random',
390
# search_size=1000, trace=TRUE, verbose=TRUE,
391
# rp=rp) # use the same random portfolios generated above
392
# plot(MeanmETL.RND, risk.col="pasd.pasd", return.col="mean")
393
# Evaluate the objectives with RP through time
394
MeanmETL.RND.t = optimize.portfolio.rebalancing(R=R,
395
constraints=MeanmETL.constr,
396
optimize_method='random',
397
search_size=permutations, trace=TRUE, verbose=TRUE,
398
rp=rp, # all the same as prior
399
rebalance_on=rebalance_period, # uses xts 'endpoints'
400
trailing_periods=NULL, # calculates from inception
401
training_period=36) # starts 3 years in to the data history
402
MeanmETL.w = extractWeights.rebal(MeanmETL.RND.t)
403
MeanmETL=Return.rebalancing(edhec.R, MeanmETL.w)
404
colnames(MeanmETL) = "MeanmETL"
405
save(MeanmETL.RND.t,MeanmETL.w,MeanmETL,file=paste('MeanmETL',Sys.Date(),runname,'rda',sep='.'))
406
print(paste('Completed meanmETL optimization at',Sys.time(),'moving on to MinSD'))
407
408
### Evaluate BUOY 3: Constrained Minimum Variance Portfolio
409
# MinSD.RND<-optimize.portfolio(R=R,
410
# constraints=MinSD.constr,
411
# optimize_method='random',
412
# search_size=1000, trace=TRUE, verbose=TRUE,
413
# rp=rp) # use the same random portfolios generated above
414
# plot(MinSD.RND, risk.col="pasd.pasd", return.col="mean")
415
# Evaluate the objectives with RP through time
416
MinSD.RND.t = optimize.portfolio.rebalancing(R=R,
417
constraints=MinSD.constr,
418
optimize_method='random',
419
search_size=permutations, trace=TRUE, verbose=TRUE,
420
rp=rp, # all the same as prior
421
rebalance_on=rebalance_period, # uses xts 'endpoints'
422
trailing_periods=NULL, # calculates from inception
423
training_period=36) # starts 3 years in to the data history
424
MinSD.w = extractWeights.rebal(MinSD.RND.t)
425
MinSD=Return.rebalancing(edhec.R, MinSD.w)
426
colnames(MinSD) = "MinSD"
427
save(MinSD.RND.t,MinSD.w,MinSD,file=paste('MinSD',Sys.Date(),runname,'rda',sep='.'))
428
print(paste('Completed MinSD optimization at',Sys.time(),'moving on to MinmETL'))
429
430
### Evaluate BUOY 4: Constrained Minimum mETL Portfolio
431
# MinmETL.RND<-optimize.portfolio(R=R,
432
# constraints=MinmETL.constr,
433
# optimize_method='random',
434
# search_size=1000, trace=TRUE, verbose=TRUE,
435
# rp=rp) # use the same random portfolios generated above
436
# plot(MinmETL.RND, risk.col="pasd.pasd", return.col="mean")
437
# Evaluate the objectives with RP through time
438
MinmETL.RND.t = optimize.portfolio.rebalancing(R=R,
439
constraints=MinmETL.constr,
440
optimize_method='random',
441
search_size=permutations, trace=TRUE, verbose=TRUE,
442
rp=rp, # all the same as prior
443
rebalance_on=rebalance_period, # uses xts 'endpoints'
444
trailing_periods=NULL, # calculates from inception
445
training_period=36) # starts 3 years in to the data history
446
MinmETL.w = extractWeights.rebal(MinmETL.RND.t)
447
MinmETL=Return.rebalancing(edhec.R, MinmETL.w)
448
colnames(MinmETL) = "MinmETL"
449
save(MinmETL.RND.t,MinmETL.w,MinmETL,file=paste('MinmETL',Sys.Date(),runname,'rda',sep='.'))
450
print(paste('Completed MinmETL optimization at',Sys.time(),'moving on to EqSD'))
451
452
### Evaluate BUOY 5: Constrained Equal Variance Contribution Portfolio
453
# EqSD.RND<-optimize.portfolio(R=R,
454
# constraints=EqSD.constr,
455
# optimize_method='random',
456
# search_size=1000, trace=TRUE, verbose=TRUE,
457
# rp=rp) # use the same random portfolios generated above
458
# plot(EqSD.RND, risk.col="pasd.pasd", return.col="mean")
459
EqSD.RND.t = optimize.portfolio.rebalancing(R=R,
460
constraints=EqSD.constr,
461
optimize_method='random',
462
search_size=permutations, trace=TRUE, verbose=TRUE,
463
rp=rp, # all the same as prior
464
rebalance_on=rebalance_period, # uses xts 'endpoints'
465
trailing_periods=NULL, # calculates from inception
466
training_period=36) # starts 3 years in to the data history
467
EqSD.w = extractWeights.rebal(EqSD.RND.t)
468
EqSD=Return.rebalancing(edhec.R, EqSD.w)
469
colnames(EqSD) = "EqSD"
470
save(EqSD.RND.t,EqSD.w,EqSD,file=paste('EqSD',Sys.Date(),runname,'rda',sep='.'))
471
print(paste('Completed EqSD optimization at',Sys.time(),'moving on to EqmETL'))
472
473
### Evaluate BUOY 6: Constrained Equal mETL Contribution Portfolio
474
# EqmETL.RND<-optimize.portfolio(R=R,
475
# constraints=EqmETL.constr,
476
# optimize_method='random',
477
# search_size=1000, trace=TRUE, verbose=TRUE,
478
# rp=rp) # use the same random portfolios generated above
479
EqmETL.RND.t = optimize.portfolio.rebalancing(R=R,
480
constraints=EqmETL.constr,
481
optimize_method='random',
482
search_size=permutations, trace=TRUE, verbose=TRUE,
483
rp=rp, # all the same as prior
484
rebalance_on=rebalance_period, # uses xts 'endpoints'
485
trailing_periods=NULL, # calculates from inception
486
training_period=36) # starts 3 years in to the data history
487
EqmETL.w = extractWeights.rebal(EqmETL.RND.t)
488
EqmETL=Return.rebalancing(edhec.R, EqmETL.w)
489
colnames(EqmETL) = "EqmETL"
490
save(EqmETL.RND.t,EqmETL.w,EqmETL,file=paste('EqmETL',Sys.Date(),runname,'rda',sep='.'))
491
print(paste('Completed EqmETL optimization at',Sys.time(),'moving on to EqWgt'))
492
493
### Evaluate BUOY 7: Equal Weight Portfolio
494
# There's only one, so calculate it. Rebalance the equal-weight portfolio regularly, matching the periods above
495
EqWgt = Return.rebalancing(edhec.R,weights) # requires development build of PerfA >= 1863 or CRAN version 1.0.4 or higher
496
colnames(EqWgt)="EqWgt"
497
### Performance of Buy & Hold Random Portfolios
498
#BHportfs = EqWgt
499
#for(i in 2:NROW(rp)){ #@TODO: Use foreach in this loop instead
500
# weights_i = xts(matrix(rep(rp[i,],length(dates)), ncol=NCOL(rp)), order.by=dates)
501
# tmp = Return.rebalancing(edhec.R,weights_i)
502
# BHportfs = cbind(BHportfs,tmp)
503
#}
504
BHportfs <- foreach(i=1:NROW(rp),.combine=cbind, .inorder=TRUE) %dopar% {
505
weights_i = xts(matrix(rep(rp[i,],length(dates)), ncol=NCOL(rp)), order.by=dates)
506
tmp = Return.rebalancing(edhec.R,weights_i)
507
}
508
# BHportfs <- cbind(EqWgt,BHportfs)
509
save(rp,BHportfs,EqWgt,file=paste('BHportfs',Sys.Date(),runname,'rda',sep='.'))
510
511
end_time<-Sys.time()
512
end_time-start_time
513
514
# Assemble the ex ante result data
515
516
results.obj = c("MeanSD.RND.t", "MeanmETL.RND.t", "MinSD.RND.t", "MinmETL.RND.t", "EqSD.RND.t", "EqmETL.RND.t")
517
results.names= c("Eq Wgt", "Mean SD", "Mean mETL", "Min SD", "Min mETL", "Eq SD", "Eq mETL")
518
519
results = list(EqWgt=EqWgt,
520
BHportfs=BHportfs,
521
MeanSD.RND.t=MeanSD.RND.t,
522
MeanmETL.RND.t=MeanmETL.RND.t,
523
MinSD.RND.t=MinSD.RND.t,
524
MinmETL.RND.t=MinmETL.RND.t,
525
EqSD.RND.t=EqSD.RND.t,
526
EqmETL.RND.t=EqmETL.RND.t)
527
528
529
# evalDate="2010-12-31"
530
## Extract Weights
531
evalDate="2008-06-30"
532
RND.weights = MeanSD.RND.t[[evalDate]]$random_portfolio_objective_results[[1]]$weights #EqWgt
533
for(result in results.obj){
534
x=get(result)
535
RND.weights = rbind(RND.weights,x[[evalDate]]$weights)
536
}
537
rownames(RND.weights)=results.names # @TODO: add prettier labels
538
539
#RND.weights = MeanSD.RND.t[["2010-12-31"]]$random_portfolio_objective_results[[1]]$weights #EqWgt
540
#for(result in results){
541
# RND.weights = rbind(RND.weights,result[["2010-12-31"]]$weights)
542
#}
543
#results.names= c("Eq Wgt", "Mean SD", "Mean mETL", "Min SD", "Min mETL", "Eq SD", "Eq mETL")
544
#rownames(RND.weights)=c(results.names) # @TODO: add prettier labels
545
#
546
### Extract Objective measures
547
#RND.objectives=rbind(MeanSD.RND.t[["2010-12-31"]]$random_portfolio_objective_results[[1]]$objective_measures[1:3]) #EqWgt
548
#for(result in results){
549
# RND.objectives = rbind(RND.objectives,rbind(result[["2010-12-31"]]$objective_measures[1:3]))
550
#}
551
#rownames(RND.objectives)=c("EqWgt",results) # @TODO: add prettier labels
552
save(results,file=paste(Sys.Date(),runname,'full-results','rda',sep='.'))
553
554
## Extract Objective measures
555
RND.objectives=rbind(MeanSD.RND.t[[evalDate]]$random_portfolio_objective_results[[1]]$objective_measures[1:3]) #EqWgt
556
x.obj<-NULL
557
for(result in names(results)[grep('.t',names(results),fixed=TRUE)]){
558
print(result)
559
x=get('results')[[result]]
560
x.obj=rbind(x.obj, data.frame(mean=x[[evalDate]]$objective_measures[[1]],pasd=x[[evalDate]]$objective_measures[[2]],CVaR=as.numeric(x[[evalDate]]$objective_measures[[3]][1])))
561
}
562
print(x.obj)
563
rownames(x.obj)=names(results)[grep('.t',names(results),fixed=TRUE)] # @TODO: add prettier labels
564
565
566
#****************************************************************************
567
# END main optimization section
568
#****************************************************************************
569
op <- par(no.readonly=TRUE)
570
571
# --------------------------------------------------------------------
572
# NOT USED: Chart EqWgt Results against BH RP portfolios
573
# --------------------------------------------------------------------
574
postscript(file="EqWgtBHPerfSumm.eps", height=6, width=5, paper="special", horizontal=FALSE, onefile=FALSE)
575
charts.PerformanceSummary(BHportfs, main="Equal Weight and Buy & Hold Random Portfolios", methods=c("ModifiedVaR", "ModifiedES"), p=(1-1/12), gap=36, colorset=c("orange",rep("darkgray",NCOL(BHportfs))), lwd=3, legend.loc=NA)
576
# use clean='boudt', show.cleaned=TRUE, in final version?
577
dev.off()
578
# --------------------------------------------------------------------
579
580
581
### Plot comparison of objectives and weights
582
# > names(EqmETL.RND)
583
# [1] "random_portfolios" "random_portfolio_objective_results"
584
# [3] "weights" "objective_measures"
585
# [5] "call" "constraints"
586
# [7] "data_summary" "elapsed_time"
587
# [9] "end_t"
588
589
# --------------------------------------------------------------------
590
# Plot Ex Ante scatter of RP and ONLY Equal Weight portfolio
591
# --------------------------------------------------------------------
592
xtract = extractStats(MeanSD.RND.t[[evalDate]])
593
594
png(filename="RP-EqW-ExAnte-2008-06-30.png", units="in", height=5.5, width=9, res=96)
595
par(mar=c(5, 4, 1, 2) + 0.1) #c(bottom, left, top, right)
596
plot(xtract[,"pasd.pasd"],xtract[,"pamean.pamean"], xlab="Predicted StdDev", ylab="Predicted Mean", col="darkgray", axes=FALSE, main="", cex=.7)
597
grid(col = "darkgray")
598
abline(h = 0, col = "darkgray")
599
points(RND.objectives[1,2],RND.objectives[1,1], col=tol7qualitative, pch=16, cex=1.5)
600
axis(1, cex.axis = 0.8, col = "darkgray")
601
axis(2, cex.axis = 0.8, col = "darkgray")
602
box(col = "darkgray")
603
legend("bottomright",legend=results.names[1], col=tol7qualitative, pch=16, ncol=1, border.col="darkgray", y.intersp=1.2, cex=0.8, inset=.02)
604
par(op)
605
dev.off()
606
607
# --------------------------------------------------------------------
608
# Plot Ex Ante scatter of RP and ALL BUOY portfolios
609
# --------------------------------------------------------------------
610
png(filename="Buoy-ExAnte-2008-06-30.png", units="in", height=5.5, width=9, res=96)
611
par(mar=c(5, 4, 1, 2) + 0.1) #c(bottom, left, top, right)
612
plot(xtract[,"pasd.garch.pasd.garch"],xtract[,"pamean.pamean"], xlab="Predicted StdDev", ylab="Predicted Mean", col="darkgray", axes=FALSE, main="", cex=.7)
613
grid(col = "darkgray")
614
abline(h = 0, col = "darkgray")
615
points(x.obj[,2],x.obj[,1], col=tol7qualitative, pch=16, cex=1.5)
616
axis(1, cex.axis = 0.8, col = "darkgray")
617
axis(2, cex.axis = 0.8, col = "darkgray")
618
box(col = "darkgray")
619
legend("bottomright", legend=results.names, col=tol7qualitative, pch=16, ncol=1, border.col="darkgray", y.intersp=1.2, inset=.02)
620
par(op)
621
dev.off()
622
623
# --------------------------------------------------------------------
624
# Plot weights of Buoy portfolios as of 2008-06-30
625
# --------------------------------------------------------------------
626
png(filename="Weights-ExAnte-2008-06-30.png", units="in", height=5.5, width=9, res=96)
627
par(oma = c(4,8,2,1), mar=c(0,0,0,1)) # c(bottom, left, top, right)
628
layout(matrix(c(1:7), nr = 1, byrow = TRUE))
629
row.names = sapply(colnames(RND.weights), function(x) paste(strwrap(x,10), collapse = "\n"), USE.NAMES=FALSE)
630
for(i in 1:7){
631
if(i==1){
632
barplot(RND.weights[i,], col=rainbow8equal, horiz=TRUE, xlim=c(0,max(RND.weights)), axes=FALSE, names.arg=row.names, las=2, cex.names=1.1)
633
abline(v=0, col="darkgray")
634
abline(v=1/7, col="darkgray", lty=2)
635
axis(1, cex.axis = 1, col = "darkgray", las=1)
636
mtext(rownames(RND.weights)[i], side= 3, cex=0.7, adj=0)
637
}
638
else{
639
barplot(RND.weights[i,], col=rainbow8equal, horiz=TRUE, xlim=c(0,max(RND.weights)), axes=FALSE, names.arg="", ylab=rownames(RND.weights)[i])
640
abline(v=0, col="darkgray")
641
abline(v=1/7, col="darkgray", lty=2)
642
mtext(rownames(RND.weights)[i], side= 3, cex=0.7, adj=0)
643
}
644
}
645
par(op)
646
dev.off()
647
648
# --------------------------------------------------------------------
649
# NOT USED: Plot Ex Ante scatter of buoy portfolios and weights
650
# --------------------------------------------------------------------
651
postscript(file="ExAnteScatterWeights20101231.eps", height=6, width=5, paper="special", horizontal=FALSE, onefile=FALSE)
652
op <- par(no.readonly=TRUE)
653
layout(matrix(c(1,2,3)),height=c(2,0.25,1.5),width=1)
654
par(mar=c(4,4,4,2)+.1, cex=1)
655
## Draw the Scatter chart of combined results
656
### Get the random portfolios from one of the result sets
657
# xtract = extractStats(MeanSD.RND.t[["2010-12-31"]]) # did this above
658
plot(xtract[,"pasd.pasd"],xtract[,"mean"], xlab="StdDev", ylab="Mean", col="darkgray", axes=FALSE, main="Objectives in Mean-Variance Space", cex=.7)
659
points(RND.objectives[,2],RND.objectives[,1], col=tol7qualitative, pch=16)
660
# This could easily be done in mean CVaR space as well
661
# plot(xtract[,"pasd.pasd"],xtract[,"mean"], xlab="CVaR", ylab="Mean", col="darkgray", axes=FALSE, main="Objectives in Mean-mETL Space")
662
# points(RND.objectives[,3],RND.objectives[,1], col=rainbow8equal, pch=16)
663
axis(1, cex.axis = 0.8, col = "darkgray")
664
axis(2, cex.axis = 0.8, col = "darkgray")
665
box(col = "darkgray")
666
667
# Add legend to middle panel
668
par(mar=c(0,4,0,2)+.1, cex=0.7)
669
plot.new()
670
legend("bottom",legend=rownames(RND.weights), col=tol7qualitative, pch=16, lwd=2, ncol=4, border.col="darkgray", y.intersp=1.2)
671
672
# Draw the Weights chart of the combined results
673
columnnames = colnames(RND.weights)
674
numassets = length(columnnames)
675
minmargin = 3
676
topmargin=1
677
# set the bottom border to accommodate labels
678
bottommargin = max(c(minmargin, (strwidth(columnnames,units="in"))/par("cin")[1])) * 1 #cex.lab
679
if(bottommargin > 10 ) {
680
bottommargin<-10
681
columnnames<-substr(columnnames,1,19)
682
# par(srt=45) #TODO figure out how to use text() and srt to rotate long labels
683
}
684
par(mar = c(bottommargin, 4, topmargin, 2) +.1, cex=1)
685
plot(RND.weights[1,], type="b", col=rainbow8equal[1], ylim=c(0,max(EqSD.RND.t$constraints$max)), ylab="Weights", xlab="",axes=FALSE)
686
points(EqSD.RND.t$constraints$min, type="b", col="darkgray", lty="solid", lwd=2, pch=24)
687
points(EqSD.RND.t$constraints$max, type="b", col="darkgray", lty="solid", lwd=2, pch=25)
688
for(i in 1:NROW(RND.weights)) points(RND.weights[i,], type="b", col=tol7qualitative[i], lwd=2)
689
axis(2, cex.axis = .8, col = "darkgray")
690
axis(1, labels=columnnames, at=1:numassets, las=3, cex.axis = .8, col = "darkgray")
691
box(col = "darkgray")
692
par(op)
693
dev.off()
694
# Use colors to group measures weight=orange, ETL=blue, sd=green
695
# Use pch to group types min=triangle, equal=circle, returnrisk=square
696
697
# --------------------------------------------------------------------
698
# Plot Ex Post scatter of buoy portfolios
699
# --------------------------------------------------------------------
700
# Calculate ex post results
701
xpost.ret=Return.cumulative(BHportfs["2008-06::2008-09"])
702
xpost.sd=StdDev.annualized(BHportfs["2008-06::2008-09"])
703
704
xpost.obj=NA
705
for(i in 1:NROW(RND.weights)){
706
x = Return.portfolio(R=edhec.R["2008-06::2008-09"], weights=RND.weights[i,])
707
y=c(Return.cumulative(x), StdDev.annualized(x))
708
if(is.na(xpost.obj))
709
xpost.obj=y
710
else
711
xpost.obj=rbind(xpost.obj,y)
712
}
713
rownames(xpost.obj)=rownames(RND.weights)
714
colnames(xpost.obj)=c("Realized Returns","Realized SD")
715
xmin=min(c(xpost.sd,xtract[,"pasd.garch.pasd.garch"]))
716
xmax=max(c(xpost.sd,xtract[,"pasd.garch.pasd.garch"]))
717
ymin=min(c(xpost.ret,xtract[,"pamean.pamean"]))
718
ymax=max(c(xpost.ret,xtract[,"pamean.pamean"]))
719
720
png(filename="Scatter-ExPost-2008-06-30.png", units="in", height=5.5, width=9, res=96)
721
par(mar=c(5, 4, 1, 2) + 0.1) #c(bottom, left, top, right)
722
plot(xpost.sd,xpost.ret, xlab="Realized StdDev", ylab="Realized Mean", col="darkgray", axes=FALSE, main="", cex=.7)#, xlim=c(xmin,xmax), ylim=c(ymin,ymax))
723
grid(col = "darkgray")
724
points(xpost.obj[,2],xpost.obj[,1], col=tol7qualitative, pch=16, cex=1.5)
725
abline(h = 0, col = "darkgray")
726
axis(1, cex.axis = 0.8, col = "darkgray")
727
axis(2, cex.axis = 0.8, col = "darkgray")
728
box(col = "darkgray")
729
legend("bottomleft",legend=rownames(RND.weights), col=tol7qualitative, pch=16, ncol=1, border.col="darkgray", y.intersp=1.2, inset=.02)
730
dev.off()
731
732
# --------------------------------------------------------------------
733
# NOT USED: Show Ex Ante AND Ex Post results for 2010-12-31
734
# --------------------------------------------------------------------
735
# One more time, chart the ex ante results in mean-sd space
736
# postscript(file="ExAnteExPost20070630.eps", height=6, width=5, paper="special", horizontal=FALSE, onefile=FALSE)
737
op <- par(no.readonly=TRUE)
738
layout(matrix(c(1,2,3)),height=c(2,0.25,2),width=1)
739
par(mar=c(4,4,4,2)+.1, cex=1)
740
## Draw the Scatter chart of combined results
741
### Get the random portfolios from one of the result sets
742
xtract = extractStats(MeanSD.RND.t[["2010-12-31"]])
743
plot(xtract[,"pasd.pasd"],xtract[,"mean"], xlab="StdDev", ylab="Mean", col="darkgray", axes=FALSE, main="Ex Ante Results for 2010-12-31", cex=.5, xlim=c(xmin,xmax), ylim=c(ymin,ymax))
744
grid(col = "darkgray")
745
points(RND.objectives[,2],RND.objectives[,1], col=tol7qualitative, pch=16)
746
abline(h = 0, col = "darkgray")
747
# This could easily be done in mean CVaR space as well
748
# plot(xtract[,"pasd.pasd"],xtract[,"mean"], xlab="CVaR", ylab="Mean", col="darkgray", axes=FALSE, main="Objectives in Mean-mETL Space")
749
# points(RND.objectives[,3],RND.objectives[,1], col=rainbow8equal, pch=16)
750
axis(1, cex.axis = 0.8, col = "darkgray")
751
axis(2, cex.axis = 0.8, col = "darkgray")
752
box(col = "darkgray")
753
754
# Add legend to middle panel
755
par(mar=c(0,4,0,2)+.1, cex=0.7)
756
plot.new()
757
legend("bottom",legend=rownames(RND.weights), col=tol7qualitative, pch=16, ncol=4, border.col="darkgray", y.intersp=1.2)
758
759
# Plot the ex post results in mean-sd space
760
# Realized return versus predicted volatility?
761
par(mar=c(4,4,4,2)+.1, cex=1)
762
plot(x.sd2011,x.ret2011, xlab="StdDev", ylab="Mean", col="darkgray", axes=FALSE, main="Ex Post Results for 2010-12-31", cex=.5, xlim=c(xmin,xmax), ylim=c(ymin,ymax))
763
grid(col = "darkgray")
764
points(obj.real2011[,2],obj.real2011[,1], col=tol7qualitative, pch=16)
765
abline(h = 0, col = "darkgray")
766
axis(1, cex.axis = 0.8, col = "darkgray")
767
axis(2, cex.axis = 0.8, col = "darkgray")
768
box(col = "darkgray")
769
legend("bottomright",legend=rownames(RND.weights), col=tol7qualitative, pch=16, ncol=4, border.col="darkgray", y.intersp=1.2)
770
par(op)
771
dev.off()
772
773
# --------------------------------------------------------------------
774
# Ex Post Results Through Time
775
# --------------------------------------------------------------------
776
# charts.PerformanceSummary(cbind(EqWgt,MeanSD, MeanmETL,MinSD,MinmETL,EqSD,EqmETL)["2009::2011"], colorset=tol7qualitative)
777
# charts.PerformanceSummary(cbind(EqWgt,MeanSD, MeanmETL,MinSD,MinmETL,EqSD,EqmETL)["2000::2011"], colorset=tol7qualitative)
778
buoys.R=cbind(EqWgt,MeanSD, MeanmETL,MinSD,MinmETL,EqSD,EqmETL)
779
png(filename="Buoy-Cumulative-Returns.png", units="in", height=5.5, width=9, res=96)
780
op <- par(no.readonly = TRUE)
781
layout(matrix(c(1, 2)), height = c(2, 1.3), width = 1)
782
par(mar = c(1, 4, 1, 2)) # c(bottom, left, top, right)
783
chart.CumReturns(buoys.R["2000::",], main = "", xaxis = FALSE, legend.loc = "topleft", ylab = "Cumulative Return", colorset= tol7qualitative, ylog=TRUE, wealth.index=TRUE, cex.legend=.7, cex.axis=.6, cex.lab=.7)
784
par(mar = c(4, 4, 0, 2))
785
chart.Drawdown(buoys.R["2000::",], main = "", ylab = "Drawdown", colorset = tol7qualitative, cex.axis=.6, cex.lab=.7)
786
par(op)
787
dev.off()
788
789
790
# --------------------------------------------------------------------
791
# Show turnover of the RP portfolios relative to the EqWgt portfolio
792
# --------------------------------------------------------------------
793
turnover = function(w1,w2) {sum(abs(w1-w2))/length(w1)}
794
# Calculate the turnover matrix for the random portfolio set:
795
to.matrix<-matrix(nrow=NROW(rp),ncol=NROW(rp))
796
for(x in 1:NROW(rp)){
797
for(y in 1:NROW(rp)) {
798
to.matrix[x,y]<-turnover(rp[x,],rp[y,])
799
}
800
}
801
802
png(filename="Turnover-2010-12-31.png", units="in", height=5.5, width=9, res=96)
803
# postscript(file="TurnoverOf20101231.eps", height=6, width=5, paper="special", horizontal=FALSE, onefile=FALSE)
804
op <- par(no.readonly=TRUE)
805
layout(matrix(c(1,2)),height=c(4,1.25),width=1)
806
par(mar=c(4,4,1,2)+.1, cex=1) # c(bottom, left, top, right)
807
seq.col = heat.colors(11)
808
## Draw the Scatter chart of combined results
809
### Get the random portfolios from one of the result sets
810
x=apply(rp, MARGIN=1,FUN=turnover,w2=rp[1,])
811
plot(xtract[,"pasd.garch.pasd.garch"],xtract[,"pamean.pamean"], xlab="Predicted StdDev", ylab="Predicted Mean", col=seq.col[ceiling(x*100)], axes=FALSE, main="", cex=.7, pch=16)
812
grid(col = "darkgray")
813
points(RND.objectives[1,2],RND.objectives[1,1], col="blue", pch=19, cex=1.5)
814
axis(1, cex.axis = 0.8, col = "darkgray")
815
axis(2, cex.axis = 0.8, col = "darkgray")
816
box(col = "darkgray")
817
818
# Add legend to bottom panel
819
par(mar=c(5,5.5,1,3)+.1, cex=0.7)
820
## Create a histogramed legend for sequential colorsets
821
## this next bit of code is based on heatmap.2 in gplots package
822
x=ceiling(x*100)
823
scale01 <- function(x, low = min(x), high = max(x)) {
824
return((x - low)/(high - low))
825
}
826
breaks <- seq(min(x, na.rm = TRUE), max(x, na.rm = TRUE), length = length(seq.col)+1)
827
min.raw <- min(x, na.rm = TRUE)
828
max.raw <- max(x, na.rm = TRUE)
829
z <- seq(min.raw, max.raw, length = length(seq.col))
830
image(z = matrix(z, ncol = 1), col = seq.col, breaks = breaks, xaxt = "n", yaxt = "n")
831
par(usr = c(0, 1, 0, 1)) # needed to draw the histogram correctly
832
lv <- pretty(breaks)
833
xv <- scale01(as.numeric(lv), min.raw, max.raw)
834
axis(1, at = xv, labels=sprintf("%s%%", pretty(lv)))
835
h <- hist(x, plot = FALSE, breaks=breaks)
836
hx <- scale01(breaks, min(x), max(x))
837
hy <- c(h$counts, h$counts[length(h$counts)])
838
lines(hx, hy/max(hy)*.95, lwd = 2, type = "s", col = "blue")
839
axis(2, at = pretty(hy)/max(hy)*.95, pretty(hy))
840
title(ylab="Count")
841
title(xlab="Degree of Turnover from Equal Weight Portfolio")
842
par(op)
843
dev.off()
844
845
# --------------------------------------------------------------------
846
# RSGarch results against EqWgt returns
847
# --------------------------------------------------------------------
848
849
print(load("~/devel/R/RSGarch.rda"))
850
851
png(filename="RSGarch.png", units="in", height=5.5, width=9, res=96)
852
layout(matrix(c(1,2)),height=c(2,1.5),width=1)
853
par(mar=c(1, 4, 4, 2) + 0.1, cex=0.8) #c(bottom, left, top, right)
854
chart.TimeSeries(zoo(f.MC.q,index(EqWgt)[-1]), main='Regime Switching Garch model for the Equal Weight Portfolio', ylab='Volatility Regime from 0(low) to 1(high)', xaxis=FALSE, colorset=rep("blue",2), lty=2, lwd=1)
855
par(mar=c(4,4,0,2)+.1, cex=0.8) #c(bottom, left, top, right)
856
chart.BarVaR(EqWgt, methods="StdDev", show.symmetric=TRUE, main="", ylab="EqWgt Return", width=12)
857
par(op)
858
dev.off()
859
860
861
# --------------------------------------------------------------------
862
# Other things we might do:
863
864
###############
865
#ARMA-GARCH(1,1,1) for mu, sigma, and skew estimates 3 months out
866
require(rugarch)
867
868
869
ctrl = list(rho = 1, delta = 1e-6, outer.iter = 100, tol = 1e-6,outer.iter=700,inner.iter=2000)
870
spec = ugarchspec(variance.model = list(model = "gjrGARCH", garchOrder = c(1,1)),
871
mean.model = list(armaOrder = c(1,0), include.mean = TRUE),
872
distribution.model = "ghyp")
873
874
dates<-seq.Date(from=as.Date('1975-03-01'), to=as.Date('1996-12-31'),by=1)
875
dates<-dates[endpoints(dates,on='months')]
876
taildates<-seq.Date(from=as.Date(as.Date(last(index(edhec.R)))+1), to=as.Date(as.Date(last(index(edhec.R)))+160),by=1)
877
taildates<-taildates[endpoints(taildates,on='months')]
878
tailxts<-xts(rep(0,length(taildates)),order.by=taildates)
879
880
garch.out <- foreach(i=1:ncol(edhec.R),.inorder=TRUE) %dopar% {
881
882
oridata <- edhec.R[,i]
883
start <- first(index(oridata))
884
end <- last(index(oridata))
885
886
#bootsstrap
887
#we're going to do a simple sample with replacement here
888
# if doing this 'for real', a more sophisticated factor model monte carlo
889
# or AR tsboot() approach would likely be preferred
890
data<-rbind(xts(sample(oridata,length(dates),replace=TRUE),order.by=dates),oridata,tailxts)
891
colnames(data)<-colnames(oridata)
892
#add some NA's on the end, hack for now
893
894
#run the garch
895
rm(bktest)
896
#NOTE forecast.length needs to be evenly divisible by n.ahead and refit.every
897
bktest = ugarchroll(spec, data = data, n.ahead = 3,
898
forecast.length = 186, refit.every = 3, refit.window = "moving",
899
solver = "solnp", fit.control = list(), solver.control = ctrl,
900
calculate.VaR = FALSE, VaR.alpha = c(0.01, 0.025, 0.05))
901
902
# the standardized density parameters (rho, zeta)
903
f01density = bktest@roll$f01density[[3]]
904
skew = apply(f01density[,5:6],1, FUN = function(x) dskewness("nig", skew=x[1], shape=x[2]))
905
kurt = apply(f01density[,5:6],1, FUN = function(x) dkurtosis("nig", skew=x[1], shape=x[2])) #excess kurtosis
906
907
# just sum the n.ahead predictions for now, could compound them, not sure
908
# what trouble that would cause
909
mu3 = rowSums(cbind(as.data.frame(bktest, n.ahead=1, refit = "all", which = "series"),
910
as.data.frame(bktest, n.ahead=2, refit = "all", which = "series"),
911
as.data.frame(bktest, n.ahead=3, refit = "all", which = "series")))
912
913
sigma3 = rowMeans(cbind(as.data.frame(bktest, n.ahead=1, refit = "all", which = "sigma"),
914
as.data.frame(bktest, n.ahead=2, refit = "all", which = "sigma"),
915
as.data.frame(bktest, n.ahead=3, refit = "all", which = "sigma")))
916
917
garchmom<-cbind(
918
as.data.frame(bktest, n.ahead=3, refit = "all", which = "series"),
919
as.data.frame(bktest, n.ahead=3, refit = "all", which = "sigma"),
920
skew, kurt,mu3,sigma3)
921
922
garchmom.xts<-xts(garchmom,order.by=as.Date(rownames(garchmom)))
923
garchdata<-garchmom.xts[index(oridata)]
924
colnames(garchdata)[1]<-'mu'
925
colnames(garchdata)[6]<-'sigma3'
926
927
out<-list(bktest=bktest,spec=spec,oridata=oridata,data=data,garchmom=garchmom.xts,garchdata=garchdata,start=start, end=end)
928
}
929
names(garch.out)<-colnames(edhec.R)
930
# OK, so now we've got a big unweildy GARCH list. let's create garchmu and garchsigma
931
garch.mu<-foreach(x=iter(garch.out),.combine=cbind)%do% { x$garchdata$mu }
932
names(garch.mu)<-colnames(edhec.R)
933
garch.sigma<-foreach(x=iter(garch.out),.combine=cbind)%do% { x$garchdata$sigma }
934
names(garch.sigma)<-colnames(edhec.R)
935
garch.skew<-foreach(x=iter(garch.out),.combine=cbind)%do% { x$garchdata$skew }
936
names(garch.skew)<-colnames(edhec.R)
937
garch.kurtosis <-foreach(x=iter(garch.out),.combine=cbind)%do% { x$garchdata$kurt }
938
names(garch.kurtosis)<-colnames(edhec.R)
939
garch.mu3 <- foreach(x=iter(garch.out),.combine=cbind)%do% { x$garchdata$mu3 }
940
names(garch.mu3)<-colnames(edhec.R)
941
garch.sigma3 <- foreach(x=iter(garch.out),.combine=cbind)%do% { x$garchdata$sigma3 }
942
names(garch.sigma3)<-colnames(edhec.R)
943
944
945
#diagnose skew and kurtosis
946
last(garch.skew)
947
skewness(tail(edhec.R,36))
948
last(garch.kurtosis)
949
kurtosis(tail(edhec.R,36))
950
951
foreach(i=1:ncol(edhec.R)) %do% {
952
dev.new()
953
par(mfrow=c(3,1))
954
plot(garch.out[[i]]$bktest, n.ahead=1, which = 3,main=paste(names(garch.out)[i],'n-ahead 1'))
955
plot(garch.out[[i]]$bktest, n.ahead=2, which = 3,main=paste(names(garch.out)[i],'n-ahead 2'))
956
plot(garch.out[[i]]$bktest, n.ahead=3, which = 3,main=paste(names(garch.out)[i],'n-ahead 3'))
957
}
958
959
save(garch.out,garch.mu,garch.mu3,garch.sigma,garch.sigma3,garch.skew,garch.kurtosis,file=paste(Sys.Date(),runname,'garch-results','rda',sep='.'))
960
961
#####
962
# you can examine the bktest slots using commands like:
963
#report(bktest, type="VaR", n.ahead = 1, VaR.alpha = 0.01, conf.level = 0.95)
964
#report(convert.arb.bktest, type="fpm")
965
#plot(bktest)
966
967
# fit=ugarchfit(garch.out$"Global Macro"$spec, garch.out$"Global Macro"$data)
968
# show(fit)
969
970
971
###########
972
# Multivariate Garch from rmgarch package
973
974
# set up the data
975
bs.data <- foreach(i=1:ncol(edhec.R),.inorder=TRUE, .combine=cbind) %dopar% {
976
977
oridata <- edhec.R[,i]
978
start <- first(index(oridata))
979
end <- last(index(oridata))
980
981
#bootsstrap
982
#we're going to do a simple sample with replacement here
983
# if doing this 'for real', a more sophisticated factor model monte carlo
984
# or AR tsboot() approach would likely be preferred
985
data<-rbind(xts(sample(oridata,length(dates),replace=TRUE),order.by=dates),oridata,tailxts)
986
colnames(data)<-colnames(oridata)
987
#add some NA's on the end, hack for now
988
989
data
990
}
991
992
#try GO-GARCH
993
ggspec = gogarchspec(
994
mean.model = list(model = c("constant", "AR", "VAR")[3], lag = 2), #external.regressors = ex),
995
variance.model = list(model = "gjrGARCH", garchOrder = c(1,1), submodel = NULL, variance.targeting = FALSE),
996
distribution.model = c("mvnorm", "manig", "magh")[3], ica = c("fastica", "pearson", "jade", "radical")[1])
997
ggfit = gogarchfit(ggspec, data = bs.data, out.sample = 0,
998
parallel = FALSE, parallel.control = parallel.control)
999
1000
gportmoments(ggfit,weights=rep(1/ncol(bs.data),ncol(bs.data)))
1001
1002
rcov(ggfit)
1003
1004
ggroll = gogarchroll(ggspec, data = bs.data, n.ahead = 1,
1005
forecast.length = 186, refit.every = 3, refit.window = "moving",
1006
solver = "solnp", fit.control = list(), solver.control = ctrl)
1007
1008
# try DCC-GARCH
1009
spec = spec # use the same spec we used for the univariate GARCH
1010
spec1 = dccspec(uspec = multispec( replicate(7, spec) ), dccOrder = c(1,1), asymmetric = TRUE, distribution = "mvnorm")
1011
dccfit1 = dccfit(spec1, data = bs.data, fit.control = list(eval.se=FALSE))
1012
1013
1014
#dccroll1 = dccroll(spec1, data = bs.data, n.ahead = 1,
1015
# forecast.length = 186, refit.every = 3, refit.window = "moving",
1016
# solver = "solnp", fit.control = list(), solver.control = ctrl)
1017
1018
###
1019
# garch moments
1020
# mu
1021
dccmu<-fitted(dccfit1)
1022
colnames(dccmu)<-colnames(edhec.R)
1023
rownames(dccmu)<-as.character(index(bs.data)[-1])
1024
dccmu<-xts(dccmu,order.by=as.Date(rownames((dccmu))))
1025
dccmu<-dccmu[index(edhec.R)]
1026
1027
# sigma
1028
dccsigma<-sigma(dccfit1)
1029
colnames(dccsigma)<-colnames(edhec.R)
1030
rownames(dccsigma)<-as.character(index(bs.data)[-1])
1031
dccsigma<-xts(dccsigma,order.by=as.Date(rownames((dccsigma))))
1032
dccsigma<-dccsigma[index(edhec.R)]
1033
1034
# conditional covariance
1035
dcccova<-rcov(dccfit1)
1036
dcccovl<-list()
1037
for(i in 1:dim(dcccova)[3]) { dcccovl[[i]]<- dcccova[,,i]; colnames(dcccovl[[i]])<-colnames(edhec.R); rownames(dcccovl[[i]])<-colnames(edhec.R)}
1038
names(dcccovl)<-index(bs.data)[-length(index(bs.data))]
1039
dcccovls<-dcccovl[1:444] #subset out only the real data
1040
dcccovls<-dcccovls[263:444] # dump the zero junk from the end
1041
all.equal(names(dcccovls),as.character(index(edhec.R)))
1042
1043
# conditional correlation
1044
dcccora<-rcor(dccfit1)
1045
dcccorl<-list()
1046
for(i in 1:dim(dcccora)[3]) { dcccorl[[i]]<- dcccora[,,i]; colnames(dcccorl[[i]])<-colnames(edhec.R); rownames(dcccorl[[i]])<-colnames(edhec.R)}
1047
names(dcccorl)<-index(bs.data)[-length(index(bs.data))]
1048
dcccorls<-dcccorl[1:444] #subset out only the real data
1049
dcccorls<-dcccorls[263:444] # dump the zero junk from the end
1050
dcccorl<-dcccorls
1051
rm(dcccorls,dcccora)
1052
save(spec,dccfit1,dccmu,dccsigma,dcccovl,dcccorl,file=paste('MVDCCGarch',Sys.Date(),'rda',sep='.'))
1053
1054
# Historical performance of each buoy portfolio
1055
## Same statistics as above
1056
## Compare relative performance
1057
1058
# Condition factor model forecasts?
1059
## On volatility
1060
## On correlation
1061