Usted podría intentar una aproximación heurística.
El problema se puede dividir en dos anidada optimizaciones: i) en el interior de la optimización, dado un conjunto de activos seleccionados, calcular decir--varianza eficiente de pesos; ii) en el exterior de la optimización, se itera a través de combinaciones de activos.
El interior de la optimización puede ser resuelto a través de una ecuación cuadrática
programa (QP). Para el exterior de la optimización, usted podría
el uso de un local-técnica de búsqueda. Boceto de cómo un
el método podría ser aplicado, puedo crear algunos datos aleatorios. Yo
se asume que para cada activo, hay 60 regreso
observaciones (para la intuición, para pensar en ellos
como rendimientos mensuales).
set.seed(75578)
I <- cbind(0:15*1440+1, 1:16*1440)
rownames(I) <- LETTERS[1:nrow(I)]
colnames(I) <- c("first", "last")
R <- rnorm(60*max(I), sd = 0.02)
dim(R) <- c(60, max(I))
Los rendimientos de la matriz R
es de tamaño 60 veces 23040, como por tu comentario: de 16 países con 1440 activos de cada uno. El
columnas de R
son asignados a los países a, B, ... y la
inicio y fin de los índices para cada país se encuentran en la matriz I
. Esta última matriz se parece a esto:
first last
A 1 1440
B 1441 2880
C 2881 4320
D 4321 5760
E 5761 7200
F 7201 8640
G 8641 10080
H 10081 11520
I 11521 12960
J 12961 14400
K 14401 15840
L 15841 17280
M 17281 18720
N 18721 20160
O 20161 21600
P 21601 23040
Puedo recoger todos estos datos en una lista única, lo que hace que
es más fácil transmitir la información a una función.
Data <- list(I = I,
nc = nrow(I),
R = R)
Ahora supongamos que tenemos un conjunto de activos:
x <- Data$I[,1]
x
ve de la siguiente manera:
A B C D E F G H
1 1441 2881 4321 5761 7201 8641 10081
I J K L M N O P
11521 12961 14401 15841 17281 18721 20161 21601
Para el cálculo de la solución para el interior problema, yo uso el
la función mvar
. Para mantener las cosas simples, se calcula el tiempo-sólo
mínimo de la varianza de la cartera. La función hace uso de la NMOF paquete. (Yo soy el autor del paquete. Necesitarás la última versión, que puede ser instalado como se muestra a continuación o desde GitHub; con el CRAN versión, usted tendrá que escribir NMOF:::minvar
).
## install.packages('NMOF', type = 'source',
## repos = c('http://enricoschumann.net/R',
## getOption('repos')))
require("NMOF")
mvar <- function(x, Data) {
cv <- cov(Data$R[ ,x])
w <- minvar(cv, wmin = 0, wmax = 0.5)
c(sqrt(w %*% cv %*% w))
}
Comprobamos lo bien que la cartera x
es mediante el cálculo de su valor de la función objetivo.
mvar(x, Data)
que, con la semilla, es
0.003645508
En realidad, antes de utilizar una búsqueda local, tratemos de
un 'constructivo' solución como punto de referencia: seleccione el activo con el
menor volatilidad de cada país, y, a continuación, calcular el
mínimo de la varianza de los pesos de esta selección.
x_sort <- numeric(Data$nc)
for (i in 1:nrow(Data$I)) {
cols <- Data$I[i,1]:Data$I[i,2]
x_sort[i] <- cols[order(apply(Data$R[ ,cols ], 2, sd))[1]]
}
Podemos calcular esta solución el valor de la función objetivo
mvar(x_sort, Data)
que es mejor:
0.002234832
Tenga en cuenta que la volatilidad (0.2%) es un
orden de magnitud inferior a la media de la volatilidad de los
al azar del conjunto de datos, que fue del 2%.
Ahora, en una búsqueda local, empezamos con un poco de solución y
tratar de mejorarlo de forma iterativa. Para ello, necesitamos un
barrio función que toma una de las soluciones y
devuelve un poco cambiado solución. Aquí es una manera de
escribir una función.
nb <- function(x, Data) {
## randomly pick one country
i <- sample(Data$nc, 1)
## randomly pick one asset
x[i] <- sample(Data$I[i,1]:Data$I[i,2], 1)
x
}
Ahora trato de dos locales-algoritmos de búsqueda: simple
estocásticos de búsqueda local (LSopt
) y el Umbral de Aceptación (TAopt
). Yo
el uso de las implementaciones en el NMOF paquete. La diferencia entre los dos algoritmos es que LSopt
le
sólo aceptan a los vecinos que no son peores que el
solución actual, mientras que TAopt
es más tolerante y
incluso a aceptar soluciones que son ligeramente peor que el
solución actual. De esta manera, TAopt
puede escapar de local
los mínimos. Ambos métodos utilizan 100000 iteraciones.
steps <- 100000
sol_LS <- LSopt(mvar, list(x0 = Data$I[,1],
neighbour = nb,
nS = steps),
Data = Data)
sol_TA <- TAopt(mvar, list(x0 = Data$I[,1],
neighbour = nb,
nS = steps/10),
Data = Data)
Podemos comparar los resultados de ambos métodos con nuestro
punto de referencia de la solución, que me agregue como un azul horizontal
de la línea.
par(mar = c(5,5,1,1), las = 1, mgp = c(3,0.25,0), tck = 0.01)
plot(x = seq(1, steps, length.out = 1000),
y = sol_TA$Fmat[seq(1, steps, length.out = 1000),2], log = "y",
xlab = "iteration", ylab = "portfolio vol", type = "l")
lines(x = seq(1, steps, length.out = 1000),
y = sol_LS$Fmat[seq(1, steps, length.out = 1000),2], col = grey(.4))
abline(h = mvar(x_sort, Data), col = "blue")
legend("topright",
legend = c("Local Search", "Threshold Accepting"),
col = c(grey(.4), "black"), lwd = 4, lty =1)
text(x = steps*0.8, y = mvar(x_sort, Data), pos = 3,
"lowest-vol asset per country", col = "blue")
LSopt
(gris) y TAopt
(negro) ambos a lograr soluciones de alrededor de 0.1%, por lo que claramente mejor que la de la solución constructiva. Umbral de Aceptación de prestaciones son ligeramente mejor que una simple búsqueda local.