-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathrp_shaw.R
148 lines (119 loc) · 3.88 KB
/
rp_shaw.R
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# R script to test the ideas in the Shaw 2011 paper
# Function based on the Shaw 2011 paper to generate sets of portfolio weights
# with FEV biasing
rp_shaw <- function(N, p, k, L){
# N = number of assets
# p = vector of values of p for level of FEV-biasing
# k = number of portfolios for each value of p
# L = lower bounds
# generate uniform[0, 1] random numbers
U <- runif(n=k*N, 0, 1)
Umat <- matrix(data=U, nrow=k, ncol=N)
# List to store the portfolios for each value of p
out <- list()
# Create k portfolios for each value of p
# Total of k * length(p) portfolios
for(i in 1:length(p)){
q <- 2^p[i]
tmp_Umat <- t(apply(Umat, 1, function(x) L + (1 - sum(L)) * log(x)^q / sum(log(x)^q)))
out[[i]] <- tmp_Umat
}
return(out)
}
# Quick test of the rp_shaw function
# create 10 portfolios for 4 assets
tmp <- rp_shaw(N=6, p=0:5, k=10, L=rep(0, 6))
tmp
do.call("rbind", tmp)
##### Shaw 2011 Example #####
# Replicate exaple from Shaw 2011
# covariance matrix 4.19
Sigma <- rbind(c(0.0549686, 0.144599, -0.188442, 0.0846818, 0.21354, 0.0815392),
c(0.144599, 1.00269, -0.837786, 0.188534, 0.23907, -0.376582),
c(-0.188442, -0.837786, 1.65445, 0.404402, 0.34708, -0.350142),
c(0.0846818, 0.188534, 0.404402, 0.709815, 1.13685, -0.177787),
c(0.21354, 0.23907, 0.34708, 1.13685, 2.13408, 0.166434),
c(0.0815392, -0.376582, -0.350142, -0.177787, 0.166434, 0.890896))
w_optimum <- c(0.883333, 0, 0.11667, 0, 0, 0)
# Create 3,600,000 portfolios
# Create 600,000 portfolios of 6 assets for each value of p
# This is slow... takes about 30 seconds
# Investigate possible solutions for parallel random number generation in R
system.time(
tmp_shaw <- rp_shaw(N=6, p=0:5, k=600000, L=rep(0, 6))
)
tmp <- do.call("rbind", tmp_shaw)
# Calculate the objective function on the tmp matrix
# get this working in parallel
# Define objective function
obj_fun <- function(x) t(x) %*% Sigma %*% x
# single-core version using apply
# takes about 70 seconds
system.time(
obj1 <- apply(tmp, 1, obj_fun)
)
# single-core version using lapply
# faster than apply... takes about 38 seconds
system.time(
obj2 <- unlist(lapply(1:nrow(tmp), function(x) obj_fun(tmp[x,])))
)
all.equal(obj1, obj2)
# multi-core version using mclapply
# faster than lapply version... takes about 24 seconds
library(multicore)
system.time(
obj3 <- unlist(mclapply(1:nrow(tmp), function(x) obj_fun(tmp[x,])))
)
all.equal(obj1, obj3)
# library(foreach)
# system.time(
# obj4 <- foreach(i=1:nrow(tmp)) %dopar% obj_fun(tmp[i,])
# )
# all.equal(obj1, obj4)
# Find the minimum of the objective measure
tmp_min <- min(obj1)
# Find the optimal weights that minimize the objective measure
w <- tmp[which.min(obj1),]
# view the weights
print(round(w,6))
print(w_optimum)
# solution is close
print(all.equal(round(w,6), w_optimum))
##### Lower Bounds #####
# Specify lower bounds
L <- c(0.1, 0.05, 0.05, 0.08)
U <- runif(4, 0, 1)
log(U) / sum(log(U))
# w_i = L_i + sum(L) * log(U_i)/sum(log(U)
w <- L + (1 - sum(L)) * log(U) / sum(log(U))
w
sum(w)
all(w >= L)
##### Lower Bounds with FEV Biasing #####
# N = number of assets
# p = vector of values of p for level of FEV-biasing
# k = number of portfolios for each value of p
# L = lower bounds
N <- 4
k <- 10
p <- 0:5
L <- c(0.1, 0.05, 0.05, 0.08)
U <- runif(n=k*N, 0, 1)
Umat <- matrix(data=U, nrow=k, ncol=N)
# List to store the portfolios for each value of p
out <- list()
# Create k portfolios for each value of p
# Total of k * length(p) portfolios
for(i in 1:length(p)){
q <- 2^p[i]
tmp_Umat <- t(apply(Umat, 1, function(x) L + (1 - sum(L)) * log(x)^q / sum(log(x)^q)))
out[[i]] <- tmp_Umat
}
out
# rbind each matrix in the list together
tmp <- do.call("rbind", out)
tmp
# check that all the weights sum to 1
apply(tmp, 1, sum)
# check that all weights obey the lower bounds
apply(tmp, 1, function(x) all(x >= L))