Estoy usando cvxpy a hacer una simple optimización de cartera.
He implementado el siguiente código ficticio
from cvxpy import *
import numpy as np
np.random.seed(1)
n = 10
Sigma = np.random.randn(n, n)
Sigma = Sigma.T.dot(Sigma)
orig_weight = [0.15,0.25,0.15,0.05,0.20,0,0.1,0,0.1,0]
w = Variable(n)
mu = np.abs(np.random.randn(n, 1))
ret = mu.T*w
lambda_ = Parameter(sign='positive')
lambda_ = 5
risk = quad_form(w, Sigma)
constraints = [sum_entries(w) == 1, w >= 0, sum_entries(abs(w-orig_weight)) <= 0.750]
prob = Problem(Maximize(ret - lambda_ * risk), constraints)
prob.solve()
print 'Solver Status : ',prob.status
print('Weights opt :', w.value)
Estoy limitando en ser completamente invertido, de largo y tienen una cifra de negocio <= 75%. Sin embargo, me gustaría utilizar la rotación de un "suave" de la restricción en el sentido de que el solucionador se utilizan como poco como sea posible, pero tanto como sea necesario, en la actualidad el solucionador casi totalmente el máximo de la cifra de negocios.
Yo, básicamente, quiero algo como esto que es convexo y no violar las reglas DCP
sum_entries(abs(w-orig_weight)) >= 0.05
Supongo que esto debe establecer un umbral mínimo (5%) y, a continuación, use la cantidad de rotación hasta que encuentra una solución factible.
Alguien alguna sugerencia de cómo esto podría ser solucionado o re-escrito en una forma convexa?
EDIT: solución Intermedia
from cvxpy import *
import numpy as np
np.random.seed(1)
n = 10
Sigma = np.random.randn(n, n)
Sigma = Sigma.T.dot(Sigma)
w = Variable(n)
mu = np.abs(np.random.randn(n, 1))
ret = mu.T*w
risk = quad_form(w, Sigma)
orig_weight = [0.15,0.2,0.2,0.2,0.2,0.05,0.0,0.0,0.0,0.0]
min_weight = [0.35,0.0,0.0,0.0,0.0,0,0.0,0,0.0,0.0]
max_weight = [0.35,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]
lambda_ret = Parameter(sign='positive')
lambda_ret = 5
lambda_risk = Parameter(sign='positive')
lambda_risk = 1
penalty = Parameter(sign='positive')
penalty = 100
penalized = True
if penalized == True:
print '-------------- RELAXED ------------------'
constraints = [sum_entries(w) == 1, w >= 0, w >= min_weight, w <= max_weight]
prob = Problem(Maximize(lambda_ * ret - lambda_ * risk - penalty * max_entries(sum_entries(abs(w-orig_weight)))-0.01), constraints)
else:
print '-------------- HARD ------------------'
constraints = [sum_entries(w) == 1, w >= 0, w >= min_weight, w <= max_weight, sum_entries(abs(w-orig_weight)) <= 0.40]
prob = Problem(Maximize(lambda_ret * ret - lambda_risk * risk ),constraints)
prob.solve()
print 'Solver Status : ',prob.status
print('Weights opt :', w.value)
all_in = []
for i in range(n):
all_in.append(np.abs(w.value[i][0] - orig_weight[i]))
print 'Turnover : ', sum(all_in)
El código anterior se fuerza un aumento específico en peso para el elemento[0], aquí +20%, con el fin de mantener la suma() =1 restricción que tiene que ser compensado por un -20% de disminución, por lo tanto sé que se necesita un mínimo de 40% del volumen de negocios que hacen que, si se ejecuta el código con penalizado = False <= 0.4 tiene que ser codificado, algo más pequeño que el que va a fracasar. La penalizado = True caso se encuentra el mínimo requerido volumen de ventas del 40% y resolver la optimización. Lo que no he averiguado todavía es, cómo puedo ajustar un umbral mínimo en el relajado caso, es decir, hacer al menos el 45% (o más si es necesario).
He encontrado algunas explicaciones en torno al problema de Multi-Período en el Comercio a través de la Optimización Convexa por Boyd et al., en el capítulo 4.6, página 37.