QSTK Tutorial 7
In this tutorial we will use the qstk portfolio optimization function which in turn calls a Numerical Algorithms Group (NAG) function to do the convex optimization.
A NAG library license is required for this function, as well as a compiled NAG interface library, nagint.so. Instructions on how to compile this library can be found at extlib/NAG/README. For Georgia Tech students, the default config.sh exports the variables pointing to the library and license for the Gekko machine. I.e. if you are working on gekko, the portfolio optimization should work out of the box.
The tsutil.getOptPort() 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. 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.
To use getOptPort 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 for fTarget = None, just get average returns ''' (naAvgRets, naStd) = tsu.getOptPort( naData, None, lPeriod ) fMin = np.min(naAvgRets) fMax = np.max(naAvgRets)
The min and max provide bounds to plotting the efficient frontier. Targeting returns beyond this will produce an infeasible portfolio and return a generic NAG error. If you run into other issues, NAG debug can be turned on through a flag passed into getPortOpt().
Normal calls to getPortOpt 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.
''' Call the function 100 times for the given range ''' for fTarget in lfReturn: (naWeights, fStd) = tsu.getOptPort( naData, fTarget, lPeriod ) lfStd.append(fStd) lnaPortfolios.append( naWeights )
Efficient Frontier Plot
The rest of the tutorial pulls data for the S&P100 in 2009 and 2001, 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.