8

Вот интересная головоломка.оптимизация quadprog

Ниже приведено значение R snippet, которое идентифицирует точку касания квадратичной функции относительно линии, проведенной из точки (0, rf) по оси y.

Для тех, кто знаком с теорией портфеля, эта точка находится в обратном и пространстве риска, а решение представляет собой набор весов, определяющих портфолио касаний (максимальное отношение шара). Сниппет позволяет отрицательных весов (то есть шорты) и есть один равенство веса ограничение, которое требует сумму весов = 1.

require(quadprog) 

# create artifical data 
nO  <- 100  # number of observations 
nA  <- 10  # number of assets 
mData <- array(rnorm(nO * nA, mean = 0.001, sd = 0.01), dim = c(nO, nA)) 
rf  <- 0.0001  # riskfree rate (2.5% pa) 
mu  <- apply(mData, 2, mean) # means 
mu2 <- mu - rf     # excess means 

# qp 
aMat <- as.matrix(mu2) 
bVec <- 1 # set expectation of portfolio excess return to 1 
zeros <- array(0, dim = c(nA,1)) 
solQP <- solve.QP(cov(mData), zeros, aMat, bVec, meq = 1) 

# rescale variables to obtain weights 
w <- as.matrix(solQP$solution/sum(solQP$solution)) 

# compute sharpe ratio 
SR <- t(w) %*% mu2/sqrt(t(w) %*% cov(mData) %*% w) 

Мой вопрос - как адаптировать код для решения для оптимального набора весы такие, что сумма весов суммируется до произвольного числа (включая краевой случай самофинансируемого портфеля, где сумма весов = 0), в отличие от единицы?

В качестве альтернативы вы можете добавить элемент «cash» в матрицу ковариации с ковариацией дисперсии 0 и добавить ограничение равенства, требующее веса на деньги = 1. Однако эта матрица не будет положительной полуопределенной , Также я подозреваю, что неденежные веса могут быть тривиально нулевыми.

+1

Внутри вашего 'решающегоQP' вызова, я не вижу ограничения, обеспечивающего, чтобы весы суммировались с одним. Вместо этого 'aMat, bVec, meq = 1' требует, чтобы ваш избыток портфеля был единым, что вы можете проверить с помощью' sum (aMat * solQP $ solution) '. Внутри вашего 'solve.QP' вызов, не следует ли использовать вектор из них вместо' aMat'? – flodel

+0

@flodel - вы правы. Типичный фиксированный, хороший улов –

ответ

7

Давайте сначала объясним, почему этот действительно производит максимальное портфолио коэффициентов Шарпа.

Мы хотим, чтобы w, чтобы увеличить w' mu/sqrt(w' V w). Но это количество не изменится, если умножить w рядом (это «однородна степени 0»): поэтому мы можем наложить w' mu = 1, и проблема максимизации 1/sqrt(w' V w) эквивалентно к минимуму w' V w. Максимальное портфолио коэффициентов Шарпа не уникально: они образуют линию. Если мы хотим, чтобы весы суммировались до 1 (или любого другого ненулевого номера), , нам просто нужно их перемасштабировать.

Если мы хотим веса суммировать до 0, мы можем добавить, что ограничение на проблему - это работает только потому, что ограничение также однородны степени 0. Вам все равно нужно переранжировать веса, например, быть на 100% длинным и на 100% коротким.

solQP <- solve.QP(cov(mData), zeros, 
    cbind(aMat,1), 
    c(bVec,0), 
    meq = 2 
) 

# Let us compare with another solver 
V <- cov(mData) 
library(Rsolnp) 
r <- solnp(
    rep(1/length(mu), length(mu)), 
    function(w) - t(w) %*% mu2/sqrt(t(w) %*% V %*% w), 
    eqfun = function(w) sum(w), 
    eqB = 0, 
    LB = rep(-1, length(mu)) 
) 
solQP$solution/r$pars # constant 
1

Посмотрите на ссылку, которую вы включили. По-видимому, роль aMat, bVec, meq = 1 в вызове solve.QP заключается в фиксации значения числителя (вашего возврата) в формуле отношения Шарпа, поэтому оптимизация фокусируется на минимизации знаменателя. В некотором смысле, совершенно законно исправить числитель, это как фиксация общего размера вашего портфеля. Позднее ваше портфолио может быть увеличено или уменьшено, оно будет поддерживать тот же коэффициент Шарпа. Чтобы вы поняли это, вы можете запустить свой код выше для любого значения bVec (предоставленного, отличного от нуля), и вы получите тот же результат для весов w и коэффициента Sharpe SR.

Таким образом, я чувствую, что вы можете неправильно истолковать понятие «веса портфеля». Они являются отношениями, представляющими то, из чего сделан ваш портфель, и они должны суммироваться с одним. Как только вы найдете оптимальные веса, которые вы уже сделали, вы можете масштабировать свое портфолио до любого уровня, который хотите, просто умножьте w на текущее значение, которое вы хотите для своего портфеля.

0

Это не очень хорошая техника для длинных портфолио.Даже портфели, чем короткие запасы, имеют весовые коэффициенты неправильного знака после нормализации суммы весов.

Эти ситуации возникают с отрицательными избыточными доходами. Принуждение w'mu = 1 помещает решение влево от источника (отрицательный риск) в этих случаях.

library(quadprog) 
nA = 2 # two assets 
mu2 = c(-.1,.1) # one negative excess return 
Dmat = matrix(c(1,0,0,10),2,2) 

aMat <- as.matrix(mu2) 
bVec <- 1 # set expectation of portfolio excess return to 1 
zeros <- array(0, dim = c(nA,1)) 
solQP <- solve.QP(Dmat, zeros, aMat, bVec, meq = 1) 

rawW = solQP$solution 
cat('\nraw weights ') 
cat(rawW) 

netW = rawW/sum(rawW) 
cat('\nnormalized weights ') 
cat(netW) 

portfReturn = sum(netW*mu2) 
cat('\nportfolio excess return ') 
cat(portfReturn)