''' Created on 29 Sep 2013 @author: deniz turan (denizstij AT gmail DOT com) ''' import numpy as np import QSTK.qstkutil.qsdateutil as du import QSTK.qstkutil.tsutil as tsu import QSTK.qstkutil.DataAccess as da import datetime as dt import matplotlib.pyplot as plt import pandas as pd class PortfolioEfficientFrontierMonteCarloSimulator(): def simulate(self, dt_start, endDate, ls_symbols, weights): dt_timeofday = dt.timedelta(hours=16) ldt_timestamps = du.getNYSEdays(dt_start, dt_end, dt_timeofday) c_dataobj = da.DataAccess('Yahoo') ls_keys = ['open', 'high', 'low', 'close', 'volume', 'actual_close'] ldf_data = c_dataobj.get_data(ldt_timestamps, ls_symbols, ls_keys) d_data = dict(zip(ls_keys, ldf_data)) closePrices = d_data['close'].values rows = closePrices.shape[0] dailyReturns = (closePrices[0:rows, :] / closePrices[0, :]) dailyPortfolioCum = dailyReturns * weights; dailyPortfolioSum = np.sum(dailyPortfolioCum, axis=1) dailyPortfolioRet = (dailyPortfolioSum[1:rows] / dailyPortfolioSum[0:rows - 1]) - 1 dailyPortfolioRet = np.append(0, dailyPortfolioRet) mean = np.mean(dailyPortfolioRet, axis=0) vol = np.std(dailyPortfolioRet, axis=0) cumReturn = dailyPortfolioSum[-1] T = 252; riskFree = 0 sharpRatio = np.sqrt(T) * (mean - riskFree) / vol return [mean, vol, sharpRatio,cumReturn] def generateShortWeights(self, numWeight): weights = np.zeros(numWeight) weights[0:numWeight - 1] = np.random.randint(-101, 101, numWeight - 1) weights[numWeight - 1] = 100 - np.sum(weights) np.random.shuffle(weights) # eliminate bias on last element weights = weights / np.sum(weights) return weights def generateNoShortWeights(self, numWeight): weights = np.random.rand(numWeight) weights = weights / np.sum(weights) return weights def genareteWeight(self, numWeight, isShortAllowed): if isShortAllowed : return self.generateShortWeights(numWeight) else: return self.generateNoShortWeights(numWeight) myClass = PortfolioEfficientFrontierMonteCarloSimulator() dt_start = dt.datetime(2011, 1, 1) dt_end = dt.datetime(2011, 12, 31) stockList = ['AAPL', 'GLD', 'GOOG', 'XOM'] # weight=[0.4, 0.4, 0.0, 0.2] numTrial=10000 res= np.zeros((numTrial,4)) weights= np.zeros((numTrial,4)) for i in range(0, numTrial): weights[i] = myClass.genareteWeight(4, True) res[i,:]=myClass.simulate(dt_start, dt_end, stockList, weights[i]) # find index of min/max of mean and vol minMeanIndex=res[:,0].argmin() maxMeanIndex=res[:,0].argmax() minVolIndex=res[:,1].argmin() maxVolIndex=res[:,1].argmax() # min and max mean and vol maxVol=res[maxVolIndex,1] maxMean=res[maxMeanIndex,0] minVol=res[minVolIndex,1] minMean=res[minMeanIndex,0] # lets plot now plt.clf() plt.scatter(res[:,1],res[:,0],marker="+", linewidths=0.5) # Plot global mean variance portfolio plt.scatter(res[minVolIndex,1],res[minVolIndex,0],c='m',marker='x',linewidths=3) plt.xlim([minVol*0.8,maxVol*1.2]) plt.ylim([minMean*0.8,maxMean*1.2]) plt.ylabel('Return') plt.xlabel('Vol') plt.savefig('efficientFrontier.png', format='png') # lets print some stats now print "Global Mean-Variance, mean=%s, vol=%s, weights: %s" %( res[minVolIndex,0],res[minVolIndex,1], weights[minVolIndex,:]) print "minMeanIndex mean=%s, vol=%s, weights: %s" %( res[minMeanIndex,0],res[minMeanIndex,1], weights[minMeanIndex,:]) print "maxMeanIndex mean=%s, vol=%s, weights: %s" %( res[maxMeanIndex,0],res[maxMeanIndex,1], weights[maxMeanIndex,:]) print "maxVolIndex mean=%s, vol=%s, weights: %s" %( res[maxVolIndex,0],res[maxVolIndex,1], weights[maxVolIndex,:])
Efficient Frontier Portfolio (no short allowed) |