Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/demo/demo_JPM2024MinDownsideRiskCVXR.R
1433 views
1
## This R script reproduces the graphs in Exhibits 6, 8, 10,
2
## 12, 14, 16, 18 of the paper "Minimum Downside Risk Portfolios"
3
## published in the Journal of Portfolio Management, Oct. 2024.
4
##
5
## Copy/past this script into your own computer R file. Then
6
## run code lines 11 to 262 to create functions that will be
7
## needed, and run lines 267 to 271 to load packages needed.
8
## Then we recommend to run code that follows in convenient
9
## chunks to replicate each of the above Exhits
10
11
rm(list = ls())
12
13
# MV: Using CVXR
14
optimize_portfolio_MV_rebalance <- function(returns, training_period=NULL, rolling_window=NULL,
15
rebalance_on) {
16
# Start time
17
t1 <- Sys.time()
18
19
# Get the number of assets and name of the assets
20
num_assets <- ncol(returns)
21
asset_names <- colnames(returns)
22
23
# Set the training period for portfolio optimization with rebalancing
24
if(is.null(training_period) & !is.null(rolling_window)) {
25
training_period <- rolling_window
26
}
27
28
# Determine the dates when rebalancing takes place
29
epoints <- endpoints(returns, on = rebalance_on)[which(endpoints(returns, on = rebalance_on) >= training_period)]
30
31
# Get the rebalancing dates
32
rebal_date_indx <- index(returns)[epoints]
33
34
# Matrix to hold the weights
35
mv_portfolio_wts <- matrix(NA, nrow = length(epoints), ncol = num_assets)
36
colnames(mv_portfolio_wts) <- asset_names
37
38
# Optimize portfolio at each date
39
for (j in 1:length(epoints)) {
40
ep <- epoints[j]
41
returns_est_window <- returns[(ifelse(ep - rolling_window >= 1, ep - rolling_window, 1)):ep, ]
42
43
# Calculate the mean returns and volatility of returns
44
mu <- apply(returns_est_window, 2, mean)
45
mu <- matrix(mu, nrow = num_assets)
46
Sigma <- cov(returns_est_window)
47
48
# Formulate the optimization problem
49
wts_mv <- Variable(num_assets)
50
ret <- t(mu) %*% wts_mv
51
52
# Constraints (long-only and full-investment) for MV portfolio optimization
53
constraints_mv <- list(wts_mv >= 0,
54
sum_entries(wts_mv) == 1)
55
56
# Objective function for MV portfolio optimization
57
objective_mv <- quad_form(wts_mv, Sigma)
58
59
# Solve the MV portfolio optimization problem
60
prob_mv <- Problem(Minimize(objective_mv), constraints_mv)
61
result_mv <- solve(prob_mv, solver = 'OSQP')
62
# cat("\nMV Status of the solution: ", result_mv$status)
63
# cat("\nMV Solver used: ", result_mv$solver)
64
65
# Evaluate risk and return for current solution
66
optimal_risk <- sqrt(result_mv$value)
67
optimal_ret <- result_mv$getValue(ret)
68
69
# Get the optimal weights
70
wts <- as.vector(result_mv$getValue(wts_mv))
71
names(wts) <- asset_names
72
mv_portfolio_wts[j, ] <- t(wts)
73
}
74
75
# Convert the weights to xts
76
rebal_mv_wts <- xts(mv_portfolio_wts, order.by = rebal_date_indx)
77
78
# Save the portfolio weights in a list
79
result <- list(wts = rebal_mv_wts)
80
81
t2 <- Sys.time()
82
cat("\nTime taken to run the portfolio optimization: ", t2-t1)
83
84
return(result)
85
}
86
87
88
89
# MES: Using CVXR
90
optimize_portfolio_MES_rebalance <- function(returns, alpha, training_period=NULL, rolling_window=NULL,
91
rebalance_on) {
92
93
# Start time
94
t1 <- Sys.time()
95
96
# Get the number of assets and name of the assets
97
num_assets <- ncol(returns)
98
asset_names <- colnames(returns)
99
100
# Set the training period for portfolio optimization with rebalancing
101
if(is.null(training_period) & !is.null(rolling_window)) {
102
training_period <- rolling_window
103
}
104
105
# Determine the dates when rebalancing takes place
106
epoints <- endpoints(returns, on = rebalance_on)[which(endpoints(returns, on = rebalance_on) >= training_period)]
107
108
# Get the rebalancing dates
109
rebal_date_indx <- index(returns)[epoints]
110
111
# Matrix to hold the weights
112
mes_portfolio_wts <- matrix(NA, nrow = length(epoints), ncol = num_assets)
113
colnames(mes_portfolio_wts) <- asset_names
114
115
# Optimize portfolio at each date
116
for (j in 1:length(epoints)) {
117
ep <- epoints[j]
118
returns_est_window <- returns[(ifelse(ep - rolling_window >= 1, ep - rolling_window, 1)):ep, ]
119
120
# Formulate the optimization problem
121
# Calculate values of parameters and define variables
122
J <- nrow(returns_est_window)
123
X <- as.matrix(returns_est_window)
124
mu <- colMeans(returns_est_window)
125
126
# Variables
127
wts_mes <- Variable(num_assets)
128
z <- Variable(J)
129
eta <- Variable(1)
130
131
# Constraints (long-only and full-investment) for MES portfolio optimization
132
constraints_mes <- list(wts_mes >= 0,
133
sum(wts_mes) == 1,
134
z >= 0,
135
z >= -X %*% wts_mes - eta
136
)
137
138
# Objective function for MES portfolio optimization
139
# Problem formulation for MES
140
objective_mes <- eta + (1/(J*alpha)) * sum(z)
141
142
# Solve the MES portfolio optimization problem
143
prob_mes <- Problem(Minimize(objective_mes), constraints = constraints_mes)
144
result_mes <- solve(prob_mes, solver = 'SCS')
145
# cat("\nMES Status of the solution: ", result_mes$status)
146
# cat("\nMES Solver used: ", result_mes$solver)
147
148
# Get the optimal weights
149
wts <- as.vector(result_mes$getValue(wts_mes))
150
names(wts) <- asset_names
151
mes_portfolio_wts[j, ] <- t(wts)
152
}
153
154
# Convert the weights to xts
155
rebal_mes_wts <- xts(mes_portfolio_wts, order.by = rebal_date_indx)
156
157
# Save the portfolio weights in a list
158
result <- list(wts = rebal_mes_wts)
159
160
t2 <- Sys.time()
161
cat("\nTime taken to run the portfolio optimization: ", t2-t1)
162
163
return(result)
164
}
165
166
167
168
# MCSM: Using CVXR
169
optimize_portfolio_MCSM_rebalance <- function(returns, alpha, training_period=NULL, rolling_window=NULL,
170
rebalance_on) {
171
172
# Start time
173
t1 <- Sys.time()
174
175
# Get the number of assets and name of the assets
176
num_assets <- ncol(returns)
177
asset_names <- colnames(returns)
178
179
# Set the training period for portfolio optimization with rebalancing
180
if(is.null(training_period) & !is.null(rolling_window)) {
181
training_period <- rolling_window
182
}
183
184
# Determine the dates when rebalancing takes place
185
epoints <- endpoints(returns, on = rebalance_on)[which(endpoints(returns, on = rebalance_on) >= training_period)]
186
187
# Get the rebalancing dates
188
rebal_date_indx <- index(returns)[epoints]
189
190
# Matrix to hold the weights
191
mcsm_portfolio_wts <- matrix(NA, nrow = length(epoints), ncol = num_assets)
192
colnames(mcsm_portfolio_wts) <- asset_names
193
194
# Optimize portfolio at each date
195
for (j in 1:length(epoints)) {
196
ep <- epoints[j]
197
returns_est_window <- returns[(ifelse(ep - rolling_window >= 1, ep - rolling_window, 1)):ep, ]
198
199
# Formulate the optimization problem
200
# Calculate values of parameters and define variables
201
J <- nrow(returns_est_window)
202
X <- as.matrix(returns_est_window)
203
mu <- colMeans(returns_est_window)
204
205
# Variables
206
wts_mcsm <- Variable(num_assets)
207
z <- Variable(J)
208
eta <- Variable(1)
209
f <- Variable(1)
210
211
# Constraints (long-only and full-investment) for MCSM portfolio optimization
212
constraints_mcsm <- list(wts_mcsm >= 0,
213
sum_entries(wts_mcsm) == 1,
214
z >= 0,
215
z >= -X %*% wts_mcsm - eta,
216
f >= p_norm(z, p=2)
217
)
218
219
# Objective function for MCSM portfolio optimization
220
# Problem formulation for MCSM (following Krokhmal's algorithm)
221
objective_mcsm <- eta + (1/(alpha*sqrt(J)))*f
222
223
# Solve the MCSM portfolio optimization problem
224
prob_mcsm <- Problem(Minimize(objective_mcsm), constraints = constraints_mcsm)
225
result_mcsm <- solve(prob_mcsm, solver = 'SCS')
226
# cat("\nMCSM Status of the solution: ", result_mcsm$status)
227
# cat("\nMCSM solver used: ", result_mcsm$solver)
228
229
# Get the optimal weights
230
wts <- as.vector(result_mcsm$getValue(wts_mcsm))
231
names(wts) <- asset_names
232
mcsm_portfolio_wts[j, ] <- t(wts)
233
}
234
235
# Convert the weights to xts
236
rebal_mcsm_wts <- xts(mcsm_portfolio_wts, order.by = rebal_date_indx)
237
238
# Save the portfolio weights in a list
239
result <- list(wts = rebal_mcsm_wts)
240
241
t2 <- Sys.time()
242
cat("\nTime taken to run the portfolio optimization: ", t2-t1)
243
244
return(result)
245
}
246
247
248
249
# Turnover Control
250
TOcontrol <- function(wts, delta){
251
idx <- index(wts)
252
out <- copy(wts)
253
TO <- rep(NA, length(idx))
254
for(i in 2:length(idx)){
255
currentTO <- sum(abs(coredata(wts[idx[i], ]) - coredata(wts[idx[i-1], ])))
256
TO[i] <- currentTO
257
if(currentTO <= delta){
258
out[idx[i], ] <- out[idx[i-1], ]
259
}
260
}
261
return(wts = out)
262
}
263
264
###
265
266
# Load packages
267
library(PortfolioAnalytics)
268
library(CVXR)
269
library(data.table)
270
library(xts)
271
library(PCRA)
272
273
274
# Use CRSP daily data set
275
stocksCRSPdaily <- getPCRAData(dataset = "stocksCRSPdaily")
276
dateRange <- c("1993-01-01","2015-12-31")
277
smallcapTS <- selectCRSPandSPGMI(
278
periodicity = "daily",
279
dateRange = dateRange,
280
stockItems = c("Date", "TickerLast", "CapGroupLast", "Return",
281
"MktIndexCRSP", "Ret13WkBill"),
282
factorItems = NULL,
283
subsetType = "CapGroupLast",
284
subsetValues = "SmallCap",
285
outputType = "xts")
286
287
# Extract Market and RF from smallcapTS
288
Market <- smallcapTS[ , 107]
289
names(Market) <- "Market"
290
RF <- smallcapTS[ , 108]
291
names(RF) <- "RF"
292
293
# Remove "MktIndexCRSP", "Ret13WkBill" from smallcapTS
294
smallcapTS <- smallcapTS[ , -c(107,108)]
295
dim(smallcapTS)
296
297
## Exhibit 6 (1 minute 30 seconds)
298
299
returns <- smallcapTS[ , 1:30]
300
dim(returns)
301
302
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
303
rolling_window <- 260
304
305
## MV
306
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
307
rolling_window = rolling_window,
308
rebalance_on = "months")
309
310
# Extract portfolio weights from the result
311
mv_wts <- opt_mv_result$wts
312
mv_wts <- mv_wts[complete.cases(mv_wts), ]
313
314
## MES05 (for tail probability 5%)
315
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
316
rolling_window = rolling_window,
317
rebalance_on = "months")
318
319
# Extract portfolio weights from the result
320
mes_wts <- opt_mes_result$wts
321
mes_wts <- mes_wts[complete.cases(mes_wts), ]
322
323
## MES05-TOC
324
mes_wts_toc <- TOcontrol(mes_wts, 0.9) # Optimal for 1-30
325
326
# Compute returns of the portfolios
327
MV <- Return.rebalancing(returns, mv_wts)
328
MES05 <- Return.rebalancing(returns, mes_wts)
329
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
330
331
# Combine MV, MES05, MES05_TOC returns
332
portf_ret_comb <- na.omit(merge(MV, MES05, MES05TOC, Market, all=F))
333
names(portf_ret_comb) <- c("MV", "MES05", "MES05-TOC", "Market")
334
335
backtest.plot(portf_ret_comb, plotType = "cumRet",
336
main = "MV, MES05, MES05-TOC(0.9), Stocks 1-30",
337
colorSet = c("red","darkgreen","darkblue","black"),
338
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
339
340
341
## Exhibit 8 (1 minute 28 seconds)
342
343
returns <- smallcapTS[ , 31:60]
344
dim(returns)
345
346
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
347
rolling_window <- 260
348
349
## MV
350
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
351
rolling_window = rolling_window,
352
rebalance_on = "months")
353
354
# Extract portfolio weights from the result
355
mv_wts <- opt_mv_result$wts
356
mv_wts <- mv_wts[complete.cases(mv_wts), ]
357
358
## MES05 (for tail probability 5%)
359
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
360
rolling_window = rolling_window,
361
rebalance_on = "months")
362
363
# Extract portfolio weights from the result
364
mes_wts <- opt_mes_result$wts
365
mes_wts <- mes_wts[complete.cases(mes_wts), ]
366
367
## MES05-TOC
368
mes_wts_toc <- TOcontrol(mes_wts, 0.5) # Optimal for 31-60
369
370
# Compute returns of the portfolios
371
MV <- Return.rebalancing(returns, mv_wts)
372
MES05 <- Return.rebalancing(returns, mes_wts)
373
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
374
375
# Combine MV, MES05, MES05_TOC returns
376
portf_ret_comb <- na.omit(merge(MV, MES05, MES05TOC, Market, all=F))
377
names(portf_ret_comb) <- c("MV", "MES05", "MES05-TOC", "Market")
378
379
backtest.plot(portf_ret_comb, plotType = "cumRet",
380
main = "MV, MES05, MES05-TOC(0.5), Stocks 31-60",
381
colorSet = c("red","darkgreen","darkblue","black"),
382
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
383
384
385
## Exhibit 10 (1 minute 26 seconds)
386
387
returns <- smallcapTS[ , 61:90]
388
dim(returns)
389
390
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
391
rolling_window <- 260
392
393
## MV
394
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
395
rolling_window = rolling_window,
396
rebalance_on = "months")
397
398
# Extract portfolio weights from the result
399
mv_wts <- opt_mv_result$wts
400
mv_wts <- mv_wts[complete.cases(mv_wts), ]
401
402
## MES05 (for tail probability 5%)
403
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
404
rolling_window = rolling_window,
405
rebalance_on = "months")
406
407
# Extract portfolio weights from the result
408
mes_wts <- opt_mes_result$wts
409
mes_wts <- mes_wts[complete.cases(mes_wts), ]
410
411
## MES05-TOC
412
mes_wts_toc <- TOcontrol(mes_wts, 0.5) # Optimal for 61-90
413
414
# Compute returns of the portfolios
415
MV <- Return.rebalancing(returns, mv_wts)
416
MES05 <- Return.rebalancing(returns, mes_wts)
417
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
418
419
# Combine MV, MES05, MES05_TOC returns
420
portf_ret_comb <- na.omit(merge(MV, MES05, MES05TOC, Market, all=F))
421
names(portf_ret_comb) <- c("MV", "MES05", "MES05-TOC", "Market")
422
423
backtest.plot(portf_ret_comb, plotType = "cumRet",
424
main = "MV, MES05, MES05-TOC(0.5), Stocks 61-90",
425
colorSet = c("red","darkgreen","darkblue","black"),
426
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
427
428
429
## Get Exhibit 12 microcaps data set
430
431
#' use CRSP daily microcaps data set
432
stocksCRSPdaily <- getPCRAData(dataset = "stocksCRSPdaily")
433
dateRange <- c("1993-01-01","2015-12-31")
434
microcapTS <- selectCRSPandSPGMI(
435
periodicity = "daily",
436
dateRange = dateRange,
437
stockItems = c("Date", "TickerLast", "CapGroupLast", "Return",
438
"MktIndexCRSP", "Ret13WkBill"),
439
factorItems = NULL,
440
subsetType = "CapGroupLast",
441
subsetValues = "MicroCap",
442
outputType = "xts")
443
444
# Extract Market and RF from microcapTS
445
Market <- microcapTS[ , 35]
446
names(Market) <- "Market"
447
RF <- microcapTS[ , 36]
448
names(RF) <- "RF"
449
450
# Remove "MktIndexCRSP", "Ret13WkBill"
451
microcapTS <- microcapTS[ , -c(35, 36)]
452
returns <- microcapTS
453
454
455
## Exhibit 12 (1 minute 33 seconds)
456
457
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
458
rolling_window <- 260
459
460
## MV
461
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
462
rolling_window = rolling_window,
463
rebalance_on = "months")
464
465
# Extract portfolio weights from the result
466
mv_wts <- opt_mv_result$wts
467
mv_wts <- mv_wts[complete.cases(mv_wts), ]
468
469
## MES05 (for tail probability 5%)
470
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
471
rolling_window = rolling_window,
472
rebalance_on = "months")
473
474
# Extract portfolio weights from the result
475
mes_wts <- opt_mes_result$wts
476
mes_wts <- mes_wts[complete.cases(mes_wts), ]
477
478
## MES05-TOC
479
mes_wts_toc <- TOcontrol(mes_wts, 0.5)
480
481
# Compute returns of the portfolios
482
MV <- Return.rebalancing(returns, mv_wts)
483
MES05 <- Return.rebalancing(returns, mes_wts)
484
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
485
486
# Combine MV, MES05, MES05_TOC returns
487
portf_ret_comb <- na.omit(merge(MV, MES05, MES05TOC, Market, all=F))
488
names(portf_ret_comb) <- c("MV", "MES05", "MES05-TOC", "Market")
489
490
backtest.plot(portf_ret_comb, plotType = "cumRet",
491
main = "MV, MES05, MES05-TOC(0.5), Microcaps 34",
492
colorSet = c("red","darkgreen","darkblue","black"),
493
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
494
495
496
## Exhibit 14 (2 minutes 34 seconds)
497
498
returns <- smallcapTS[ , 1:30]
499
500
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
501
rolling_window <- 260
502
503
## MV
504
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
505
rolling_window = rolling_window,
506
rebalance_on = "months")
507
508
# Extract portfolio weights from the result
509
mv_wts <- opt_mv_result$wts
510
mv_wts <- mv_wts[complete.cases(mv_wts), ]
511
512
## MES05 (for tail probability 5%)
513
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
514
rolling_window = rolling_window,
515
rebalance_on = "months")
516
517
# Extract portfolio weights from the result
518
mes_wts <- opt_mes_result$wts
519
mes_wts <- mes_wts[complete.cases(mes_wts), ]
520
521
## MES05-TOC
522
mes_wts_toc <- TOcontrol(mes_wts, 0.9) # Optimal for 1-30
523
524
## MCSM15 (for tail probability 15%)
525
opt_mcsm_result <- optimize_portfolio_MCSM_rebalance(returns = returns, alpha = 0.15,
526
rolling_window = rolling_window,
527
rebalance_on = "months")
528
529
# Extract portfolio weights from the result
530
mcsm_wts <- opt_mcsm_result$wts
531
mcsm_wts <- mcsm_wts[complete.cases(mcsm_wts), ]
532
533
## MCSM15-TOC
534
mcsm_wts_toc <- TOcontrol(mcsm_wts, 0.8) # Optimal for 1-30
535
536
# Compute cumulative returns of the portfolios
537
MV <- Return.rebalancing(returns, mv_wts)
538
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
539
MCSM15TOC <- Return.rebalancing(returns, mcsm_wts_toc)
540
541
# Combine MV, MES05TOC, MCSM05TOC gross cumulative returns
542
portf_ret_comb <- na.omit(merge(MV, MES05TOC, MCSM15TOC, Market, all=F))
543
names(portf_ret_comb) <- c("MV", "MES05-TOC", "MCSM15-TOC", "Market")
544
545
backtest.plot(portf_ret_comb, plotType = "cumRet",
546
main = "MV, MES05-TOC(0.9), MCSM15-TOC(0.8), Stocks 1-30",
547
colorSet = c("red","darkgreen","darkblue","black"),
548
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
549
550
551
## Exhibit 16 (2 minutes 35 seconds)
552
553
returns <- smallcapTS[ , 31:60]
554
555
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
556
rolling_window <- 260
557
558
## MV
559
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
560
rolling_window = rolling_window,
561
rebalance_on = "months")
562
563
# Extract portfolio weights from the result
564
mv_wts <- opt_mv_result$wts
565
mv_wts <- mv_wts[complete.cases(mv_wts), ]
566
567
## MES05 (for tail probability 5%)
568
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
569
rolling_window = rolling_window,
570
rebalance_on = "months")
571
572
# Extract portfolio weights from the result
573
mes_wts <- opt_mes_result$wts
574
mes_wts <- mes_wts[complete.cases(mes_wts), ]
575
576
## MES05-TOC
577
mes_wts_toc <- TOcontrol(mes_wts, 0.5) # Optimal for 31-60
578
579
## MCSM15 (for tail probability 15%)
580
opt_mcsm_result <- optimize_portfolio_MCSM_rebalance(returns = returns, alpha = 0.15,
581
rolling_window = rolling_window,
582
rebalance_on = "months")
583
584
# Extract portfolio weights from the result
585
mcsm_wts <- opt_mcsm_result$wts
586
mcsm_wts <- mcsm_wts[complete.cases(mcsm_wts), ]
587
588
## MCSM15-TOC
589
mcsm_wts_toc <- TOcontrol(mcsm_wts, 0.6) # Optimal for 31-60
590
591
# Compute cumulative returns of the portfolios
592
MV <- Return.rebalancing(returns, mv_wts)
593
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
594
MCSM15TOC <- Return.rebalancing(returns, mcsm_wts_toc)
595
596
# Combine MV, MES05TOC, MCSM05TOC gross cumulative returns
597
portf_ret_comb <- na.omit(merge(MV, MES05TOC, MCSM15TOC, Market, all=F))
598
names(portf_ret_comb) <- c("MV", "MES05-TOC", "MCSM15-TOC", "Market")
599
600
backtest.plot(portf_ret_comb, plotType = "cumRet",
601
main = "MV, MES05-TOC(0.5), MCSM15-TOC(0.6), Stocks 31-60",
602
colorSet = c("red","darkgreen","darkblue","black"),
603
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
604
605
606
## Exhibit 18 (2 minutes 36 seconds)
607
608
returns <- smallcapTS[ , 61:90]
609
610
# Optimize Portfolio at Monthly Rebalancing and 260-Day Training
611
rolling_window <- 260
612
613
## MV
614
opt_mv_result <- optimize_portfolio_MV_rebalance(returns = returns,
615
rolling_window = rolling_window,
616
rebalance_on = "months")
617
618
# Extract portfolio weights from the result
619
mv_wts <- opt_mv_result$wts
620
mv_wts <- mv_wts[complete.cases(mv_wts), ]
621
622
## MES05 (for tail probability 5%)
623
opt_mes_result <- optimize_portfolio_MES_rebalance(returns = returns, alpha = 0.05,
624
rolling_window = rolling_window,
625
rebalance_on = "months")
626
627
# Extract portfolio weights from the result
628
mes_wts <- opt_mes_result$wts
629
mes_wts <- mes_wts[complete.cases(mes_wts), ]
630
631
## MES05-TOC
632
mes_wts_toc <- TOcontrol(mes_wts, 0.6) # Optimal for 61-90
633
634
## MCSM15 (for tail probability 15%)
635
opt_mcsm_result <- optimize_portfolio_MCSM_rebalance(returns = returns, alpha = 0.15,
636
rolling_window = rolling_window,
637
rebalance_on = "months")
638
639
# Extract portfolio weights from the result
640
mcsm_wts <- opt_mcsm_result$wts
641
mcsm_wts <- mcsm_wts[complete.cases(mcsm_wts), ]
642
643
## MCSM15-TOC
644
mcsm_wts_toc <- TOcontrol(mcsm_wts, 0.8) # Optimal for 61-90
645
646
# Compute cumulative returns of the portfolios
647
MV <- Return.rebalancing(returns, mv_wts)
648
MES05TOC <- Return.rebalancing(returns, mes_wts_toc)
649
MCSM15TOC <- Return.rebalancing(returns, mcsm_wts_toc)
650
651
# Combine MV, MES05TOC, MCSM15TOC gross cumulative returns
652
portf_ret_comb <- na.omit(merge(MV, MES05TOC, MCSM15TOC, Market, all=F))
653
names(portf_ret_comb) <- c("MV", "MES05-TOC", "MCSM15-TOC", "Market")
654
655
backtest.plot(portf_ret_comb, plotType = "cumRet",
656
main = "MV, MES05-TOC(0.6), MCSM15-TOC(0.8), Stocks 61-90",
657
colorSet = c("red","darkgreen","darkblue","black"),
658
ltySet = c(3, 1, 1, 1), lwdSet = c(0.7, 0.7, 0.7, 0.7))
659
660
661