R Code – Graph Efficient Frontier
The following code, which is referenced here, can be cut and paste into the R console.In order to load several of these libraries, make sure that you have installed the associated packages. For assistance, please refer to the instructions contained here.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
| # Economist at Large# Modern Portfolio Theory# Use solve.QP to solve for efficient frontier# Last Edited 5/3/13# This file uses the solve.QP function in the quadprog package to solve for the# efficient frontier.# Since the efficient frontier is a parabolic function, we can find the solution# that minimizes portfolio variance and then vary the risk premium to find# points along the efficient frontier. Then simply find the portfolio with the# largest Sharpe ratio (expected return / sd) to identify the most# efficient portfoliolibrary(stockPortfolio) # Base package for retrieving returnslibrary(ggplot2) # Used to graph efficient frontierlibrary(reshape2) # Used to melt the datalibrary(quadprog) #Needed for solve.QP# Create the portfolio using ETFs, incl. hypothetical non-efficient allocationstocks <- c( "VTSMX" = .0, "SPY" = .20, "EFA" = .10, "IWM" = .10, "VWO" = .30, "LQD" = .20, "HYG" = .10)# Retrieve returns, from earliest start date possible (where all stocks have# data) through most recent datereturns <- getReturns(names(stocks[-1]), freq="week") #Currently, drop index#### Efficient Frontier function ####eff.frontier <- function (returns, short="no", max.allocation=NULL, risk.premium.up=.5, risk.increment=.005){ # return argument should be a m x n matrix with one column per security # short argument is whether short-selling is allowed; default is no (short # selling prohibited)max.allocation is the maximum % allowed for any one # security (reduces concentration) risk.premium.up is the upper limit of the # risk premium modeled (see for loop below) and risk.increment is the # increment (by) value used in the for loop covariance <- cov(returns) print(covariance) n <- ncol(covariance) # Create initial Amat and bvec assuming only equality constraint # (short-selling is allowed, no allocation constraints) Amat <- matrix (1, nrow=n) bvec <- 1 meq <- 1 # Then modify the Amat and bvec if short-selling is prohibited if(short=="no"){ Amat <- cbind(1, diag(n)) bvec <- c(bvec, rep(0, n)) } # And modify Amat and bvec if a max allocation (concentration) is specified if(!is.null(max.allocation)){ if(max.allocation > 1 | max.allocation <0){ stop("max.allocation must be greater than 0 and less than 1") } if(max.allocation * n < 1){ stop("Need to set max.allocation higher; not enough assets to add to 1") } Amat <- cbind(Amat, -diag(n)) bvec <- c(bvec, rep(-max.allocation, n)) } # Calculate the number of loops loops <- risk.premium.up / risk.increment + 1 loop <- 1 # Initialize a matrix to contain allocation and statistics # This is not necessary, but speeds up processing and uses less memory eff <- matrix(nrow=loops, ncol=n+3) # Now I need to give the matrix column names colnames(eff) <- c(colnames(returns), "Std.Dev", "Exp.Return", "sharpe") # Loop through the quadratic program solver for (i in seq(from=0, to=risk.premium.up, by=risk.increment)){ dvec <- colMeans(returns) * i # This moves the solution along the EF sol <- solve.QP(covariance, dvec=dvec, Amat=Amat, bvec=bvec, meq=meq) eff[loop,"Std.Dev"] <- sqrt(sum(sol$solution*colSums((covariance*sol$solution)))) eff[loop,"Exp.Return"] <- as.numeric(sol$solution %*% colMeans(returns)) eff[loop,"sharpe"] <- eff[loop,"Exp.Return"] / eff[loop,"Std.Dev"] eff[loop,1:n] <- sol$solution loop <- loop+1 } return(as.data.frame(eff))}# Run the eff.frontier function based on no short and 50% alloc. restrictionseff <- eff.frontier(returns=returns$R, short="no", max.allocation=.50, risk.premium.up=1, risk.increment=.001)# Find the optimal portfolioeff.optimal.point <- eff[eff$sharpe==max(eff$sharpe),]# graph efficient frontier# Start with color schemeealred <- "#7D110C"ealtan <- "#CDC4B6"eallighttan <- "#F7F6F0"ealdark <- "#423C30"ggplot(eff, aes(x=Std.Dev, y=Exp.Return)) + geom_point(alpha=.1, color=ealdark) + geom_point(data=eff.optimal.point, aes(x=Std.Dev, y=Exp.Return, label=sharpe), color=ealred, size=5) + annotate(geom="text", x=eff.optimal.point$Std.Dev, y=eff.optimal.point$Exp.Return, label=paste("Risk: ", round(eff.optimal.point$Std.Dev*100, digits=3),"\nReturn: ", round(eff.optimal.point$Exp.Return*100, digits=4),"%\nSharpe: ", round(eff.optimal.point$sharpe*100, digits=2), "%", sep=""), hjust=0, vjust=1.2) + ggtitle("Efficient Frontier\nand Optimal Portfolio") + labs(x="Risk (standard deviation of portfolio)", y="Return") + theme(panel.background=element_rect(fill=eallighttan), text=element_text(color=ealdark), plot.title=element_text(size=24, color=ealred))ggsave("Efficient Frontier.png")Source: (http://economistatlarge.com/portfolio-theory/r-optimized-portfolio/r-code-graph-efficient-frontier) |
No comments:
Post a Comment