[Returnanalytics-commits] r2159 - pkg/MPO/R
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Sat Jul 14 23:20:51 CEST 2012
Author: jamesleehobbs
Date: 2012-07-14 23:20:50 +0200 (Sat, 14 Jul 2012)
New Revision: 2159
Added:
pkg/MPO/R/ClassicMV.R
pkg/MPO/R/TransactionCostOpt.R
Log:
-ClassicMV & proportional transaction cost optimization added
Added: pkg/MPO/R/ClassicMV.R
===================================================================
--- pkg/MPO/R/ClassicMV.R (rev 0)
+++ pkg/MPO/R/ClassicMV.R 2012-07-14 21:20:50 UTC (rev 2159)
@@ -0,0 +1,55 @@
+#classic mv
+#From Guy Yollins code
+MinVariancePortOpt = function(returns)
+{
+ C <- var(returns)
+ one <- rep(1, nrow(C))
+ z <- solve(C, one)
+ # Compute z = C.inv * 1
+ cc <- t(one) %*% z
+ # Compute cc = 1.transpose * C.inv * 1
+ cc <- as.numeric(cc)
+ # Convert 1-by-1 matrix to a scalar
+ w <- z/cc
+ mu <- apply(returns, 2, mean)
+ a <- t(mu) %*% z
+ port.mu <- as.numeric(a/cc)
+ port.sd <- 1/cc^0.5
+ list(w = w, port.mu = port.mu, port.sd = port.sd)
+}
+
+
+PortOptUnconstrained <- function(returns,mu.target){
+ nassets <- ncol(returns)
+ cov.mat <- cov(returns)
+ Dmat <- 2*cov.mat
+ mu <- apply(returns,2,mean)
+ dvec <- rep(0,nassets) #no linear part
+ constraint.sum <- c(rep(1,nassets))
+ constraint.mu.target <- mu
+ Amat <- cbind(constraint.sum, constraint.mu.target)
+ bvec <- c(1,mu.target)
+ solution <- solve.QP(Dmat,dvec,Amat,bvec,meq=(2))
+ port.sd <- (solution$value)^0.5
+ w <- solution$solution
+ port.mu <- w%*%mu
+ list(w = w, port.sd = port.sd, port.mu = port.mu)
+}
+
+UnconstrainedFrontier <- function(returns,npoints = 10){
+ nassets <- ncol(returns)
+ min.variance.port <- MinVariancePortOpt(returns)
+ mu.max <- max(apply(returns,2,mean))
+ mu.min <- min.variance.port$port.mu
+ mu.vals <- seq(mu.min, mu.max, length.out = npoints)
+ result = matrix (0,nrow = npoints, ncol = (nassets+2))
+ colnames(result)=c("MU","SD",colnames(returns))
+ for(i in 1:npoints){
+ sol <- PortOptUnconstrained(returns,mu.vals[i])
+ result[i,"MU"] <- sol$port.mu
+ result[i,"SD"] <- sol$port.sd
+ result[i,3:(nassets+2)] <- sol$w
+ }
+ result
+}
+
Added: pkg/MPO/R/TransactionCostOpt.R
===================================================================
--- pkg/MPO/R/TransactionCostOpt.R (rev 0)
+++ pkg/MPO/R/TransactionCostOpt.R 2012-07-14 21:20:50 UTC (rev 2159)
@@ -0,0 +1,91 @@
+library(xts)
+library(quadprog)
+library(corpcor)
+
+
+
+
+#generic quadratic utility maximization
+UtilityMaximization <- function(returns,lambda){
+ nassets <- ncol(returns)
+ cov.mat <- cov(returns)
+ Dmat <- 2*cov.mat*lambda #objective won't return cov matrix, no need to x2
+ mu <- apply(returns,2,mean)
+ dvec <- -mu #linear part is to maximize mean return
+
+ #left hand side of constraints
+ constraint.weight.sum <- rep(1,nassets)
+ Amat <- cbind(constraint.weight.sum)
+
+ #right hand side of constraints
+ bvec <- c(-1)
+
+ solution <- solve.QP(Dmat,dvec,Amat,bvec,meq=1)
+ w <- solution$solution
+ port.var <- -w%*%cov.mat%*%-w
+ port.mu <- -w%*%mu
+ list(w = w, port.var=port.var, port.mu=port.mu)
+}
+
+
+#lambda - risk aversion paramter
+#c - proportional transaction cost
+TransactionCostOpt <- function(returns,lambda,w.initial,c){
+ nassets <- ncol(returns)
+ if(length(c)==1){
+ c = rep(c,nassets)
+ }
+ if(length(c)!=nassets){
+ stop("c must either be a single value, or the same length as the number of assets")
+ }
+ #step 1: optimize without constraints to determine buys vs sells
+ #if w*>w.initial c = c
+ #if w* < w.initial c = -c
+ unconstrained <- UtilityMaximization(returns,lambda)
+ w.unconstrained <- unconstrained$w
+
+ sign.vec <- rep(1,nassets)
+ sign.vec[w.unconstrained<0] <- -1
+ c <- c*sign.vec
+
+ #TODO fix this part
+ #step 2: optimize with fixed c from step 1
+ #this solution will be good as long as no buys or sells flip
+ cov.mat <- cov(returns)
+ Dmat <- cov.mat*lambda #objective won't return cov matrix, no need to x2
+ mu <- apply(returns,2,mean)
+ dvec <- -(mu-c) #linear part is to maximize mean return
+
+ #left hand side of constraints
+ constraint.weight.sum <- rep(1,nassets)
+ constraint.weight.buysell <- diag(sign.vec)
+ Amat <- cbind(constraint.weight.sum,constraint.weight.buysell)
+
+ #right hand side of constraints
+ bvec <- c(1,(w.initial*sign.vec))
+
+ solution <- solve.QP(Dmat,dvec,Amat,bvec,meq=1)
+ w <- solution$solution
+ port.var <- w%*%cov.mat%*%w
+ port.mu <- w%*%mu
+ list(w = w, port.var=port.var, port.mu=port.mu)
+}
+
+
+#TODO add documentation
+TransCostFrontier <- function(returns,npoints = 10, min.lambda, max.lambda,
+ w.initial,c,long.only = FALSE)
+{
+ p = ncol(returns)
+ efront = matrix(rep(0,npoints*(p+2)),ncol = p+2)
+ dimnames(efront)[[2]] = c("MU","SD",dimnames(returns)[[2]])
+ lambda.vals = seq(min.lambda,max.lambda,length.out = npoints)
+ for(i in 1:npoints) {
+ opt <- TransactionCostOpt(returns,lambda = lambda.vals[i],w.initial,c)
+ efront[i,"MU"] <- opt$port.mu
+ efront[i,"SD"] <- sqrt(opt$port.var)
+ efront[i,3:ncol(efront)] <- opt$w
+ }
+
+ efront
+}
More information about the Returnanalytics-commits
mailing list