2

I have my input parameters mu (mean vector μ), Q (covariance matrix Q), and tau (risk tolerance τ) and I need to return the vector h (asset weights) that maximizes the following utility function U defined by:

U(h)= −1/2h^T*Q*h + τ*h^T*μ

subject to constraints:

0 ≤ h ≤ 0.1 for all h
and sum of all h is equal to 1: h^T*e = 1

TAU contains numbers from zero to 0.5 in steps of 0.001. How do I define the parameters: Dmat, dvec, Amat and bvec for this problem? I know the finance concepts but not how to program it correctly.

Thank you

This doesn't work as I still have negative weights indicative of short selling :(

frontieropti <- c(NULL)
i <- 1
for (i in 1:nrow(TAU)){
  solQP <- solve.QP(Dmat,TAU[i]*mu, Amat, bvec, meq = 1, factorized = F)
  sol <- c(i,solQP$value)
  frontieropti <- rbind(frontieropti,sol)
  i <- i +1
}
solQP <- solve.QP(Dmat, TAU[1]*mu, Amat, bvec, meq = 1, factorized = F)
solQP
eruiz
  • 59
  • 9
  • these slides http://enricoschumann.net/files/slides_rimini_2016_qp.pdf show how to use package `quadprog` for mean-variance optimisation. The referenced code is at http://enricoschumann.net/files/mv.R – Enrico Schumann Jun 25 '20 at 13:51
  • I appreciate the materials but I already have slides and similar codes. I was just looking for some code to my problem so that I can move on to other parts I need to complete. Like very explicit definitions of my variables. The equal to or less than 10% is what's tripping me up and how to define that in the Amat properly. – eruiz Jun 25 '20 at 14:02
  • Is that intentional that you skip all even `i`? – Jan Jun 25 '20 at 19:15
  • @Jan can you explain. `i` is looking at `TAU` which is either an array of numbers from zero to 0.5 in increments of 0.001 or, as I have it written, different rows of a matrix with the same numbers. I am merely going row to row within the `TAU` matrix but am I inadvertently skipping all the evens??? – eruiz Jun 25 '20 at 21:19
  • The `for` loop takes care of the increment itself. The statement `i <- i+1` is extra and not needed. However, I just tried it out and R completely ignores the extra `i+1`statement. So, it doesn' t do any harm and my suspicion was wrong. So, you are right that it works. – Jan Jun 25 '20 at 22:46
  • @Jan Thank you for your comment, I will be extra careful from here on out. I have been using `i<-i+1` always as a bad habit from when I was learning to code. I'll be aware in the future – eruiz Jun 25 '20 at 23:03

1 Answers1

2

Setting up Amat:

na <- 5  ## number of assets

I use only 5 assets and a maximum weight of 40% so that I can show the resulting matrices:

wmin <- 0
wmax <- 0.4
A <- rbind(1,-diag(na), diag(na))
bvec <- c(1, -rep(wmax, na), rep(wmin, na))
cbind(A, bvec)
##                      bvec
##  [1,]  1  1  1  1  1  1.0
##  [2,] -1  0  0  0  0 -0.4
##  [3,]  0 -1  0  0  0 -0.4
##  [4,]  0  0 -1  0  0 -0.4
##  [5,]  0  0  0 -1  0 -0.4
##  [6,]  0  0  0  0 -1 -0.4
##  [7,]  1  0  0  0  0  0.0
##  [8,]  0  1  0  0  0  0.0
##  [9,]  0  0  1  0  0  0.0
## [10,]  0  0  0  1  0  0.0
## [11,]  0  0  0  0  1  0.0

Note that the first row of Amat is for the budget constraint, so you need to set argument meq to 1. Also, solve.QP wants the transpose of Amat, i.e. t(Amat).


So here would be a complete example:

library("quadprog")
library("NMOF")

I start by creating some random data for 30 assets.

na <- 30
R <- randomReturns(na = na, ns = 120, rho = 0.5, sd = 0.03)
mu <- colMeans(R)
V <- cov(R)


