Это нормально в scipy.optimise?
Я хочу оптимизировать свой портфель, используя теорию Марковица (минимизация рисков по методу Марковица для данного дохода = 15%) и Scipy.minimize
У меня есть функция риска
def objective(x):
x1=x[0];x2=x[1];x3=x[2]; x4=x[3]
return 1547.87020*x1**2 + 125.26258*x1*x2 + 1194.3433*x1*x3 + 63.6533*x1*x4 \
+ 27.3176649*x2**2 + 163.28848*x2*x3 + 4.829816*x2*x4 \
+ 392.11819*x3**2 + 56.50518*x3*x4 \
+ 34.484063*x4**2
Сумма частей запасов (в%) = 1
def constraint1(x):
return (x[0]+x[1]+x[2]+x[3]-1.0)
Функция дохода с ограничением
def constraint2(x):
return (-1.37458*x[0] + 0.92042*x[1] + 5.06189*x[2] + 0.35974*x[3] - 15.0)
И я проверяю это с помощью:
x0=[0,1,1,0] #Initial value
b=(0.0,1.0)
bnds=(b,b,b,b)
con1={'type':'ineq','fun':constraint1}
con2={'type':'eq','fun':constraint2}
cons=[con1,con2]
sol=minimize(objective,x0,method='SLSQP',\
bounds=bnds,constraints=cons)
И мой результат:
fun: 678.5433939
jac: array([1383.25920868, 222.75363159, 1004.03005219, 130.30312347])
message: 'Positive directional derivative for linesearch'
nfev: 216
nit: 20
njev: 16
status: 8
success: False
x: array([0., 1., 1., 1.])
Но как? Сумма частей портфеля не может быть больше 1(теперь части акции 2=stock3=stock4=100%). Его ограничение1. Где проблема?
2 ответа
В выходных данных говорится "success: False". Таким образом, он говорит вам, что не смог найти решение проблемы.
Кроме того, почему вы поставили con1={'type':'ineq','fun':constraint1}
Разве вы не хотите con1 = {'type': 'eq', 'fun': constraint1}
Я получил успех, используя метод ='BFGS'
Ваш код возвращает значения, которые не соблюдают ваше ограничение из-за ложного определения первого ограничения (a-b >= 0 => a>b)
так что в вашем случае a=1
(порядок в неравенстве важен). С другой стороны, вашx0
также должны уважать ваши ограничения и sum([0,1,1,0]) = 2 > 1
. Я немного улучшил ваш код и исправил вышеупомянутые проблемы, но я все еще думаю, что вам нужно пересмотреть свое второе ограничение:
import numpy as np
from scipy.optimize import minimize
def objective(x):
x1, x2, x3, x4 = x[0], x[1], x[2], x[3]
coefficients = np.array([1547.87020, 125.26258, 1194.3433, 63.6533, 27.3176649, 163.28848, 4.829816, 392.11819, 56.50518, 34.484063])
xs = np.array([ x1**2, x1*x2, x1*x3, x1*x4, x2**2, x2*x3, x2*x4, x3**2, x3*x4, x4**2])
return np.dot(xs, coefficients)
const1 = lambda x: 1 - sum(x)
const2 = lambda x: np.dot(np.array([-1.37458, 0.92042, 5.06189, 0.35974]), x) - 15.0
x0 = [0, 0, 0, 0] #Initial value
b = (0.0, 1.0)
bnds = (b, b, b, b)
cons = [{'type':'ineq','fun':const1}, {'type':'eq', 'fun':const2}]
# minimize
sol = minimize(objective,
x0,
method = 'SLSQP',
bounds = bnds,
constraints = cons)
print(sol)
выход:
fun: 392.1181900000138
jac: array([1194.34332275, 163.28847885, 784.23638535, 56.50518036])
message: 'Positive directional derivative for linesearch'
nfev: 92
nit: 11
njev: 7
status: 8
success: False
x: array([0.00000000e+00, 5.56638069e-14, 1.00000000e+00, 8.29371293e-14])