'''
(c) 2011, 2012 Georgia Tech Research Corporation
This source code is released under the New BSD license. Please see
http://wiki.quantsoftware.org/index.php?title=QSTK_License
for license details.
Created on January, 24, 2013
@author: Sourabh Bajaj
@contact: sourabhbajaj@gatech.edu
@summary: Demonstrates the use of the CVXOPT portfolio optimization call.
'''
# QSTK Imports
import QSTK.qstkutil.qsdateutil as du
import QSTK.qstkutil.tsutil as tsu
import QSTK.qstkutil.DataAccess as da
# Third Party Imports
import datetime as dt
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
def getFrontier(na_data):
'''Function gets a 100 sample point frontier for given returns'''
# 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[1])
na_upper = np.ones(na_data.shape[1])
# 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")
# Getting the step size and list of returns to optimize for.
f_step = (f_max - f_min) / 100.0
lf_returns = [f_min + x * f_step for x in range(101)]
# Declaring empty lists
lf_std = []
lna_portfolios = []
# 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)
return (lf_returns, lf_std, lna_portfolios, na_avgrets, na_std)
def main():
'''Main Function'''
# S&P 100
ls_symbols = ['AAPL', 'ABT', 'ACN', 'AEP', 'ALL', 'AMGN', 'AMZN', 'APC', 'AXP', 'BA', 'BAC', 'BAX', 'BHI', 'BK', 'BMY', 'BRK.B', 'CAT', 'C', 'CL', 'CMCSA', 'COF', 'COP', 'COST', 'CPB', 'CSCO', 'CVS', 'CVX', 'DD', 'DELL', 'DIS', 'DOW', 'DVN', 'EBAY', 'EMC', 'EXC', 'F', 'FCX', 'FDX', 'GD', 'GE', 'GILD', 'GOOG', 'GS', 'HAL', 'HD', 'HNZ', 'HON', 'HPQ', 'IBM', 'INTC', 'JNJ', 'JPM', 'KFT', 'KO', 'LLY', 'LMT', 'LOW', 'MA', 'MCD', 'MDT', 'MET', 'MMM', 'MO', 'MON', 'MRK', 'MS', 'MSFT', 'NKE', 'NOV', 'NSC', 'NWSA', 'NYX', 'ORCL', 'OXY', 'PEP', 'PFE', 'PG', 'PM', 'QCOM', 'RF', 'RTN', 'SBUX', 'SLB', 'HSH', 'SO', 'SPG', 'T', 'TGT', 'TWX', 'TXN', 'UNH', 'UPS', 'USB', 'UTX', 'VZ', 'WAG', 'WFC', 'WMB', 'WMT', 'XOM']
# Creating an object of the dataaccess class with Yahoo as the source.
c_dataobj = da.DataAccess('Yahoo')
ls_all_syms = c_dataobj.get_all_symbols()
# Bad symbols are symbols present in portfolio but not in all syms
ls_bad_syms = list(set(ls_symbols) - set(ls_all_syms))
for s_sym in ls_bad_syms:
i_index = ls_symbols.index(s_sym)
ls_symbols.pop(i_index)
# Start and End date of the charts
dt_end = dt.datetime(2010, 1, 1)
dt_start = dt_end - dt.timedelta(days=365)
dt_test = dt_end + dt.timedelta(days=365)
# We need closing prices so the timestamp should be hours=16.
dt_timeofday = dt.timedelta(hours=16)
# Get a list of trading days between the start and the end.
ldt_timestamps = du.getNYSEdays(dt_start, dt_end, dt_timeofday)
ldt_timestamps_test = du.getNYSEdays(dt_end, dt_test, dt_timeofday)
# Reading just the close prices
df_close = c_dataobj.get_data(ldt_timestamps, ls_symbols, "close")
df_close_test = c_dataobj.get_data(ldt_timestamps_test, ls_symbols, "close")
# Filling the data for missing NAN values
df_close = df_close.fillna(method='ffill')
df_close = df_close.fillna(method='bfill')
df_close_test = df_close_test.fillna(method='ffill')
df_close_test = df_close_test.fillna(method='bfill')
# Copying the data values to a numpy array to get returns
na_data = df_close.values.copy()
na_data_test = df_close_test.values.copy()
# Getting the daily returns
tsu.returnize0(na_data)
tsu.returnize0(na_data_test)
# Calculating the frontier.
(lf_returns, lf_std, lna_portfolios, na_avgrets, na_std) = getFrontier(na_data)
(lf_returns_test, lf_std_test, unused, unused, unused) = getFrontier(na_data_test)
# Plotting the efficient frontier
plt.clf()
plt.plot(lf_std, lf_returns, 'b')
plt.plot(lf_std_test, lf_returns_test, 'r')
# Plot where the efficient frontier would be the following year
lf_ret_port_test = []
lf_std_port_test = []
for na_portfolio in lna_portfolios:
na_port_rets = np.dot(na_data_test, na_portfolio)
lf_std_port_test.append(np.std(na_port_rets))
lf_ret_port_test.append(np.average(na_port_rets))
plt.plot(lf_std_port_test, lf_ret_port_test, 'k')
# Plot indivisual stock risk/return as green +
for i, f_ret in enumerate(na_avgrets):
plt.plot(na_std[i], f_ret, 'g+')
# # Plot some arrows showing transistion of efficient frontier
# for i in range(0, 101, 10):
# plt.arrow(lf_std[i], lf_returns[i], lf_std_port_test[i] - lf_std[i],
# lf_ret_port_test[i] - lf_returns[i], color='k')
# Labels and Axis
plt.legend(['2009 Frontier', '2010 Frontier',
'Performance of \'09 Frontier in 2010'], loc='lower right')
plt.title('Efficient Frontier For S&P 100 ')
plt.ylabel('Expected Return')
plt.xlabel('StDev')
plt.savefig('tutorial8.pdf', format='pdf')
if __name__ == '__main__':
main()