QSTK Tutorial 8
In this tutorial we will use the qstk portfolio optimization function which in turn calls a CVXOPT (A open source convex optimization library) function to do the convex optimization.
The code for this tutorial can be found in tutorial8.py in the "Examples/Basic/" directory.
The CVXOPT library is required for this tutorial. If you're a Georgia Tech student then this library is already installed on the server.
IMPORTANT : Please make sure you've CVXOPT installed on your system. Instructions are available here.
The tsutil.OptPort() function performs standard Markowitz optimization based on the risk/return of various assets. It requires the daily returns to be passed in as well as a target return value, expected return values, the upper and lower bounds of weights of entities. It will then return the bundle of assets which provide the desired return with the least amount of risk. Called many times it can also be used to plot the efficient frontier for all risk/return levels. If the expected returns are not specified then it assumes average returns of the data as the expected returns. If the lower bound is not specified then it assumes it to be zero for all the entries. The upper bound if not specified then is assumed to be one for all entries.
To use OptPort it is often the case that you want to call it with fTarget=None as shown below. This is a special call which will return the average returns of all assets based on the new sampling period.
# Special Case with fTarget=None, just returns average rets. (na_avgrets, na_std, b_error) = tsu.OptPort(na_data, None) # Declaring bounds on the optimized portfolio na_lower = np.zeros(na_data.shape) na_upper = np.ones(na_data.shape) # Getting the range of possible returns with these bounds (f_min, f_max) = tsu.getRetRange(na_data, na_lower, na_upper, na_avgrets, s_type="long")
The min and max provide bounds to plotting the efficient frontier. Targeting returns beyond this will produce an infeasible portfolio and return a error.
Normal calls to OptPort simply pass in the daily returns, new sampling period if desired, and target return. A tuple is returned containing the weights of each stock in the portfolio as well as the standard deviation of the resulting portfolio. The tutorial code below does this ~100 times to generate an efficient frontier plot.
# Calling the optimization for all returns for f_target in lf_returns: (na_weights, f_std, b_error) = tsu.OptPort(na_data, f_target, na_lower, na_upper, s_type="long") lf_std.append(f_std) lna_portfolios.append(na_weights)
Efficient Frontier Plot
The rest of the tutorial pulls data for the S&P100 in 2009 and 2010, plotting efficient frontiers for both years. Additionally it plots what the 2009 frontier would look like in 2010. Obviously there will be changes year to year.