Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/R/charts.PSO.R
1433 views
1
2
chart.Weight.pso <- function(object, ..., neighbors = NULL, main="Weights", las = 3, xlab=NULL, cex.lab = 1, element.color = "darkgray", cex.axis=0.8, colorset=NULL, legend.loc="topright", cex.legend=0.8, plot.type="line"){
3
4
if(!inherits(object, "optimize.portfolio.pso")) stop("object must be of class 'optimize.portfolio.pso'")
5
6
if(plot.type %in% c("bar", "barplot")){
7
barplotWeights(object=object, ..., main=main, las=las, xlab=xlab, cex.lab=cex.lab, element.color=element.color, cex.axis=cex.axis, legend.loc=legend.loc, cex.legend=cex.legend, colorset=colorset)
8
} else if(plot.type == "line"){
9
10
columnnames = names(object$weights)
11
numassets = length(columnnames)
12
13
constraints <- get_constraints(object$portfolio)
14
15
if(is.null(xlab))
16
minmargin = 3
17
else
18
minmargin = 5
19
if(main=="") topmargin=1 else topmargin=4
20
if(las > 1) {# set the bottom border to accommodate labels
21
bottommargin = max(c(minmargin, (strwidth(columnnames,units="in"))/par("cin")[1])) * cex.lab
22
if(bottommargin > 10 ) {
23
bottommargin<-10
24
columnnames<-substr(columnnames,1,19)
25
# par(srt=45) #TODO figure out how to use text() and srt to rotate long labels
26
}
27
}
28
else {
29
bottommargin = minmargin
30
}
31
par(mar = c(bottommargin, 4, topmargin, 2) +.1)
32
if(any(is.infinite(constraints$max)) | any(is.infinite(constraints$min))){
33
# set ylim based on weights if box constraints contain Inf or -Inf
34
ylim <- range(object$weights)
35
} else {
36
# set ylim based on the range of box constraints min and max
37
ylim <- range(c(constraints$min, constraints$max))
38
}
39
plot(object$weights, type="b", col="blue", axes=FALSE, xlab='', ylim=ylim, ylab="Weights", main=main, pch=16, ...)
40
if(!any(is.infinite(constraints$min))){
41
points(constraints$min, type="b", col="darkgray", lty="solid", lwd=2, pch=24)
42
}
43
if(!any(is.infinite(constraints$max))){
44
points(constraints$max, type="b", col="darkgray", lty="solid", lwd=2, pch=25)
45
}
46
# if(!is.null(neighbors)){
47
# if(is.vector(neighbors)){
48
# xtract=extractStats(ROI)
49
# weightcols<-grep('w\\.',colnames(xtract)) #need \\. to get the dot
50
# if(length(neighbors)==1){
51
# # overplot nearby portfolios defined by 'out'
52
# orderx = order(xtract[,"out"])
53
# subsetx = head(xtract[orderx,], n=neighbors)
54
# for(i in 1:neighbors) points(subsetx[i,weightcols], type="b", col="lightblue")
55
# } else{
56
# # assume we have a vector of portfolio numbers
57
# subsetx = xtract[neighbors,weightcols]
58
# for(i in 1:length(neighbors)) points(subsetx[i,], type="b", col="lightblue")
59
# }
60
# }
61
# if(is.matrix(neighbors) | is.data.frame(neighbors)){
62
# # the user has likely passed in a matrix containing calculated values for risk.col and return.col
63
# nbweights<-grep('w\\.',colnames(neighbors)) #need \\. to get the dot
64
# for(i in 1:nrow(neighbors)) points(as.numeric(neighbors[i,nbweights]), type="b", col="lightblue")
65
# # note that here we need to get weight cols separately from the matrix, not from xtract
66
# # also note the need for as.numeric. points() doesn't like matrix inputs
67
# }
68
# }
69
# points(ROI$weights, type="b", col="blue", pch=16)
70
axis(2, cex.axis = cex.axis, col = element.color)
71
axis(1, labels=columnnames, at=1:numassets, las=las, cex.axis = cex.axis, col = element.color)
72
box(col = element.color)
73
}
74
}
75
76
#' @rdname chart.Weights
77
#' @method chart.Weights optimize.portfolio.pso
78
#' @export
79
chart.Weights.optimize.portfolio.pso <- chart.Weight.pso
80
81
chart.Scatter.pso <- function(object, ..., neighbors=NULL, return.col="mean", risk.col="ES", chart.assets=FALSE, element.color = "darkgray", cex.axis=0.8, xlim=NULL, ylim=NULL){
82
if(!inherits(object, "optimize.portfolio.pso")) stop("object must be of class 'optimize.portfolio.pso'")
83
84
R <- object$R
85
if(is.null(R)) stop("Returns object not detected, must run optimize.portfolio with trace=TRUE")
86
# portfolio <- object$portfolio
87
xtract = extractStats(object)
88
columnnames = colnames(xtract)
89
#return.column = grep(paste("objective_measures",return.col,sep='.'),columnnames)
90
return.column = pmatch(return.col,columnnames)
91
if(is.na(return.column)) {
92
return.col = paste(return.col,return.col,sep='.')
93
return.column = pmatch(return.col,columnnames)
94
}
95
#risk.column = grep(paste("objective_measures",risk.col,sep='.'),columnnames)
96
risk.column = pmatch(risk.col,columnnames)
97
if(is.na(risk.column)) {
98
risk.col = paste(risk.col,risk.col,sep='.')
99
risk.column = pmatch(risk.col,columnnames)
100
}
101
102
# if(is.na(return.column) | is.na(risk.column)) stop(return.col,' or ',risk.col, ' do not match extractStats output')
103
104
# If the user has passed in return.col or risk.col that does not match extractStats output
105
# This will give the flexibility of passing in return or risk metrics that are not
106
# objective measures in the optimization. This may cause issues with the "neighbors"
107
# functionality since that is based on the "out" column
108
if(is.na(return.column) | is.na(risk.column)){
109
return.col <- gsub("\\..*", "", return.col)
110
risk.col <- gsub("\\..*", "", risk.col)
111
warning(return.col,' or ', risk.col, ' do not match extractStats output of $objective_measures slot')
112
# Get the matrix of weights for applyFUN
113
wts_index <- grep("w.", columnnames)
114
wts <- xtract[, wts_index]
115
if(is.na(return.column)){
116
tmpret <- applyFUN(R=R, weights=wts, FUN=return.col)
117
xtract <- cbind(tmpret, xtract)
118
colnames(xtract)[which(colnames(xtract) == "tmpret")] <- return.col
119
}
120
if(is.na(risk.column)){
121
tmprisk <- applyFUN(R=R, weights=wts, FUN=risk.col)
122
xtract <- cbind(tmprisk, xtract)
123
colnames(xtract)[which(colnames(xtract) == "tmprisk")] <- risk.col
124
}
125
columnnames = colnames(xtract)
126
return.column = pmatch(return.col,columnnames)
127
if(is.na(return.column)) {
128
return.col = paste(return.col,return.col,sep='.')
129
return.column = pmatch(return.col,columnnames)
130
}
131
risk.column = pmatch(risk.col,columnnames)
132
if(is.na(risk.column)) {
133
risk.col = paste(risk.col,risk.col,sep='.')
134
risk.column = pmatch(risk.col,columnnames)
135
}
136
}
137
if(chart.assets){
138
# Get the arguments from the optimize.portfolio$portfolio object
139
# to calculate the risk and return metrics for the scatter plot.
140
# (e.g. arguments=list(p=0.925, clean="boudt")
141
arguments <- NULL # maybe an option to let the user pass in an arguments list?
142
if(is.null(arguments)){
143
tmp.args <- unlist(lapply(object$portfolio$objectives, function(x) x$arguments), recursive=FALSE)
144
tmp.args <- tmp.args[!duplicated(names(tmp.args))]
145
if(!is.null(tmp.args$portfolio_method)) tmp.args$portfolio_method <- "single"
146
arguments <- tmp.args
147
}
148
# Include risk reward scatter of asset returns
149
asset_ret <- scatterFUN(R=R, FUN=return.col, arguments)
150
asset_risk <- scatterFUN(R=R, FUN=risk.col, arguments)
151
xlim <- range(c(xtract[,risk.column], asset_risk))
152
ylim <- range(c(xtract[,return.column], asset_ret))
153
} else {
154
asset_ret <- NULL
155
asset_risk <- NULL
156
}
157
158
# plot the portfolios from PSOoutput
159
plot(xtract[,risk.column],xtract[,return.column], xlab=risk.col, ylab=return.col, col="darkgray", axes=FALSE, xlim=xlim, ylim=ylim, ...)
160
161
## @TODO: Generalize this to find column containing the "risk" metric
162
if(length(names(object)[which(names(object)=='constrained_objective')])) {
163
result.slot<-'constrained_objective'
164
} else {
165
result.slot<-'objective_measures'
166
}
167
objcols<-unlist(object[[result.slot]])
168
names(objcols)<-name.replace(names(objcols))
169
return.column = pmatch(return.col,names(objcols))
170
if(is.na(return.column)) {
171
return.col = paste(return.col,return.col,sep='.')
172
return.column = pmatch(return.col,names(objcols))
173
}
174
risk.column = pmatch(risk.col,names(objcols))
175
if(is.na(risk.column)) {
176
risk.col = paste(risk.col,risk.col,sep='.')
177
risk.column = pmatch(risk.col,names(objcols))
178
}
179
# risk and return metrics for the optimal weights if the RP object does not
180
# contain the metrics specified by return.col or risk.col
181
if(is.na(return.column) | is.na(risk.column)){
182
return.col <- gsub("\\..*", "", return.col)
183
risk.col <- gsub("\\..*", "", risk.col)
184
# warning(return.col,' or ', risk.col, ' do not match extractStats output of $objective_measures slot')
185
opt_weights <- object$weights
186
ret <- as.numeric(applyFUN(R=R, weights=opt_weights, FUN=return.col))
187
risk <- as.numeric(applyFUN(R=R, weights=opt_weights, FUN=risk.col))
188
points(risk, ret, col="blue", pch=16) #optimal
189
text(x=risk, y=ret, labels="Optimal",col="blue", pos=4, cex=0.8)
190
} else {
191
points(objcols[risk.column], objcols[return.column], col="blue", pch=16) # optimal
192
text(x=objcols[risk.column], y=objcols[return.column], labels="Optimal",col="blue", pos=4, cex=0.8)
193
}
194
195
# plot the risk-reward scatter of the assets
196
if(chart.assets){
197
points(x=asset_risk, y=asset_ret)
198
text(x=asset_risk, y=asset_ret, labels=colnames(R), pos=4, cex=0.8)
199
}
200
201
axis(1, cex.axis = cex.axis, col = element.color)
202
axis(2, cex.axis = cex.axis, col = element.color)
203
box(col = element.color)
204
}
205
206
#' @rdname chart.RiskReward
207
#' @method chart.RiskReward optimize.portfolio.pso
208
#' @export
209
chart.RiskReward.optimize.portfolio.pso <- chart.Scatter.pso
210
211
212
charts.pso <- function(pso, return.col="mean", risk.col="ES", chart.assets=FALSE, cex.axis=0.8, element.color="darkgray", neighbors=NULL, main="PSO.Portfolios", xlim=NULL, ylim=NULL, ...){
213
# Specific to the output of the optimize_method=pso
214
op <- par(no.readonly=TRUE)
215
layout(matrix(c(1,2)),heights=c(2,2),widths=1)
216
par(mar=c(4,4,4,2))
217
chart.Scatter.pso(object=pso, return.col=return.col, risk.col=risk.col, chart.assets=chart.assets, element.color=element.color, cex.axis=cex.axis, main=main, xlim=xlim, ylim=ylim, ...=...)
218
par(mar=c(2,4,0,2))
219
chart.Weight.pso(object=pso, neighbors=neighbors, las=3, xlab=NULL, cex.lab=1, element.color=element.color, cex.axis=cex.axis, ...=..., main="")
220
par(op)
221
}
222
223
224
#' @rdname plot
225
#' @method plot optimize.portfolio.pso
226
#' @export
227
plot.optimize.portfolio.pso <- function(x, ..., return.col="mean", risk.col="ES", chart.assets=FALSE, cex.axis=0.8, element.color="darkgray", neighbors=NULL, main="PSO.Portfolios", xlim=NULL, ylim=NULL){
228
charts.pso(pso=x, return.col=return.col, risk.col=risk.col, chart.assets=FALSE, cex.axis=cex.axis, element.color=element.color, neighbors=neighbors, main=main, xlim=xlim, ylim=ylim, ...=...)
229
}
230
231
232
###############################################################################
233
# R (https://r-project.org/) Numeric Methods for Optimization of Portfolios
234
#
235
# Copyright (c) 2004-2021 Brian G. Peterson, Peter Carl, Ross Bennett, Kris Boudt
236
#
237
# This library is distributed under the terms of the GNU Public License (GPL)
238
# for full details see the file COPYING
239
#
240
# $Id$
241
#
242
###############################################################################
243
244