Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/R/generics.R
1433 views
1
###############################################################################
2
# R (https://r-project.org/) Numeric Methods for Optimization of Portfolios
3
#
4
# Copyright (c) 2004-2021 Brian G. Peterson, Peter Carl, Ross Bennett, Kris Boudt
5
#
6
# This library is distributed under the terms of the GNU Public License (GPL)
7
# for full details see the file COPYING
8
#
9
# $Id$
10
#
11
###############################################################################
12
13
#' Printing output of optimize.portfolio.rebalancing
14
#'
15
#' print method for \code{optimize.portfolio.rebalancing} objects
16
#'
17
#' @param x an object used to select a method
18
#' @param \dots any other passthru parameters
19
#' @param digits the number of significant digits to use when printing.
20
#' @seealso \code{\link{optimize.portfolio.rebalancing}}
21
#' @author Ross Bennett
22
#' @rdname print.optimize.portfolio.rebalancing
23
#' @method print optimize.portfolio.rebalancing
24
25
#' @export
26
print.optimize.portfolio.rebalancing <- function(x, ..., digits=4){
27
cat(rep("*", 50) ,"\n", sep="")
28
cat("PortfolioAnalytics Optimization with Rebalancing\n")
29
cat(rep("*", 50) ,"\n", sep="")
30
31
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
32
"\n\n", sep = "")
33
34
tmp_summary <- summary(x)
35
rebal_dates <- tmp_summary$rebalance_dates
36
num_dates <- length(rebal_dates)
37
cat("Number of rebalancing dates: ", num_dates, "\n")
38
39
cat("First rebalance date:\n")
40
print(rebal_dates[1])
41
42
cat("Last rebalance date:\n")
43
print(rebal_dates[num_dates])
44
45
cat("\n")
46
cat("Annualized Portfolio Rebalancing Return:\n")
47
print(as.numeric(tmp_summary$annualized_returns))
48
cat("\n")
49
50
cat("Annualized Portfolio Standard Deviation:\n")
51
print(as.numeric(tmp_summary$annualized_StdDev))
52
cat("\n")
53
}
54
55
#' summary method for optimize.portfolio.rebalancing
56
#' @param object object of type optimize.portfolio.rebalancing
57
#' @param \dots any other passthru parameters
58
#' @method summary optimize.portfolio.rebalancing
59
#' @export
60
summary.optimize.portfolio.rebalancing <- function(object, ...) {
61
if(!inherits(object,"optimize.portfolio.rebalancing"))
62
stop ("passed object is not of class optimize.portfolio.rebalancing")
63
call <- object$call
64
elapsed_time <- object$elapsed_time
65
66
# Extract the weights and objective measures
67
weights <- extractWeights(object)
68
rebalance_dates <- index(weights)
69
objective_measures <- extractObjectiveMeasures(object)
70
71
# Calculate the portfolio rebalancing returns and some useful
72
# performance metrics
73
portfolio_returns <- Return.rebalancing(object$R, weights)
74
annualized_returns <- Return.annualized(portfolio_returns)
75
annualized_StdDev <- StdDev.annualized(portfolio_returns)
76
downside_risk <- table.DownsideRisk(portfolio_returns)
77
78
# Structure and return
79
return(structure(list(weights=weights,
80
objective_measures=objective_measures,
81
portfolio_returns=portfolio_returns,
82
annualized_returns=annualized_returns,
83
annualized_StdDev=annualized_StdDev,
84
downside_risk=downside_risk,
85
rebalance_dates=rebalance_dates,
86
call=call,
87
elapsed_time=elapsed_time),
88
class="summary.optimize.portfolio.rebalancing")
89
)
90
}
91
92
#' Printing summary output of optimize.portfolio.rebalancing
93
#'
94
#' print method for objects of class \code{summary.optimize.portfolio.rebalancing}
95
#'
96
#' @param x an object of class \code{summary.optimize.portfolio.rebalancing}.
97
#' @param \dots any other passthru parameters
98
#' @param digits number of digits used for printing
99
#' @seealso \code{\link{summary.optimize.portfolio.rebalancing}}
100
#' @author Ross Bennett
101
#' @method print summary.optimize.portfolio.rebalancing
102
103
#' @export
104
print.summary.optimize.portfolio.rebalancing <- function(x, ..., digits=4){
105
cat(rep("*", 50) ,"\n", sep="")
106
cat("PortfolioAnalytics Optimization with Rebalancing\n")
107
cat(rep("*", 50) ,"\n", sep="")
108
109
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
110
"\n\n", sep = "")
111
112
rebal_dates <- x$rebalance_dates
113
num_dates <- length(rebal_dates)
114
cat("First rebalance date:\n")
115
print(rebal_dates[1])
116
cat("\n")
117
cat("Last rebalance date:\n")
118
print(rebal_dates[num_dates])
119
cat("\n")
120
121
cat("Annualized Portfolio Rebalancing Return:\n")
122
print(as.numeric(x$annualized_returns))
123
cat("\n")
124
125
cat("Annualized Portfolio Standard Deviation:\n")
126
print(as.numeric(x$annualized_StdDev))
127
cat("\n")
128
129
cat("Downside Risk Measures:\n")
130
print(x$downside_risk, ...=...)
131
132
# Should we include the optimal weights and objective measure values on the
133
# first or last rebalance date?
134
# cat("Optimal weights on first rebalance date:\n")
135
# print(round(first(x$weights), digits=digits), digits=digits)
136
# cat("\n")
137
138
# cat("Objective measures on first rebalance date:\n")
139
# print(round(first(x$objective_measures), digits=digits), digits=digits)
140
# cat("\n")
141
}
142
143
#' Printing Portfolio Specification Objects
144
#'
145
#' Print method for objects of class \code{portfolio} created with \code{\link{portfolio.spec}}
146
#'
147
#' @param x an object of class \code{portfolio}
148
#' @param \dots any other passthru parameters
149
#' @seealso \code{\link{portfolio.spec}}
150
#' @author Ross Bennett
151
#' @method print portfolio
152
153
#' @export
154
print.portfolio <- function(x, ...){
155
if(!is.portfolio(x)) stop("object passed in is not of class 'portfolio'")
156
157
cat(rep("*", 50) ,"\n", sep="")
158
cat("PortfolioAnalytics Portfolio Specification", "\n")
159
cat(rep("*", 50) ,"\n", sep="")
160
161
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
162
"\n\n", sep = "")
163
164
# Assets
165
#cat("\nAssets\n")
166
nassets <- length(x$assets)
167
cat("Number of assets:", nassets, "\n")
168
cat("Asset Names\n")
169
print(head(names(x$assets), 10))
170
if(nassets > 10){
171
cat("More than 10 assets, only printing the first 10\n")
172
}
173
174
# Category labels
175
if(!is.null(x$category_labels)){
176
cat("\nCategory Labels\n")
177
cat_labels <- x$category_labels
178
for(i in 1:min(10, length(cat_labels))){
179
cat(names(cat_labels)[i],": ")
180
tmp <- names(x$assets[cat_labels[[i]]])
181
cat(tmp, "\n")
182
}
183
if(length(cat_labels) > 10){
184
cat("More than 10 categories, only printing the first 10\n")
185
}
186
cat("\n")
187
}
188
189
# Constraints
190
nconstraints <- length(x$constraints)
191
if(nconstraints > 0){
192
cat("\nConstraints\n")
193
# logical vector of enabled constraints
194
enabled.constraints <- which(sapply(x$constraints, function(x) x$enabled))
195
n.enabled.constraints <- ifelse(length(enabled.constraints) > 0, length(enabled.constraints), 0)
196
} else {
197
enabled.constraints <- NULL
198
n.enabled.constraints <- 0
199
}
200
# character vector of constraint types
201
names.constraints <- sapply(x$constraints, function(x) x$type)
202
#cat("Number of constraints:", nconstraints, "\n")
203
#cat("Number of enabled constraints:", n.enabled.constraints, "\n")
204
if(length(enabled.constraints) > 0){
205
cat("Enabled constraint types\n")
206
constraints <- x$constraints
207
nconstraints <- length(constraints)
208
for(i in 1:nconstraints){
209
if(constraints[[i]]$enabled){
210
type <- constraints[[i]]$type
211
if(type == "box"){
212
# long only
213
if(all(constraints[[i]]$min == 0) & all(constraints[[i]]$max == 1)){
214
cat("\t\t-", "box (long only)", "\n")
215
} else if(all(constraints[[i]]$min == -Inf) & all(constraints[[i]]$max == Inf)){
216
# unconstrained
217
cat("\t\t-", "box (unconstrained)", "\n")
218
} else if(any(constraints[[i]]$min < 0)){
219
# with shorting
220
cat("\t\t-", "box (with shorting)", "\n")
221
} else {
222
cat("\t\t-", type, "\n")
223
}
224
} else {
225
cat("\t\t-", type, "\n")
226
}
227
}
228
}
229
}
230
231
if((nconstraints - n.enabled.constraints) > 0){
232
#cat("Number of disabled constraints:", nconstraints - n.enabled.constraints, "\n")
233
cat("Disabled constraint types\n")
234
constraints <- x$constraints
235
nconstraints <- length(constraints)
236
for(i in 1:nconstraints){
237
if(!constraints[[i]]$enabled){
238
type <- constraints[[i]]$type
239
if(type == "box"){
240
# long only
241
if(all(constraints[[i]]$min == 0) & all(constraints[[i]]$max == 1)){
242
cat("\t\t-", "box (long only)", "\n")
243
} else if(all(constraints[[i]]$min == -Inf) & all(constraints[[i]]$max == Inf)){
244
# unconstrained
245
cat("\t\t-", "box (unconstrained)", "\n")
246
} else if(any(constraints[[i]]$min < 0)){
247
# with shorting
248
cat("\t\t-", "box (with shorting)", "\n")
249
} else {
250
cat("\t\t-", type, "\n")
251
}
252
} else {
253
cat("\t\t-", type, "\n")
254
}
255
}
256
}
257
}
258
259
# Objectives
260
nobjectives <- length(x$objectives)
261
if(nobjectives > 0){
262
cat("\nObjectives:\n")
263
# logical vector of enabled objectives
264
enabled.objectives <- which(sapply(x$objectives, function(x) x$enabled))
265
n.enabled.objectives <- ifelse(length(enabled.objectives) > 0, length(enabled.objectives), 0)
266
} else {
267
enabled.objectives <- NULL
268
n.enabled.objectives <- 0
269
}
270
# character vector of objective names
271
names.objectives <- sapply(x$objectives, function(x) x$name)
272
#cat("Number of objectives:", nobjectives, "\n")
273
#cat("Number of enabled objectives:", n.enabled.objectives, "\n")
274
if(n.enabled.objectives > 0){
275
cat("Enabled objective names\n")
276
for(name in names.objectives[enabled.objectives]) {
277
cat("\t\t-", name, "\n")
278
}
279
}
280
281
if((nobjectives - n.enabled.objectives) > 0){
282
#cat("Number of disabled objectives:", nobjectives - n.enabled.objectives, "\n")
283
cat("Disabled objective names\n")
284
for(name in setdiff(names.objectives, names.objectives[enabled.objectives])) {
285
cat("\t\t-", name, "\n")
286
}
287
}
288
cat("\n")
289
}
290
291
#' Summarize Portfolio Specification Objects
292
#'
293
#' summary method for class \code{portfolio} created with \code{\link{portfolio.spec}}
294
#'
295
#' @param object an object of class \code{portfolio}
296
#' @param \dots any other passthru parameters
297
#' @seealso \code{\link{portfolio.spec}}
298
#' @author Ross Bennett
299
#' @method summary portfolio
300
#' @export
301
summary.portfolio <- function(object, ...){
302
if(!is.portfolio(object)) stop("object passed in is not of class 'portfolio'")
303
304
out <- list()
305
306
out$category_labels <- object$category_labels
307
out$weight_seq <- object$weight_seq
308
out$assets <- object$assets
309
310
# constraints
311
out$enabled_constraints <- list()
312
out$disabled_constraints <- list()
313
constraints <- object$constraints
314
if(length(constraints) >= 1){
315
for(i in 1:length(constraints)){
316
if(constraints[[i]]$enabled){
317
tmp <- length(out$enabled_constraints)
318
out$enabled_constraints[[tmp+1]] <- constraints[[i]]
319
} else {
320
tmp <- length(out$disabled_constraints)
321
out$disabled_constraints[[tmp+1]] <- constraints[[i]]
322
}
323
}
324
}
325
326
# objectives
327
out$enabled_objectives <- list()
328
out$disabled_objectives <- list()
329
objectives <- object$objectives
330
if(length(objectives) >= 1){
331
for(i in 1:length(objectives)){
332
if(objectives[[i]]$enabled){
333
tmp <- length(out$enabled_objectives)
334
out$enabled_objectives[[tmp+1]] <- objectives[[i]]
335
} else {
336
tmp <- length(out$disabled_objectives)
337
out$disabled_objectives[[tmp+1]] <- objectives[[i]]
338
}
339
}
340
}
341
class(out) <- "summary.portfolio"
342
return(out)
343
}
344
345
#' print method for constraint objects
346
#'
347
#' @param x object of class \code{constraint}
348
#' @param \dots any other passthru parameters
349
#' @author Ross Bennett
350
#' @method print constraint
351
352
#' @export
353
print.constraint <- function(x, ...){
354
print.default(x, ...)
355
}
356
357
#' Printing output of optimize.portfolio
358
#'
359
#' print method for \code{optimize.portfolio} objects
360
#'
361
#' @param x an object used to select a method
362
#' @param \dots any other passthru parameters
363
#' @param digits the number of significant digits to use when printing.
364
#' @seealso \code{\link{optimize.portfolio}}
365
#' @author Ross Bennett
366
#' @rdname print.optimize.portfolio
367
#' @method print optimize.portfolio.ROI
368
369
#' @export
370
print.optimize.portfolio.ROI <- function(x, ..., digits=4){
371
cat(rep("*", 35) ,"\n", sep="")
372
cat("PortfolioAnalytics Optimization\n")
373
cat(rep("*", 35) ,"\n", sep="")
374
375
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
376
"\n\n", sep = "")
377
378
# get optimal weights
379
cat("Optimal Weights:\n")
380
print.default(round(x$weights, digits=digits), digits=digits)
381
cat("\n")
382
383
# get objective measure
384
objective_measures <- x$objective_measures
385
tmp_obj <- as.numeric(unlist(objective_measures))
386
names(tmp_obj) <- names(objective_measures)
387
cat("Objective Measure:\n")
388
for(i in 1:length(objective_measures)){
389
print(tmp_obj[i], digits=digits)
390
cat("\n")
391
if(length(objective_measures[[i]]) > 1){
392
# This will be the case for any objective measures with HHI for QP problems
393
for(j in 2:length(objective_measures[[i]])){
394
tmpl <- objective_measures[[i]][j]
395
cat(names(tmpl), "\n")
396
tmpv <- unlist(tmpl)
397
names(tmpv) <- gsub(paste(names(tmpl), ".", sep=""), "", names(tmpv))
398
print.default(round(tmpv, digits=digits), digits=digits)
399
cat("\n")
400
}
401
}
402
cat("\n")
403
}
404
cat("\n")
405
}
406
407
408
#' @rdname print.optimize.portfolio
409
#' @method print optimize.portfolio.CVXR
410
411
#' @export
412
print.optimize.portfolio.CVXR <- function(x, ..., digits=4){
413
cat(rep("*", 35) ,"\n", sep="")
414
cat("PortfolioAnalytics Optimization\n")
415
cat(rep("*", 35) ,"\n", sep="")
416
417
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
418
"\n\n", sep = "")
419
420
# get optimal weights
421
cat("Optimal Weights:\n")
422
print.default(round(x$weights, digits=digits), digits=digits)
423
cat("\n")
424
425
# get objective measures
426
objective_measures <- x$objective_measures
427
tmp_obj <- as.numeric(unlist(objective_measures))
428
names(tmp_obj) <- names(objective_measures)
429
cat("Objective Measures:\n")
430
for(i in 1:length(objective_measures)){
431
print(tmp_obj[i], digits=4)
432
cat("\n")
433
if(length(objective_measures[[i]]) > 1){
434
# This will be the case for any objective measures with risk budgets
435
for(j in 2:length(objective_measures[[i]])){
436
tmpl <- objective_measures[[i]][j]
437
cat(names(tmpl), ":\n")
438
tmpv <- unlist(tmpl)
439
names(tmpv) <- names(x$weights)
440
print.default(round(tmpv, digits=digits), digits=digits)
441
cat("\n")
442
}
443
}
444
cat("\n")
445
}
446
cat("\n")
447
}
448
449
450
#' @rdname print.optimize.portfolio
451
#' @method print optimize.portfolio.random
452
453
#' @export
454
print.optimize.portfolio.random <- function(x, ..., digits=4){
455
cat(rep("*", 35) ,"\n", sep="")
456
cat("PortfolioAnalytics Optimization\n")
457
cat(rep("*", 35) ,"\n", sep="")
458
459
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
460
"\n\n", sep = "")
461
462
# get optimal weights
463
cat("Optimal Weights:\n")
464
print.default(round(x$weights, digits=digits), digits=digits)
465
cat("\n")
466
467
# get objective measures
468
objective_measures <- x$objective_measures
469
tmp_obj <- as.numeric(unlist(objective_measures))
470
names(tmp_obj) <- names(objective_measures)
471
cat("Objective Measures:\n")
472
for(i in 1:length(objective_measures)){
473
print(tmp_obj[i], digits=4)
474
cat("\n")
475
if(length(objective_measures[[i]]) > 1){
476
# This will be the case for any objective measures with risk budgets
477
for(j in 2:length(objective_measures[[i]])){
478
tmpl <- objective_measures[[i]][j]
479
cat(names(tmpl), ":\n")
480
tmpv <- unlist(tmpl)
481
names(tmpv) <- names(x$weights)
482
print(tmpv, digits=digits)
483
cat("\n")
484
}
485
}
486
cat("\n")
487
}
488
cat("\n")
489
}
490
491
492
#' @rdname print.optimize.portfolio
493
#' @method print optimize.portfolio.DEoptim
494
495
#' @export
496
print.optimize.portfolio.DEoptim <- function(x, ..., digits=4){
497
cat(rep("*", 35) ,"\n", sep="")
498
cat("PortfolioAnalytics Optimization\n")
499
cat(rep("*", 35) ,"\n", sep="")
500
501
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
502
"\n\n", sep = "")
503
504
# get optimal weights
505
cat("Optimal Weights:\n")
506
print.default(round(x$weights, digits=digits), digits=digits)
507
cat("\n")
508
509
# get objective measures
510
objective_measures <- x$objective_measures
511
tmp_obj <- as.numeric(unlist(objective_measures))
512
names(tmp_obj) <- names(objective_measures)
513
cat("Objective Measures:\n")
514
for(i in 1:length(objective_measures)){
515
print(tmp_obj[i], digits=4)
516
cat("\n")
517
if(length(objective_measures[[i]]) > 1){
518
# This will be the case for any objective measures with risk budgets
519
for(j in 2:length(objective_measures[[i]])){
520
tmpl <- objective_measures[[i]][j]
521
cat(names(tmpl), ":\n")
522
tmpv <- unlist(tmpl)
523
names(tmpv) <- names(x$weights)
524
print(tmpv, digits=digits)
525
cat("\n")
526
}
527
}
528
cat("\n")
529
}
530
cat("\n")
531
}
532
533
534
#' @rdname print.optimize.portfolio
535
#' @method print optimize.portfolio.GenSA
536
537
#' @export
538
print.optimize.portfolio.GenSA <- function(x, ..., digits=4){
539
cat(rep("*", 35) ,"\n", sep="")
540
cat("PortfolioAnalytics Optimization\n")
541
cat(rep("*", 35) ,"\n", sep="")
542
543
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
544
"\n\n", sep = "")
545
546
# get optimal weights
547
cat("Optimal Weights:\n")
548
print.default(round(x$weights, digits=digits), digits=digits)
549
cat("\n")
550
551
# get objective measures
552
objective_measures <- x$objective_measures
553
tmp_obj <- as.numeric(unlist(objective_measures))
554
names(tmp_obj) <- names(objective_measures)
555
cat("Objective Measures:\n")
556
for(i in 1:length(objective_measures)){
557
print(tmp_obj[i], digits=4)
558
cat("\n")
559
if(length(objective_measures[[i]]) > 1){
560
# This will be the case for any objective measures with risk budgets
561
for(j in 2:length(objective_measures[[i]])){
562
tmpl <- objective_measures[[i]][j]
563
cat(names(tmpl), ":\n")
564
tmpv <- unlist(tmpl)
565
names(tmpv) <- names(x$weights)
566
print(tmpv, digits=digits)
567
cat("\n")
568
}
569
}
570
cat("\n")
571
}
572
cat("\n")
573
}
574
575
576
#' @rdname print.optimize.portfolio
577
#' @method print optimize.portfolio.pso
578
579
#' @export
580
print.optimize.portfolio.pso <- function(x, ..., digits=4){
581
cat(rep("*", 35) ,"\n", sep="")
582
cat("PortfolioAnalytics Optimization\n")
583
cat(rep("*", 35) ,"\n", sep="")
584
585
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
586
"\n\n", sep = "")
587
588
# get optimal weights
589
cat("Optimal Weights:\n")
590
print.default(round(x$weights, digits=digits), digits=digits)
591
cat("\n")
592
593
# get objective measures
594
objective_measures <- x$objective_measures
595
tmp_obj <- as.numeric(unlist(objective_measures))
596
names(tmp_obj) <- names(objective_measures)
597
cat("Objective Measures:\n")
598
for(i in 1:length(objective_measures)){
599
print(tmp_obj[i], digits=4)
600
cat("\n")
601
if(length(objective_measures[[i]]) > 1){
602
# This will be the case for any objective measures with risk budgets
603
for(j in 2:length(objective_measures[[i]])){
604
tmpl <- objective_measures[[i]][j]
605
cat(names(tmpl), ":\n")
606
tmpv <- unlist(tmpl)
607
names(tmpv) <- names(x$weights)
608
print(tmpv, digits=digits)
609
cat("\n")
610
}
611
}
612
cat("\n")
613
}
614
cat("\n")
615
}
616
617
#' Printing summary output of optimize.portfolio
618
#'
619
#' print method for objects of class \code{summary.optimize.portfolio}
620
#'
621
#' @param x an object of class \code{summary.optimize.portfolio}.
622
#' @param ... any other passthru parameters. Currently not used.
623
#' @seealso \code{\link{summary.optimize.portfolio}}
624
#' @author Ross Bennett
625
#' @method print summary.optimize.portfolio
626
627
#' @export
628
print.summary.optimize.portfolio <- function(x, ...){
629
630
cat(rep("*", 50) ,"\n", sep="")
631
cat("PortfolioAnalytics Optimization Summary", "\n")
632
cat(rep("*", 50) ,"\n", sep="")
633
634
# show the call to optimize.portfolio
635
cat("\nCall:\n")
636
print(x$call)
637
cat("\n")
638
639
# get optimal weights
640
cat("Optimal Weights:\n")
641
print.default(round(x$weights, digits=4))
642
cat("\n")
643
644
# objective measures
645
# The objective measure is object$out for ROI
646
cat("Objective Measures:\n")
647
if(!is.null(x$objective_values)){
648
# get objective measures
649
objective_measures <- x$objective_values
650
tmp_obj <- as.numeric(unlist(objective_measures))
651
names(tmp_obj) <- names(objective_measures)
652
for(i in 1:length(objective_measures)){
653
print.default(tmp_obj[i], digits=4)
654
cat("\n")
655
if(length(objective_measures[[i]]) > 1){
656
# This will be the case for any objective measures with risk budgets
657
for(j in 2:length(objective_measures[[i]])){
658
tmpl <- objective_measures[[i]][j]
659
cat(names(tmpl), ":\n")
660
tmpv <- unlist(tmpl)
661
names(tmpv) <- names(x$weights)
662
print.default(tmpv)
663
cat("\n")
664
}
665
}
666
cat("\n")
667
}
668
} else {
669
print.default(as.numeric(x$out))
670
}
671
672
# get initial portfolio
673
cat("Portfolio Assets and Initial Weights:\n")
674
print.default(x$initial_weights)
675
cat("\n")
676
677
# print the portfolio object
678
print(x$portfolio)
679
680
# Constraints
681
cat(rep("*", 40), "\n", sep="")
682
cat("Constraints\n")
683
cat(rep("*", 40), "\n", sep="")
684
685
# leverage constraints
686
cat("Leverage Constraint:\n")
687
if(!is.null(x$leverage_constraint)){
688
cat("min_sum = ", x$leverage_constraint$min_sum, "\n", sep="")
689
cat("max_sum = ", x$leverage_constraint$max_sum, "\n", sep="")
690
cat("actual_leverage = ", x$leverage_constraint$actual, "\n", sep="")
691
cat("\n")
692
}
693
694
# box constraints
695
cat("Box Constraints:\n")
696
if(!is.null(x$box_constraint)){
697
cat("min:\n")
698
print.default(x$box_constraint$min)
699
cat("max:\n")
700
print.default(x$box_constraint$max)
701
cat("\n")
702
}
703
704
# group constraints
705
group_weights <- NULL
706
if(!is.null(x$group_constraint)){
707
cat("Group Constraints:\n")
708
cat("Groups:\n")
709
print.default(x$group_constraint$groups)
710
cat("\n")
711
cat("Lower bound on group weights, group_min:\n")
712
print.default(x$group_constraint$group_min)
713
cat("\n")
714
cat("Upper bound on group weights, group_max:\n")
715
print.default(x$group_constraint$group_max)
716
cat("\n")
717
# cat("Group position limits, group_pos:\n")
718
# group_pos <- constraints$group_pos
719
# if(!is.null(group_pos)) names(group_pos) <- group_labels
720
# print(group_pos)
721
# cat("\n")
722
723
cat("Group Weights:\n")
724
print.default(x$group_constraint$group_weights_actual)
725
cat("\n")
726
}
727
tolerance <- .Machine$double.eps^0.5
728
729
# position limit constraints
730
cat("Position Limit Constraints:\n")
731
cat("Maximum number of non-zero weights, max_pos:\n")
732
if(!is.null(x$position_limit_constraint[["max_pos"]])){
733
print.default(x$position_limit_constraint[["max_pos"]])
734
} else {
735
print("Unconstrained")
736
}
737
cat("Realized number of non-zero weights (i.e. positions):\n")
738
print.default(x$position_limit_constraint$max_pos_actual)
739
cat("\n")
740
741
cat("Maximum number of long positions, max_pos_long:\n")
742
if(!is.null(x$position_limit_constraint[["max_pos_long"]])){
743
print.default(x$position_limit_constraint[["max_pos_long"]])
744
} else {
745
print("Unconstrained")
746
}
747
cat("Realized number of long positions:\n")
748
print.default(x$position_limit_constraint$max_pos_long_actual)
749
cat("\n")
750
751
cat("Maximum number of short positions, max_pos_short:\n")
752
if(!is.null(x$position_limit_constraint[["max_pos_short"]])){
753
print.default(x$position_limit_constraint[["max_pos_short"]])
754
} else {
755
print("Unconstrained")
756
}
757
cat("Realized number of short positions:\n")
758
print.default(x$position_limit_constraint$max_pos_short_actual)
759
cat("\n\n")
760
761
# diversification
762
cat("Diversification Target Constraint:\n")
763
if(!is.null(x$diversification_constraint$diversification_target)){
764
print.default(x$diversification_constraint$diversification_target)
765
} else {
766
print("Unconstrained")
767
}
768
cat("\n")
769
cat("Realized diversification:\n")
770
print.default(x$diversification_constraint$diversification_actual)
771
cat("\n")
772
773
# turnover
774
cat("Turnover Target Constraint:\n")
775
if(!is.null(x$turnover_constraint$turnover_target)){
776
print.default(x$turnover_constraint$turnover_target)
777
} else {
778
print("Unconstrained")
779
}
780
cat("\n")
781
cat("Realized turnover from initial weights:\n")
782
print.default(x$turnover_constraint$turnover_actual)
783
cat("\n")
784
785
# Factor exposure constraint
786
if(!is.null(x$factor_exposure_constraint)){
787
cat("Factor Exposure Constraints:\n")
788
cat("Factor Exposure B Matrix:\n")
789
print.default(x$factor_exposure_constraint$B)
790
cat("\n")
791
cat("Lower bound on factor exposures, lower:\n")
792
print.default(x$factor_exposure_constraint$lower)
793
cat("\n")
794
cat("Upper bound on group weights, upper:\n")
795
print.default(x$factor_exposure_constraint$upper)
796
cat("\n")
797
cat("Realized Factor Exposures:\n")
798
print.default(x$factor_exposure_constraint$exposure_actual)
799
cat("\n\n")
800
}
801
802
# Objectives
803
cat(rep("*", 40), "\n", sep="")
804
cat("Objectives\n")
805
cat(rep("*", 40), "\n\n", sep="")
806
807
for(obj in x$portfolio$objectives){
808
cat("Objective:", class(obj)[1], "\n")
809
print.default(obj)
810
cat("\n", rep("*", 40), "\n", sep="")
811
}
812
cat("\n")
813
814
# show the elapsed time for the optimization
815
cat("Elapsed Time:\n")
816
print(x$elapsed_time)
817
cat("\n")
818
}
819
820
#' Summarizing output of optimize.portfolio
821
#'
822
#' summary method for class \code{optimize.portfolio}
823
#'
824
#' @param object an object of class \code{optimize.portfolio}.
825
#' @param ... any other passthru parameters. Currently not used.
826
#' @seealso \code{\link{optimize.portfolio}}
827
#' @author Ross Bennett
828
#' @method summary optimize.portfolio
829
830
#' @export
831
summary.optimize.portfolio <- function(object, ...){
832
833
out <- list()
834
835
out$call <- object$call
836
837
# optimal weights
838
opt_weights <- extractWeights(object)
839
out$weights <- opt_weights
840
841
# objective measure values
842
out$objective_values <- extractObjectiveMeasures(object)
843
844
# optimization time
845
out$elapsed_time <- object$elapsed_time
846
847
# initial weights
848
initial_weights <- object$portfolio$assets
849
out$initial_weights <- initial_weights
850
851
### constraint realization
852
constraints <- get_constraints(object$portfolio)
853
# leverage
854
leverage_constraint <- list()
855
leverage_constraint$min_sum <- constraints$min_sum
856
leverage_constraint$max_sum <- constraints$max_sum
857
leverage_constraint$actual <- sum(opt_weights)
858
out$leverage_constraint <- leverage_constraint
859
860
# box
861
box_constraint <- list()
862
box_constraint$min <- constraints$min
863
box_constraint$max <- constraints$max
864
box_constraint$actual <- opt_weights
865
out$box_constraint <- box_constraint
866
867
# group
868
if(!is.null(constraints$groups)){
869
asset_names <- names(opt_weights)
870
group_constraint <- list()
871
group_constraint$groups <- list()
872
groups <- constraints$groups
873
for(i in 1:length(groups)){
874
groups[[i]] <- asset_names[groups[[i]]]
875
}
876
group_constraint$groups <- groups
877
group_constraint$group_min <- constraints$cLO
878
group_constraint$group_max <- constraints$cUP
879
group_constraint$group_pos <- constraints$group_pos
880
881
# actual weights by group and/or category
882
tmp_groups <- extractGroups(object)
883
group_constraint$group_weights_actual <- tmp_groups$group_weights
884
out$group_constraint <- group_constraint
885
}
886
887
# category weights
888
if(is.null(constraints$groups) & !is.null(object$portfolio$category_labels)){
889
category_weights <- list()
890
category_weights$category_weights <- object$portfolio$category_labels
891
tmp_groups <- extractGroups(object)
892
category_weights$category_weights_actual <- tmp_groups$category_weights
893
out$category_weights <- category_weights
894
}
895
896
# factor exposure
897
if(!is.null(constraints$B) & !is.null(constraints$lower) & !is.null(constraints$upper)){
898
factor_exposure_constraint <- list()
899
factor_exposure_constraint$B <- constraints$B
900
factor_exposure_constraint$lower <- constraints$lower
901
names(factor_exposure_constraint$lower) <- colnames(constraints$B)
902
factor_exposure_constraint$upper <- constraints$upper
903
names(factor_exposure_constraint$upper) <- colnames(constraints$B)
904
905
t.B <- t(constraints$B)
906
tmpexp <- vector(mode="numeric", length=nrow(t.B))
907
for(i in 1:nrow(t.B)){
908
tmpexp[i] <- t(opt_weights) %*% t.B[i, ]
909
}
910
names(tmpexp) <- rownames(t.B)
911
factor_exposure_constraint$exposure_actual <- tmpexp
912
out$factor_exposure_constraint <- factor_exposure_constraint
913
}
914
915
# position limit
916
tolerance <- .Machine$double.eps^0.5
917
position_limit_constraint <- list()
918
position_limit_constraint$max_pos <- constraints$max_pos
919
position_limit_constraint$max_pos_long <- constraints$max_pos_long
920
position_limit_constraint$max_pos_short <- constraints$max_pos_short
921
# number of positions with non-zero weights
922
position_limit_constraint$max_pos_actual <- sum(abs(object$weights) > tolerance)
923
# actual long positions
924
position_limit_constraint$max_pos_long_actual <- sum(object$weights > tolerance)
925
# actual short positions
926
position_limit_constraint$max_pos_short_actual <- sum(object$weights < -tolerance)
927
out$position_limit_constraint <- position_limit_constraint
928
929
# diversification
930
diversification_constraint <- list()
931
# target diversification
932
diversification_constraint$diversification_target <- constraints$div_target
933
# actual realized diversification
934
diversification_constraint$diversification_actual <- diversification(opt_weights)
935
out$diversification_constraint <- diversification_constraint
936
937
# turnover
938
turnover_constraint <- list()
939
turnover_constraint$turnover_target <- constraints$turnover_target
940
turnover_constraint$turnover_actual <- turnover(opt_weights, wts.init=initial_weights)
941
out$turnover_constraint <- turnover_constraint
942
943
# original portfolio object
944
out$portfolio <- object$portfolio
945
946
class(out) <- "summary.optimize.portfolio"
947
return(out)
948
}
949
950
#' Print an efficient frontier object
951
#'
952
#' Print method for efficient frontier objects. Display the call to create or
953
#' extract the efficient frontier object and the portfolio from which the
954
#' efficient frontier was created or extracted.
955
#'
956
#' @param x objective of class \code{efficient.frontier}
957
#' @param \dots any other passthru parameters
958
#' @seealso \code{\link{create.EfficientFrontier}}
959
#' @author Ross Bennett
960
#' @method print efficient.frontier
961
962
#' @export
963
print.efficient.frontier <- function(x, ...){
964
if(!inherits(x, "efficient.frontier")) stop("object passed in is not of class 'efficient.frontier'")
965
966
cat(rep("*", 50) ,"\n", sep="")
967
cat("PortfolioAnalytics Efficient Frontier", "\n")
968
cat(rep("*", 50) ,"\n", sep="")
969
970
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
971
"\n\n", sep = "")
972
973
cat("Efficient Frontier Points:", nrow(x$frontier), "\n\n")
974
975
print(x$portfolio)
976
}
977
978
#' Summarize an efficient frontier object
979
#'
980
#' Summary method for efficient frontier objects. Display the call to create or
981
#' extract the efficient frontier object as well as the weights and risk and
982
#' return metrics along the efficient frontier.
983
#'
984
#' @param object object of class \code{efficient.frontier}
985
#' @param ... passthrough parameters
986
#' @param digits number of digits to round to
987
#' @author Ross Bennett
988
#' @method summary efficient.frontier
989
#' @export
990
summary.efficient.frontier <- function(object, ..., digits=3){
991
if(!inherits(object, "efficient.frontier")) stop("object passed in is not of class 'efficient.frontier'")
992
993
cat(rep("*", 50) ,"\n", sep="")
994
cat("PortfolioAnalytics Efficient Frontier", "\n")
995
cat(rep("*", 50) ,"\n", sep="")
996
997
cat("\nCall:\n", paste(deparse(object$call), sep = "\n", collapse = "\n"),
998
"\n\n", sep = "")
999
1000
cat("Efficient Frontier Points:", nrow(object$frontier), "\n\n")
1001
1002
# Weights
1003
cnames <- colnames(object$frontier)
1004
wts_idx <- grep(pattern="^w\\.", cnames)
1005
wts <- round(object$frontier[, wts_idx], digits=digits)
1006
colnames(wts) <- gsub("w.", "", colnames(wts))
1007
rownames(wts) <- 1:nrow(object$frontier)
1008
cat("Weights along the efficient frontier:\n")
1009
print(round(wts, digits=digits))
1010
cat("\n")
1011
1012
# Risk and return
1013
cat("Risk and return metrics along the efficient frontier:\n")
1014
riskret <- object$frontier[, -wts_idx]
1015
rownames(riskret) <- 1:nrow(object$frontier)
1016
print(round(riskret, digits=digits))
1017
cat("\n")
1018
invisible(list(weights=wts, metrics=riskret))
1019
}
1020
1021
#' @method print portfolio.list
1022
1023
#' @export
1024
print.portfolio.list <- function(x, ...){
1025
for(i in 1:length(x)){
1026
cat("Portfolio ", i, "\n", sep="")
1027
print(x[[i]])
1028
}
1029
}
1030
1031
#' @method print opt.list
1032
1033
#' @export
1034
print.opt.list <- function(x, ...){
1035
for(i in 1:length(x)){
1036
cat("Optimization ", i, "\n", sep="")
1037
print(x[[i]])
1038
}
1039
}
1040
1041
#' @method print opt.rebal.list
1042
1043
#' @export
1044
print.opt.rebal.list <- function(x, ...){
1045
for(i in 1:length(x)){
1046
cat("Optimization ", i, "\n", sep="")
1047
print(x[[i]])
1048
}
1049
}
1050
1051
#' @method print regime.portfolios
1052
1053
#' @export
1054
print.regime.portfolios <- function(x, ...){
1055
1056
cat(rep("*", 50) ,"\n", sep="")
1057
cat("PortfolioAnalytics Regime Switching Specification", "\n")
1058
cat(rep("*", 50) ,"\n\n", sep="")
1059
1060
# Should we print the regime object information?
1061
1062
portf <- x$portfolio.list
1063
for(i in 1:length(portf)){
1064
cat("Regime ", i, " Portfolio", "\n", sep="")
1065
print(portf[[i]])
1066
}
1067
}
1068
1069
#' @method summary optimize.portfolio.parallel
1070
1071
#' @export
1072
summary.optimize.portfolio.parallel <- function(object, ...){
1073
out <- list()
1074
out$call <- object$call
1075
out$elapsed_time <- object$elapsed_time
1076
out$n_optimizations <- length(object$optimizations)
1077
xx <- lapply(object$optimizations, function(x) {
1078
tmp <- extractStats(x)
1079
out <- tmp[which.min(tmp[,"out"]),]
1080
out})
1081
stats <- do.call(rbind, xx)
1082
out$stats <- stats
1083
out$obj_val <- stats[,"out"]
1084
class(out) <- "summary.optimize.portfolio.parallel"
1085
return(out)
1086
}
1087
1088
#' @method print optimize.portfolio.parallel
1089
1090
#' @export
1091
print.optimize.portfolio.parallel <- function(x, ..., probs = c(0.025, 0.975)){
1092
cat(rep("*", 35) ,"\n", sep="")
1093
cat("PortfolioAnalytics Optimization\n")
1094
cat(rep("*", 35) ,"\n", sep="")
1095
1096
cat("\nCall:\n", paste(deparse(x$call), sep = "\n", collapse = "\n"),
1097
"\n\n", sep = "")
1098
1099
# call the summary method
1100
xx <- summary(x)
1101
1102
cat("Number of Optimizations:\n")
1103
print(xx$n_optimizations)
1104
1105
cat("Objective Value Estimate:\n")
1106
print(mean(xx$obj_val))
1107
1108
cat("Objective Value Estimate Percentiles:\n")
1109
print(quantile(xx$obj_val, probs = probs))
1110
1111
cat("Elapsed Time:\n")
1112
print(xx$elapsed_time)
1113
}
1114
1115