0

I am looking for a method that chooses the weights that minimize the portfolio variance.

For example:

I have 3 assets; their returns are given in an array below:

import numpy as np
x = np.array([[0.2,-0.1,0.5,-0.2],[0, -0.9, 0.8, 0.2],[0.4,0.5,-0.3,-.01]])

I can weight them how I want to as long as sum of their weights adds to 1. I am looking for such weights that minimize variance of the portfolio.

Here are two examples of randomly chosen weights:

weight_1 = [0.3,0.3,0.4]

weighted_x_1 = [ele_x*ele_w for ele_x,ele_w in zip (x,weight_1)]

var_1 = np.var(sum(weighted_x_1))


weight_2 = [-0.2,0.4,0.8]

weighted_x_2 = [ele_x*ele_w for ele_x,ele_w in zip (x,weight_2)]

var_2 = np.var(sum(weighted_x_2))

Output:

>>> var_1
0.02351675000000001
>>> var_2
0.012071999999999999

The second way is better.

Is there a Python (or a Python library) method that could do this for me? If not any suggestions on what method I should use to do the above are welcome.

Thank You in Advance

Akavall
  • 82,592
  • 51
  • 207
  • 251
  • Please see the accepted answer to this question: http://stackoverflow.com/questions/4119054/finance-lib-with-portfolio-optimization-method-in-python – George Skoptsov Apr 12 '12 at 16:59
  • 1
    This is a linear algebra problem. You can solve this using either linear programming or Lagrange optimization. Your constraint (lambda term) would be the 1 - sum(weights). – Joel Cornett Apr 12 '12 at 17:05
  • 1
    How is "portfolio variance" measured? – Joel Cornett Apr 12 '12 at 17:06
  • On a side note, you don't need to do things like `weighted_x_1 = [ele_x*ele_w for ele_x,ele_w in zip (x,weight_1)]`. Just do `weighted_x_1 = (weight_1 * x.T).T`. While that's a bit unreadable, if you work with things in columns instead of rows, it's just `weighted_x_1 = weight_1 * x`. – Joe Kington Apr 12 '12 at 17:17
  • Thanks for the suggestions. I need some time to go through those. – Akavall Apr 12 '12 at 23:25
  • @Joel Cornett, portfolio variance is variance of (sum of returns of all the assets weighted by their weights). I thought that two examples at the end illustrated it pretty clearly though. Did I understand your question? – Akavall Apr 12 '12 at 23:29
  • @Akavall: Ah, I see. I was confused because variance is usually the sum of squared errors (or variation) of a collection of data. I was reading the documentation and I'm pretty sure `numpy.var` calculates `sum((weight*return)**2)/(n - 1)` while what you want is "portfolio variance", which is actually `sum((weight*return)**2) + 2*weight1*return1*weight2*return2*covariance(1,2)...` and so on and so forth. [Portfolio variance on wikipedia](http://en.wikipedia.org/wiki/Modern_portfolio_theory#Risk_and_expected_return) – Joel Cornett Apr 13 '12 at 16:00
  • 1
    @Joel Cornett, Yes, but you don't need to use the "long formula" if you add your weighted returns first: Var(aX + bX) = a**2*Var(X) + b**2*Var(Y) + a*b*2*Cov(X,Y) http://en.wikipedia.org/wiki/Variance What I am doing is the left hand side of the equation. I don't think that I have any problem with calculation of variance. I am making some headway by using Gram-Schmidt process; I'll post my solution, if I am able to answer my own question. Thanks for the suggestions. – Akavall Apr 14 '12 at 04:26
  • @Akavall: I would be interested in seeing it. – Joel Cornett Apr 14 '12 at 04:31

2 Answers2

0

Please see the accepted answer to this question: Finance Lib with portfolio optimization method in python

Relevant bit is here:

Here's a quote from a post I found.

Some research says that "mean variance portfolio optimization" can give good results. I discussed this in a message

To implement this approach, a needed input is the covariance matrix of returns, which requires historical stock prices, which one can obtain using "Python quote grabber" http://www.openvest.org/Databases/ovpyq .

For expected returns -- hmmm. One of the papers I cited found that assuming equal expected returns of all stocks can give reasonable results.

Then one needs a "quadratic programming" solver, which appears to be handled by the CVXOPT Python package.

If someone implements the approach in Python, I'd be happy to hear about it.

There is a "backtest" package in R (open source stats package callable from Python) http://cran.r-project.org/web/packages/backtest/index.html "for exploring portfolio-based hypotheses about financial instruments (stocks, bonds, swaps, options, et cetera)."

Community
  • 1
  • 1
George Skoptsov
  • 3,831
  • 1
  • 26
  • 44
0

My full solution can be viewed in PDF.

The trick is to put the vectors x_i as columns of a matrix X.
Then writing the problem becomes a Convex Problem with constrain of the solution to be on the Unit Simplex.

I solved it using Projected Sub Gradient Method.
I calculated the Gradient of the objective function and created a projection to the Unit Simplex.

Now all needed is to iterate them.
I validated my solution using CVX.

% StackOverflow 44984132
% How to calculate weight to minimize variance?
% Remarks:
%   1.  sa
% TODO:
%   1.  ds
% Release Notes
% - 1.0.000     08/07/2017
%   *   First release.


%% General Parameters

run('InitScript.m');

figureIdx           = 0; %<! Continue from Question 1
figureCounterSpec   = '%04d';

generateFigures = OFF;


%% Simulation Parameters

dimOrder    = 3;
numSamples = 4;

mX = randi([1, 10], [dimOrder, numSamples]);
vE = ones([dimOrder, 1]);


%% Solve Using CVX

cvx_begin('quiet')
    cvx_precision('best');
    variable vW(numSamples)
    minimize( (0.5 * sum_square_abs( mX * vW - (1 / numSamples) * (vE.' * mX * vW) * vE )) )
    subject to
        sum(vW) == 1;
        vW >= 0;
cvx_end

disp([' ']);
disp(['CVX Solution -                       [ ', num2str(vW.'), ' ]']);


%% Solve Using Projected Sub Gradient

numIterations   = 20000;
stepSize        = 0.001;
simplexRadius   = 1; %<! Unit Simplex Radius
stopThr         = 1e-6;

hKernelFun  = @(vW) ((mX * vW) - ((1 / numSamples) * ((vE.' * mX * vW) * vE)));
hObjFun     = @(vW) 0.5 * sum(hKernelFun(vW) .^ 2);
hGradFun    = @(vW) (mX.' * hKernelFun(vW)) - ((1 / numSamples) * vE.' * (hKernelFun(vW)) * mX.' * vE);

vW = rand([numSamples, 1]);
vW = vW(:) / sum(vW);

for ii = 1:numIterations
    vGradW = hGradFun(vW);
    vW = vW - (stepSize * vGradW);

    % Projecting onto the Unit Simplex
    % sum(vW) == 1, vW >= 0.
    vW = ProjectSimplex(vW, simplexRadius, stopThr);
end

disp([' ']);
disp(['Projected Sub Gradient Solution -    [ ', num2str(vW.'), ' ]']);


%% Restore Defaults

% set(0, 'DefaultFigureWindowStyle', 'normal');
% set(0, 'DefaultAxesLooseInset', defaultLoosInset);

You can see the full code in StackOverflow Q44984132 Repository (PDF is available as well).

The solution was taken from StackOverflow Q44984132.

Royi
  • 4,640
  • 6
  • 46
  • 64