For a deeper look into our Eikon Data API, look into:

Overview |  Quickstart |  Documentation |  Downloads |  Tutorials |  Articles

question

Upvotes
Accepted
1 1 0 1

How to minimize the volatility of a portfolio as shown in video Tutorial "Eikon Data API - Python Quants Tutorial 6 - Portfolio Theory"

When testing the code in video tutorial "Eikon Data API - Python Quants Tutorial 6 - Portfolio Theory", I found it's hard to have minimized volatility by the sample code demonstrated in the video.


The average weight as initial guess will always be the optimization result. If a portfolio consists 5 stocks, the optimized weighting would be [0.2,0.2,0.2,0.2,0.2]. Is there anything missed by me or in the video?


eikoneikon-data-apipythonworkspaceworkspace-data-apirefinitiv-dataplatform-eikonportfoliooptimization
1589882200955.png (55.8 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
Accepted
7.5k 10 6 8

@Yufeng.Ling FYI I have just written a Jupyter notebook that goes through different portfolio optimisation methods using a recent library called mlfinlab. You can download the source from our github repo here. I hope this can help.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
7.5k 10 6 8

Hi @Yufeng.Ling thanks for your question. The initial guess is given by an equal weighted portfolio - in our case of 5 instruments. So in terms of the minimize function in our example:

scipy.optimize.minimize(fun, x0, bounds=None, constraints=()) where:

fun is the function to be minimized (lambda x: portfolio_volatility(rics, x))

x0 is the initial guess (len(rics) * [1 / len(rics)]) : with a 5 instrument array this gives us our equal weighted portfolio as below:

bounds is our boundary condition that each weighting be between 0 and 1 (len(rics) * [(0, 1)] - this gives us a five element array of min,max.

constraints is our condition that all weights must sum to 1 or our single equality constraint.

Now in our example after the minimize function we have a new set of weights.

fun: 0.05627559333731446
jac: array([0.06615351, 0.05769502, 0.05610596, 0.05649973, 0.05631664])
message: 'Optimization terminated successfully.'
nfev: 70
nit: 10
njev: 10
status: 0
success: True
x: array([8.53371115e-18, 0.00000000e+00, 3.66747487e-01, 1.97838465e-01, 4.35414048e-01])

If we have a look at the output from the minimize function we can see that:

x: is the solution of the optimization - in our case the first two terms are near zero - so we only have weights for the last 3 instruments.

fun: is the value of the objective function and

jac: its jacobian

nfev: is the number of function evaluations

nit: is the number of iterations

If I look at the output from your minimize function I can see that your jac: is a zero vector (which doesn't seem correct), also the nfev: is 7 versus 70 in our example and nit: is 1 in yours and 10 in our example. And this is for a similar 5 instrument portfolio.

So whilst I cannot see the code prior to the result output you posted. It seems that what is being handed to the minimize function is in someway not correct. This points to errors up above in the code. You can test the values of the inputs at any point against our example and try to debug there. I would look at evaluating the initial guess to see if an equal weighted array is returned. Or perhaps there is an error in the Portfolio_Volatility function. I hope this has provided a slightly clearer explanation for you.




1589973780933.png (57.8 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
1 1 0 1

Hi Jason,

Thanks for helping me on the issue. I tried to replicate the result after minimization but in vain. The sco.minimize() function always return initial guess as result. Please have my complete code as pasted below. Anything I'm wrong with?

Also pasted with version of each package below:


无标题.png (331.8 KiB)
ver.png (12.1 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
1 1 0 1

By adding parameter "method='SLSQP' , jac='rosen_der'" in sco.minimize(), it start to work to solve the minimal value optimization. But the result could vary a lot depending on initial guess.

Wonder if the scipy.optimize() is suitable to determine portfolio's minimal volatility. Appreciate if you can instruct on how to adjust the parameter or shall we use other Python package to solve the problem.


cp.jpg (210.2 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.