Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/rp_shaw.R
1433 views
1
# R script to test the ideas in the Shaw 2011 paper
2
3
# Function based on the Shaw 2011 paper to generate sets of portfolio weights
4
# with FEV biasing
5
rp_shaw <- function(N, p, k, L){
6
# N = number of assets
7
# p = vector of values of p for level of FEV-biasing
8
# k = number of portfolios for each value of p
9
# L = lower bounds
10
11
# generate uniform[0, 1] random numbers
12
U <- runif(n=k*N, 0, 1)
13
Umat <- matrix(data=U, nrow=k, ncol=N)
14
15
# List to store the portfolios for each value of p
16
out <- list()
17
18
# Create k portfolios for each value of p
19
# Total of k * length(p) portfolios
20
for(i in 1:length(p)){
21
q <- 2^p[i]
22
tmp_Umat <- t(apply(Umat, 1, function(x) L + (1 - sum(L)) * log(x)^q / sum(log(x)^q)))
23
out[[i]] <- tmp_Umat
24
}
25
return(out)
26
}
27
28
# Quick test of the rp_shaw function
29
# create 10 portfolios for 4 assets
30
tmp <- rp_shaw(N=6, p=0:5, k=10, L=rep(0, 6))
31
tmp
32
do.call("rbind", tmp)
33
34
##### Shaw 2011 Example #####
35
36
# Replicate exaple from Shaw 2011
37
# covariance matrix 4.19
38
Sigma <- rbind(c(0.0549686, 0.144599, -0.188442, 0.0846818, 0.21354, 0.0815392),
39
c(0.144599, 1.00269, -0.837786, 0.188534, 0.23907, -0.376582),
40
c(-0.188442, -0.837786, 1.65445, 0.404402, 0.34708, -0.350142),
41
c(0.0846818, 0.188534, 0.404402, 0.709815, 1.13685, -0.177787),
42
c(0.21354, 0.23907, 0.34708, 1.13685, 2.13408, 0.166434),
43
c(0.0815392, -0.376582, -0.350142, -0.177787, 0.166434, 0.890896))
44
w_optimum <- c(0.883333, 0, 0.11667, 0, 0, 0)
45
46
# Create 3,600,000 portfolios
47
# Create 600,000 portfolios of 6 assets for each value of p
48
# This is slow... takes about 30 seconds
49
# Investigate possible solutions for parallel random number generation in R
50
system.time(
51
tmp_shaw <- rp_shaw(N=6, p=0:5, k=600000, L=rep(0, 6))
52
)
53
tmp <- do.call("rbind", tmp_shaw)
54
55
# Calculate the objective function on the tmp matrix
56
# get this working in parallel
57
58
# Define objective function
59
obj_fun <- function(x) t(x) %*% Sigma %*% x
60
61
# single-core version using apply
62
# takes about 70 seconds
63
system.time(
64
obj1 <- apply(tmp, 1, obj_fun)
65
)
66
67
# single-core version using lapply
68
# faster than apply... takes about 38 seconds
69
system.time(
70
obj2 <- unlist(lapply(1:nrow(tmp), function(x) obj_fun(tmp[x,])))
71
)
72
all.equal(obj1, obj2)
73
74
# multi-core version using mclapply
75
# faster than lapply version... takes about 24 seconds
76
library(multicore)
77
system.time(
78
obj3 <- unlist(mclapply(1:nrow(tmp), function(x) obj_fun(tmp[x,])))
79
)
80
all.equal(obj1, obj3)
81
82
# library(foreach)
83
# system.time(
84
# obj4 <- foreach(i=1:nrow(tmp)) %dopar% obj_fun(tmp[i,])
85
# )
86
# all.equal(obj1, obj4)
87
88
# Find the minimum of the objective measure
89
tmp_min <- min(obj1)
90
91
# Find the optimal weights that minimize the objective measure
92
w <- tmp[which.min(obj1),]
93
94
# view the weights
95
print(round(w,6))
96
print(w_optimum)
97
98
# solution is close
99
print(all.equal(round(w,6), w_optimum))
100
101
##### Lower Bounds #####
102
# Specify lower bounds
103
L <- c(0.1, 0.05, 0.05, 0.08)
104
105
U <- runif(4, 0, 1)
106
log(U) / sum(log(U))
107
# w_i = L_i + sum(L) * log(U_i)/sum(log(U)
108
w <- L + (1 - sum(L)) * log(U) / sum(log(U))
109
w
110
sum(w)
111
all(w >= L)
112
113
##### Lower Bounds with FEV Biasing #####
114
115
# N = number of assets
116
# p = vector of values of p for level of FEV-biasing
117
# k = number of portfolios for each value of p
118
# L = lower bounds
119
N <- 4
120
k <- 10
121
p <- 0:5
122
L <- c(0.1, 0.05, 0.05, 0.08)
123
124
U <- runif(n=k*N, 0, 1)
125
Umat <- matrix(data=U, nrow=k, ncol=N)
126
127
# List to store the portfolios for each value of p
128
out <- list()
129
130
# Create k portfolios for each value of p
131
# Total of k * length(p) portfolios
132
for(i in 1:length(p)){
133
q <- 2^p[i]
134
tmp_Umat <- t(apply(Umat, 1, function(x) L + (1 - sum(L)) * log(x)^q / sum(log(x)^q)))
135
out[[i]] <- tmp_Umat
136
}
137
out
138
139
# rbind each matrix in the list together
140
tmp <- do.call("rbind", out)
141
tmp
142
143
# check that all the weights sum to 1
144
apply(tmp, 1, sum)
145
146
# check that all weights obey the lower bounds
147
apply(tmp, 1, function(x) all(x >= L))
148
149
150