wmin <- 0
wmax <- 0.1
A <- rbind(1,-diag(na), diag(na))
b <- c(1, -rep(wmax, na), rep(wmin, na))

TAU <- seq(0, 0.5, by = 0.01) ## choose an appropriate stepsize

It is good practice to initialise data structures before the loop, and not "grow" them. (Even though it does not matter much in this example.)

results <- numeric(length(TAU))
weights <- array(NA, dim = c(na, length(TAU)))
for (i in seq_along(TAU)) {
    solQP <- solve.QP(Dmat = V,
                      dvec = TAU[i]*mu,
                      Amat = t(A),
                      bvec = b, meq = 1)

    ## an equivalent computation    
    ## NMOF::mvPortfolio(mu, V, wmax = 0.1, lambda = c(TAU[i], 0.5))

    results[i] <- solQP$value
    weights[, i] <- solQP$solution
}

Note that, because of round-off error, some results may be negative. So round the results to 8 decimal places, say.

weights <- round(weights, 8)
barplot(weights)
Enrico Schumann
  • 1,278
  • 7
  • 8
  • thank you for your answer, I am following your thinking but have a couple followups. What would my dvec be then since I have risk tolerances tau included in the second term of the quadratic function `τ*h^T*μ`. I altered your code for my case (I have 30 assets and a max of 10%, no short sales). Also if A is Amat in your code you're saying that solve.QP only will take t(A) as an input? Thank you for helping, it doesn't help that this is such a large matrix. I appreciate you – eruiz Jun 25 '20 at 16:39
  • I included above in my original question my loop for a solution but it still gives me negative weights indicative of short selling. – eruiz Jun 25 '20 at 16:49
  • I have added to my answer. – Enrico Schumann Jun 25 '20 at 18:26
  • This is all wonderful, I follow your logic and it seems to have worked. A quick followup however. Did you just include `cbind(A, b)` in your first response to show me both A and b in one output? I was under the impression that Amat is the matrix defining the constraints under which we want to minimize the quadratic function. So why is bvec not a part of Amat? I am trying to distinguish why the weight constraint is not a part of Amat as well? – eruiz Jun 26 '20 at 14:29
  • Furthermore, is there a way to distinguish the optimum portfolio’s expected return and standard deviation of return. From your logic, `results` stores each solution from each iteration of the loop. So would the max value of this matrix of results just be the portfolio with the best possible return and therefore its corresponding weights? I am trying to store each portfolio return and standard deviation and then plot the efficient frontier. I am very new to theseoptimizations but I am so close to understanding. Thank you so much – eruiz Jun 26 '20 at 14:31
  • Hi, I think I figured everything out but when I plot my Efficient Frontier it is inverted. I think there is a sign error. If TAU is risk tolerance I am getting a the Global Minimum Variance Portfolio at TAU = 0. However this corresponds to my Return in the `results` matrix also being the greatest. My return should not be its maximum at TAU =0, it should be when TAU = 0.5 because at the highest risk tolerance you will have a higher return – eruiz Jun 26 '20 at 17:36
  • I used `cbind` only to show the relationship between `A` and `b`. In your objective function, you have used `TAU[i]` as a scalar for the return. Thus, a `TAU[i]` of zero will leave only the variance in the objective function, and you get the minimum-variance portfolio. – Enrico Schumann Jun 27 '20 at 06:51
  • Hi @Enrico, thank you very much for your fantastic help, this is truly inspiring. Can I please ask you if you could show how you would go on plotting the efficient frontier from your code above? Many thanks! – Vitomir Mar 03 '21 at 11:38
  • @Vitomir , the code gives you a matrix `weights`, each column of which is a portfolio. Each such portfolio maps into a return and a variance (for fixed `mu`and `V`). To plot the frontier, plot the returns for every portfolio vs the variances (or rather volatilities) of those portfolios. – Enrico Schumann Mar 06 '21 at 08:13