# R script to test the ideas in the Shaw 2011 paper12# Function based on the Shaw 2011 paper to generate sets of portfolio weights3# with FEV biasing4rp_shaw <- function(N, p, k, L){5# N = number of assets6# p = vector of values of p for level of FEV-biasing7# k = number of portfolios for each value of p8# L = lower bounds910# generate uniform[0, 1] random numbers11U <- runif(n=k*N, 0, 1)12Umat <- matrix(data=U, nrow=k, ncol=N)1314# List to store the portfolios for each value of p15out <- list()1617# Create k portfolios for each value of p18# Total of k * length(p) portfolios19for(i in 1:length(p)){20q <- 2^p[i]21tmp_Umat <- t(apply(Umat, 1, function(x) L + (1 - sum(L)) * log(x)^q / sum(log(x)^q)))22out[[i]] <- tmp_Umat23}24return(out)25}2627# Quick test of the rp_shaw function28# create 10 portfolios for 4 assets29tmp <- rp_shaw(N=6, p=0:5, k=10, L=rep(0, 6))30tmp31do.call("rbind", tmp)3233##### Shaw 2011 Example #####3435# Replicate exaple from Shaw 201136# covariance matrix 4.1937Sigma <- rbind(c(0.0549686, 0.144599, -0.188442, 0.0846818, 0.21354, 0.0815392),38c(0.144599, 1.00269, -0.837786, 0.188534, 0.23907, -0.376582),39c(-0.188442, -0.837786, 1.65445, 0.404402, 0.34708, -0.350142),40c(0.0846818, 0.188534, 0.404402, 0.709815, 1.13685, -0.177787),41c(0.21354, 0.23907, 0.34708, 1.13685, 2.13408, 0.166434),42c(0.0815392, -0.376582, -0.350142, -0.177787, 0.166434, 0.890896))43w_optimum <- c(0.883333, 0, 0.11667, 0, 0, 0)4445# Create 3,600,000 portfolios46# Create 600,000 portfolios of 6 assets for each value of p47# This is slow... takes about 30 seconds48# Investigate possible solutions for parallel random number generation in R49system.time(50tmp_shaw <- rp_shaw(N=6, p=0:5, k=600000, L=rep(0, 6))51)52tmp <- do.call("rbind", tmp_shaw)5354# Calculate the objective function on the tmp matrix55# get this working in parallel5657# Define objective function58obj_fun <- function(x) t(x) %*% Sigma %*% x5960# single-core version using apply61# takes about 70 seconds62system.time(63obj1 <- apply(tmp, 1, obj_fun)64)6566# single-core version using lapply67# faster than apply... takes about 38 seconds68system.time(69obj2 <- unlist(lapply(1:nrow(tmp), function(x) obj_fun(tmp[x,])))70)71all.equal(obj1, obj2)7273# multi-core version using mclapply74# faster than lapply version... takes about 24 seconds75library(multicore)76system.time(77obj3 <- unlist(mclapply(1:nrow(tmp), function(x) obj_fun(tmp[x,])))78)79all.equal(obj1, obj3)8081# library(foreach)82# system.time(83# obj4 <- foreach(i=1:nrow(tmp)) %dopar% obj_fun(tmp[i,])84# )85# all.equal(obj1, obj4)8687# Find the minimum of the objective measure88tmp_min <- min(obj1)8990# Find the optimal weights that minimize the objective measure91w <- tmp[which.min(obj1),]9293# view the weights94print(round(w,6))95print(w_optimum)9697# solution is close98print(all.equal(round(w,6), w_optimum))99100##### Lower Bounds #####101# Specify lower bounds102L <- c(0.1, 0.05, 0.05, 0.08)103104U <- runif(4, 0, 1)105log(U) / sum(log(U))106# w_i = L_i + sum(L) * log(U_i)/sum(log(U)107w <- L + (1 - sum(L)) * log(U) / sum(log(U))108w109sum(w)110all(w >= L)111112##### Lower Bounds with FEV Biasing #####113114# N = number of assets115# p = vector of values of p for level of FEV-biasing116# k = number of portfolios for each value of p117# L = lower bounds118N <- 4119k <- 10120p <- 0:5121L <- c(0.1, 0.05, 0.05, 0.08)122123U <- runif(n=k*N, 0, 1)124Umat <- matrix(data=U, nrow=k, ncol=N)125126# List to store the portfolios for each value of p127out <- list()128129# Create k portfolios for each value of p130# Total of k * length(p) portfolios131for(i in 1:length(p)){132q <- 2^p[i]133tmp_Umat <- t(apply(Umat, 1, function(x) L + (1 - sum(L)) * log(x)^q / sum(log(x)^q)))134out[[i]] <- tmp_Umat135}136out137138# rbind each matrix in the list together139tmp <- do.call("rbind", out)140tmp141142# check that all the weights sum to 1143apply(tmp, 1, sum)144145# check that all weights obey the lower bounds146apply(tmp, 1, function(x) all(x >= L))147148149150