├── .gitignore ├── Interpolation ├── interpolation_point_example.py └── interpolation_line_example.py ├── First_Second_Derivatives └── first_second_derivative_examples.py ├── README.md ├── csv_data_writer.py ├── PANDAS_MultiTicker_Download_Normalized_Plot ├── MPT ├── Markowitz_Optimization.py └── MarkowitzPortfolio.py ├── Calculate_Drawdown_Max_Drawdown ├── Correlation_Matrix_Example.py ├── Markowitz_Plot_Example.py ├── Asset_Allocation └── Asset_Allocation_with_Risk_Free_Asset.py ├── yahoo_quote_pd.py ├── mean_reversion_tutorial.py ├── adf_cointegration.py ├── Option_Pricing ├── american_option_price_binomial.py └── European_Option_Price_Hilpisch.py └── Robust_Asset_Allocation └── Robust_Asset_Allocation.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /Interpolation/interpolation_point_example.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on April 30, 2014 3 | 4 | @author: Steven E. Sommer 5 | @summary: Python script to define X and Y values and to interpolate a Y value 6 | for a given value of X. Employs scipy.interpolate. 7 | ''' 8 | 9 | # Imports 10 | from scipy.interpolate import interp1d 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | # Define X and Y values 15 | x = np.arange(0, 10) 16 | y = np.array([3.0,-4.0,-2.0,-1.0, 3.0, 6.0, 10.0, 8.0, 12.0, 20.0]) 17 | 18 | # Define scipy interpolate function 19 | f = interp1d(x, y, kind = 'cubic') 20 | 21 | # Define X value for which to interpolate Y value 22 | xint = 3.5 23 | yint = f(xint) 24 | 25 | # Plot given values for X and Y and plot values for xint and yint 26 | plt.plot(x, y, 'o', c = 'b') 27 | plt.plot(xint, yint, 's', c = 'r') 28 | plt.show() 29 | -------------------------------------------------------------------------------- /Interpolation/interpolation_line_example.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on April 30, 2014 3 | 4 | @author: Steven E. Sommer 5 | @summary: Python script to define X and Y values and to interpolate a Y values 6 | for a given values of X to produce an interpolated line. Employs scipy.interpolate. 7 | ''' 8 | 9 | # Imports 10 | from scipy.interpolate import interp1d 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | # Define X and Y values 15 | x = np.arange(0, 10) 16 | y = np.array([3.0,-4.0,-2.0,-1.0, 3.0, 6.0, 10.0, 8.0, 12.0, 20.0]) 17 | 18 | # Define scipy interpolate function 19 | f = interp1d(x, y, kind = 'cubic') 20 | 21 | # Define range of X values for which to interpolate Y values (Result=line) 22 | xint = np.arange(0,9.01,0.01) 23 | yint = f(xint) 24 | 25 | # Plot given values for X and Y and plot values for xint and yint 26 | plt.plot(x, y, 'o', c = 'b') 27 | plt.plot(xint, yint,'-r') 28 | plt.show() 29 | -------------------------------------------------------------------------------- /First_Second_Derivatives/first_second_derivative_examples.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on April 30, 2014 3 | 4 | @author: Steven E. Sommer 5 | @summary: Python script to define a function, calculate the first and second 6 | derivatives and plot the function, first derivative and second derivative. 7 | ''' 8 | 9 | # Imports 10 | from scipy.misc import derivative 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | # Define a function 15 | f = lambda x : np.exp(-x)*np.sin(x) 16 | 17 | # Define x values for the function 18 | x = np.arange(0,10, 0.1) 19 | 20 | # Calculate the first and second derivatives of the defined function 21 | first = derivative(f,x,dx=1,n=1) 22 | second = derivative(f,x,dx=1,n=2) 23 | 24 | # Plot the function, first derivative and second derivative 25 | fig, ax = plt.subplots(3,1,sharex = True) 26 | ax[0].plot(x,f(x)) 27 | ax[0].set_ylabel(r'$f(x)$') 28 | ax[1].plot(x,first) 29 | ax[1].set_ylabel(r'$f\/\prime(x)$') 30 | ax[2].plot(x,second) 31 | ax[2].set_ylabel(r'$f\/\prime\prime(x)$') 32 | ax[2].set_xlabel(r'$x$') 33 | plt.show() 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python_Finance 2 | ============== 3 | 4 | This repository was orginally created to store python HW scripts for Georgia Institute of Technology 5 | Computational Finance I. However, wide distribution of these scripts violates anybody's honor code. Therefore, I initially 6 | refrained from uploading all of the code that I created for that course beyond HW assignment 1 or variants of that code and HW assignment 2. I have now uploaded all scripts related to the Georgia Tech Computational Finance I course to a private SVN and have deleted all scripts related to the Georgia Tech Computational Finance I course from GitHub. I have added additional python scripts for various other projects related to quantitative finance that don't compromise the Georgia Tech Computational Finance I course. 7 | 8 | I will also be adding python scripts for the Michael Halls-Moore's excellent Quantitative Finance tutorials at quantstart.com. Please note that all of the quantstart tutorial code has been run in Python 2.7.5+. To run the mean_reversion_tutorial.py you must install patsy and statsmodels from the terminal command line (sudo pip install patsy and sudo pip install statsmodels). 9 | -------------------------------------------------------------------------------- /csv_data_writer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created March 19. 2014 3 | 4 | @author: Steven E. Sommer 5 | @summary: Python script to download stock price and volume data for a list of 6 | ticker symbols from Yahoo Finance into a PANDAS DataFrame and write the 7 | timestamped price and volume data to a csv file. This is a very nice way to 8 | quickly create csv data files from a list of ticker symbols. 9 | ''' 10 | 11 | # Imports 12 | import pandas.io.data as web 13 | import datetime as dt 14 | import csv 15 | 16 | # Specify starting and ending dates for the data files 17 | startdate = dt.datetime(2007,1,1) 18 | enddate = dt.datetime(2014,3,18) 19 | 20 | # Specify the list of ticker symbols to download 21 | symbols = ['SPY','IWM'] 22 | 23 | # Acquire data from Yahoo Finance 24 | print "Getting data from Yahoo Finance" 25 | # Loop through the symbol list downloading data to PANDAS and writing this 26 | # data to a csv file 27 | for sym in symbols: 28 | # Download the data to PANDAS 29 | sym1 = web.DataReader(sym,'yahoo',startdate,enddate) 30 | print "Data for " + sym 31 | print sym1 32 | 33 | # Write data to a csv file 34 | print "Writing " + sym + " data to csv file" 35 | with open('%s.csv' %sym, 'w') as outfile: 36 | writer = csv.writer(outfile) 37 | for index in sym1.index: 38 | writer.writerow([index, sym1['Open'][index], sym1['High'][index], sym1['Low'][index],sym1['Close'][index], sym1['Volume'][index], sym1['Adj Close'][index]]) 39 | -------------------------------------------------------------------------------- /PANDAS_MultiTicker_Download_Normalized_Plot: -------------------------------------------------------------------------------- 1 | ''' 2 | Created January 26, 2014 3 | 4 | @Author: Steven E. Sommer, MD, MBA 5 | @Commentary: Python script to download multiple stock tickers from Yahoo 6 | Finance, create a PANDAS dataframe, normalize the returns and plot the 7 | comparative returns vs the SPY (ETF proxy for S&P 500). This script runs in Python 3.3.3 and PANDAS 0.13.0 8 | ''' 9 | 10 | # Third Party Imports 11 | import pandas.io.data as web 12 | import matplotlib.pyplot as plt 13 | import datetime as dt 14 | import pandas as pd 15 | 16 | # Starting and Ending Dates 17 | start_date = dt.datetime(2013,8,1) 18 | end_date = dt.datetime(2014,1,24) 19 | 20 | # Tickers to download 21 | msft = web.DataReader('MSFT', "yahoo", start_date, end_date) 22 | wfc = web.DataReader('WFC', "yahoo", start_date, end_date) 23 | sne = web.DataReader('SNE', "yahoo", start_date, end_date) 24 | sbux = web.DataReader('SBUX', "yahoo", start_date, end_date) 25 | spy = web.DataReader('SPY', "yahoo", start_date, end_date) 26 | 27 | # Construct a PANDAS DataFrame 28 | df = pd.DataFrame(data = {'MSFT': msft['Adj Close'], 'WFC': wfc['Adj Close'], 'SNE': sne['Adj Close'], 'SBUX': sbux['Adj Close'], 'SPY': spy['Adj Close']}) 29 | 30 | # Compute the Daily Returns 31 | df_ret = df.pct_change() 32 | 33 | # Index the Starting date to "0" to eliminate NAN 34 | df_ret.ix['2013-08-01'] = 0 35 | 36 | # Compute the Relative Returns 37 | df_rebased = (df_ret + 1).cumprod() 38 | 39 | # Plot the Relative Returns 40 | df_rebased.plot() 41 | 42 | # Save Plot as 'pdf' file 43 | plt.savefig('adjustedclose_ret.pdf', format='pdf') 44 | 45 | -------------------------------------------------------------------------------- /MPT/Markowitz_Optimization.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on April 10, 2014 3 | 4 | @author: Steven E. Sommer 5 | @summary: Python script to call functions from MarkowitzPortfolio.py and calculate MPT characteristics of a given 6 | portfolio and weights and create a Markowitz plot of given portfolio vs the Efficient Frontier. 7 | Please note that this script requires MarkowitzPortfolio.py in the same folder to run. 8 | ''' 9 | 10 | # Imports 11 | from MarkowitzPortfolio import * 12 | 13 | # Create Portfolio of stock Tickers and weights for each Ticker 14 | stockNames = ["MSFT", "HPQ", "AAPL", "NOK"] 15 | weights = [0.1,0.1,0.7,0.1] 16 | myPortfolio = MarkowitzPortfolio("01/01/2005", "today", "monthly", stockNames, weights, 100000) 17 | 18 | print "Portfolio Mean Returns" + "\n" 19 | print myPortfolio.meanReturns 20 | 21 | print "\n" + "\n" + "Portfolio Variance Covariance Matrix" + "\n" 22 | print myPortfolio.varianceCovarianceReturns 23 | 24 | print "\n" + "\n" + "Portfolio Expected Return and Variance" + "\n" 25 | print myPortfolio.estimate 26 | 27 | print "\n" + "\n" + "Optimum Weights for Same Expected Return and Lowest Variance" + "\n" 28 | print myPortfolio.minimumVarianceWeights 29 | 30 | print "\n" + "\n" + "Optimum Weights for Lowest Variance Portfolio" + "\n" 31 | print myPortfolio.globalMinimumVariance 32 | 33 | print "\n" + "\n" + "Weights for Minimum Variance Portfolio with Target Return = 0.2" + "\n" 34 | print myPortfolio.ComputeMinVariance(0.2) 35 | 36 | print "\n" + "\n" + "5% Value at Risk (VaR) = ", myPortfolio.VaR(0.05) 37 | 38 | print "\n" + "\n" + "Creating Markowitz Plot and saving to a PDF file" + "\n" 39 | myPortfolio.plot() 40 | -------------------------------------------------------------------------------- /Calculate_Drawdown_Max_Drawdown: -------------------------------------------------------------------------------- 1 | ''' 2 | Created 4/2/2015 3 | 4 | @author: Steven Sommer 5 | @summary: Python script to calculate the current and maximum drawdown of an asset or trading strategy. This script 6 | employs normalized returns to establish peak equity, current drawdown and maximum drawdown. This script is a very nice 7 | way to calculate the current drawdown and the maximum drawdown of a PANDAS DataFrame of normalized returns. 8 | By employing a count that that tracks the current drawdown and maximum drawdown starting with the second data points 9 | in the index, you can look at and compare subsequent index data points to the first index data point. 10 | 11 | Please Note: This script will NOT run as written as a free standing script. You must specify the required library 12 | imports, download data and calculate the normalized returns to run this script. However, you can easily incorporate 13 | the code into an existing script or create a function from this script. 14 | ''' 15 | 16 | # Calculate the drawdown and maximum drawdown 17 | symbols3 = ['SPXL','TMF','Sharpe'] 18 | dd = pd.DataFrame(index=rets.index, columns=symbols3) 19 | eq_peak = pd.DataFrame(index=rets.index, columns=symbols3) 20 | max_dd = pd.DataFrame(index=rets.index, columns=symbols3) 21 | 22 | count = 0 23 | 24 | for i in rets.index: 25 | for sym in symbols3: 26 | if count == 0: 27 | dd[sym][i]= 0 28 | max_dd[sym][i] = 0 29 | elif count > 0: 30 | eq_peak[sym][i] = max(norm_rets[sym][i],norm_rets[sym][count-1]) 31 | if eq_peak[sym][i] == norm_rets[sym][i]: 32 | dd[sym][i] = 0 33 | elif eq_peak[sym][i] > norm_rets[sym][i]: 34 | dd[sym][i] = -(eq_peak[sym][i] - norm_rets[sym][i]) 35 | max_dd[sym][i] = min(dd[sym][i],max_dd[sym][count-1]) 36 | count = count + 1 37 | -------------------------------------------------------------------------------- /Correlation_Matrix_Example.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created April 6, 2014 3 | 4 | @author: Steven Sommer 5 | @summary: Python script to download historical price data from Yahoo Finance to 6 | a PANDAS DataFrame, construct and print a Correlation Matrix, constuct a 7 | Correlation Heat Map and save that plot as a PDF file. 8 | ''' 9 | 10 | # Imports 11 | import datetime as dt 12 | import pandas as pd 13 | import pandas.io.data 14 | from pandas import Series, DataFrame 15 | import matplotlib.pyplot as plt 16 | import matplotlib as mpl 17 | import sys 18 | 19 | # Specify Matplotlib figure size 20 | mpl.rc('figure', figsize=(8, 7)) 21 | 22 | # Print Python, Pandas and Matplotlib versions 23 | print 'Python ' + sys.version 24 | print 'PANDAS ' + pd.__version__ 25 | print 'Matplotlib ' + mpl.__version__ + '\n' 26 | 27 | # Download historical price data from Yahoo Finance to a PANDAS DataFrame 28 | df = pd.io.data.get_data_yahoo(['AAPL', 'GE', 'HPQ', 'IBM', 'KO', 'MSFT', 'PEP'], 29 | start=dt.datetime(2010, 1, 1), 30 | end=dt.datetime(2013, 1, 1))['Adj Close'] 31 | 32 | # Print out the headers for the DataFrame 33 | print 'DataFrame headers' + '\n' 34 | print df.head() 35 | 36 | # Calculate daily returns for the Tickers in the DataFrame 37 | rets = df.pct_change() 38 | 39 | # Calculate the Correlation for the daily returns of the Tickers 40 | corr = rets.corr() 41 | 42 | # Print the Correlation Matrix 43 | print '\n' + 'Correlation Matrix' + '\n' 44 | print corr 45 | 46 | # Create a Correlatin Matrix Heat Map and save to a PDF file 47 | print '\n' + 'Creating a Correlation Matrix Heat Map and saving to PDF file' 48 | plt.imshow(corr, cmap='hot', interpolation='none') 49 | plt.colorbar() 50 | plt.xticks(range(len(corr)), corr.columns) 51 | plt.yticks(range(len(corr)), corr.columns); 52 | 53 | plt.savefig('Correlation_Matrix_Example.pdf', format='pdf') 54 | -------------------------------------------------------------------------------- /Markowitz_Plot_Example.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on April 6, 2014 3 | 4 | @author: Steven Sommer 5 | @summary: Python script to download historical price data from Yahoo Finance to 6 | a PANDAS DataFrame, construct a Markowitz Plot and save that plot as a PDF file. 7 | ''' 8 | 9 | # Imports 10 | import datetime as dt 11 | import pandas as pd 12 | import pandas.io.data 13 | from pandas import Series, DataFrame 14 | import matplotlib.pyplot as plt 15 | import matplotlib as mpl 16 | import sys 17 | 18 | # Specify Matplotlib figure size 19 | mpl.rc('figure', figsize=(8, 7)) 20 | 21 | # Print Python, Pandas and Matplotlib versions 22 | print 'Python ' + sys.version 23 | print 'PANDAS ' + pd.__version__ 24 | print 'Matplotlib ' + mpl.__version__ + '\n' 25 | 26 | # Download historical price data from Yahoo Finance to a PANDAS DataFrame 27 | df = pd.io.data.get_data_yahoo(['AAPL', 'GE', 'HPQ', 'IBM', 'KO', 'MSFT', 'PEP'], 28 | start=dt.datetime(2010, 1, 1), 29 | end=dt.datetime(2013, 1, 1))['Adj Close'] 30 | # Print out the headers for the DataFrame 31 | print 'DataFrame headers' + '\n' 32 | print df.head() 33 | 34 | # Calculate daily returns for the Tickers in the DataFrame 35 | rets = df.pct_change() 36 | 37 | # Create the annotated Markowitz Plot and save to a PDF file 38 | print '\n' + 'Creating annotated Markowitz Plot and saving to PDF file' 39 | plt.scatter(rets.std(), rets.mean()) 40 | plt.xlabel('Risk') 41 | plt.ylabel('Expected returns') 42 | for label, x, y in zip(rets.columns, rets.std(), rets.mean()): 43 | plt.annotate( 44 | label, 45 | xy = (x, y), xytext = (20, -20), 46 | textcoords = 'offset points', ha = 'right', va = 'bottom', 47 | bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), 48 | arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')) 49 | 50 | plt.savefig('Markowitz_Plot_Example_1.pdf', format='pdf') 51 | -------------------------------------------------------------------------------- /Asset_Allocation/Asset_Allocation_with_Risk_Free_Asset.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created June 26, 2014 3 | 4 | @author: Steven E. Sommer 5 | @summary: Asset Allocation for Tangent Portfolio with Risk-Free Asset in Python 6 | Note: Script written to run in Python 2.7.6. 7 | ''' 8 | 9 | # Adapted from Accelerated Python for Quants Tutorial, Lesson 4 10 | # (c) 2014 QuantAtRisk 11 | 12 | from numpy import matrix, power 13 | from math import sqrt 14 | 15 | def TangentPortfolio(m,C,rf): 16 | # find number of rows and columns for the covariance matrix 17 | (nr,nc)=C.shape 18 | A=matrix([[0.0] for r in xrange(nr)]) 19 | A=(1/C)*(m-rf) 20 | (nr,nc)=A.shape 21 | A=A/sum(A[r,0] for r in xrange(nr)) 22 | w=[A[r,0] for r in xrange(nr)] 23 | pret=mu.T*A 24 | prsk=power(A.T*(C*A),0.5) 25 | return matrix(w),pret,prsk 26 | 27 | cov=matrix([[0.04, 0.004, 0.02],[0.004, 0.09, 0.09],[0.02,0.09,0.16]]) 28 | mu=matrix([[0.13],[0.11],[0.19]]) 29 | rf=0.05 30 | 31 | w,ret,rsk=TangentPortfolio(mu,cov,rf) 32 | 33 | print 'Portfolio weights:' + '\n' 34 | print(w.T),'\n' 35 | 36 | print 'Expected Portfolio Return = ',ret 37 | print 'Expected Portfolio Risk = ',rsk,'\n' 38 | 39 | # Calculate the Sharpe Ratio 40 | 41 | sharpe=(ret-rf)/rsk 42 | print 'Sharpe Ratio of 1st Asset = ',sharpe,'\n' 43 | 44 | count = 0 45 | for r in xrange(3): 46 | count = count + 1 47 | print 'Sharpe Ratio Asset #',count,' = ',((mu[r,0]-rf)/sqrt(cov[r,r])) 48 | 49 | # Calculate the Expected Portfolio Return and Expected Risk for fraction of 50 | # capital invested in risky assets 51 | 52 | # Define fraction of Capital invested in risky assets 53 | alpha= [0.7,0.25] 54 | 55 | # Calculate and print Expected Portfolio Return and Expected Portfolio Risk 56 | count2 = 0 57 | for a in alpha: 58 | count2 = count2 + 1 59 | print '\n' + 'Portfolio',count2 60 | print 'Capital at Risk = ',a 61 | print 'Expected Portfolio Return = ',((matrix(a)*w)*mu)+(1-a)*rf 62 | print 'Expected Rate of Risk = ',matrix(a)*power(w*cov*w.T,1),'\n' 63 | -------------------------------------------------------------------------------- /yahoo_quote_pd.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created 4/30/2013 3 | 4 | @author: Steven Sommer 5 | @commentary: Script to read Yahoo Finance Data directly to a Pandas DataFrame 6 | ''' 7 | 8 | import numpy as np 9 | import datetime as dt 10 | import urllib 11 | import urllib2 12 | import time 13 | from zipfile import ZipFile 14 | from pandas import DataFrame, read_csv, concat 15 | from pandas.io.parsers import TextParser 16 | 17 | def get_quote_yahoo(symbols): 18 | """ 19 | Get current yahoo quote 20 | 21 | Returns a DataFrame 22 | """ 23 | if not isinstance(symbols, list): 24 | raise TypeError, "symbols must be a list" 25 | # for codes see: http://www.gummy-stuff.org/Yahoo-data.htm 26 | codes = {'symbol':'s','last':'l1','change_pct':'p2','PE':'r','time':'t1','short_ratio':'s7'} 27 | request = str.join('',codes.values()) # code request string 28 | header = codes.keys() 29 | 30 | data = dict(zip(codes.keys(), [[] for i in range(len(codes))])) 31 | 32 | urlStr = 'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s' % (str.join('+',symbols), request) 33 | 34 | try: 35 | lines = urllib2.urlopen(urlStr).readlines() 36 | except Exception, e: 37 | s = "Failed to download:\n{0}".format(e) 38 | print s 39 | return None 40 | 41 | for line in lines: 42 | fields = line.strip().split(',') 43 | for i, field in enumerate(fields): 44 | if field[-2:] == '%"': 45 | data[header[i]].append(float(field.strip('"%'))) 46 | elif field[0] == '"': 47 | data[header[i]].append(field.strip('"')) 48 | else: 49 | try: 50 | data[header[i]].append(float(field)) 51 | except ValueError: 52 | data[header[i]].append(np.nan) 53 | 54 | idx = data.pop('symbol') 55 | 56 | return DataFrame(data, index=idx) 57 | 58 | ################################################# 59 | ############## MAIN CODE ###################### 60 | ################################################# 61 | 62 | 63 | symbols = ['GOOG', 'SPY', 'IBM', 'MSFT', '$SPX'] 64 | 65 | DataFrame = get_quote_yahoo(symbols) 66 | 67 | print DataFrame 68 | -------------------------------------------------------------------------------- /mean_reversion_tutorial.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created March 19, 2014 3 | 4 | @author: Steven Sommer (from Michael Halls-Moore's Mean Reversion Tutorial) 5 | @summary: Python script to look for Mean Reversion in time series data by application 6 | of the Augmented Dickey-Fuller (ADF) Test and, alternatively, testing for stationarity 7 | by the calculation of the Hurst Exponent. Please note that you must have patsy and statsmodels 8 | installed to run this script. Note: Google symbol edited on May 7, 2014 to reflect the recent 9 | changes to the Google symbols due to the split of the shares in Class A and Class C stock: 10 | GOOG = Class C stock and GOOGL = Class A stock. 11 | ''' 12 | 13 | # Import the Time Series library 14 | import statsmodels.tsa.stattools as ts 15 | 16 | # Import Datetime and the Pandas DataReader 17 | from datetime import datetime 18 | from pandas.io.data import DataReader 19 | 20 | # Import from Numpy 21 | from numpy import cumsum, log, polyfit, sqrt, std, subtract 22 | from numpy.random import randn 23 | 24 | # Download the Google OHLCV data from 1/1/2000 to 1/1/2013 25 | googl = DataReader("GOOGL", "yahoo", datetime(2000,1,1), datetime(2013,1,1)) 26 | 27 | # Output the results of the Augmented Dickey-Fuller test for Google 28 | # with a lag order value of 1 29 | Augdf = ts.adfuller(googl['Adj Close'], 1) 30 | print Augdf 31 | 32 | # Hurst Exponent Calculation 33 | 34 | def hurst(ts): 35 | """Returns the Hurst Exponent of the time series vector ts""" 36 | # Create the range of lag values 37 | lags = range(2, 100) 38 | 39 | # Calculate the array of the variances of the lagged differences 40 | tau = [sqrt(std(subtract(ts[lag:], ts[:-lag]))) for lag in lags] 41 | 42 | # Use a linear fit to estimate the Hurst Exponent 43 | poly = polyfit(log(lags), log(tau), 1) 44 | 45 | # Return the Hurst exponent from the polyfit output 46 | return poly[0]*2.0 47 | 48 | # Create a Gometric Brownian Motion, Mean-Reverting and Trending Series 49 | gbm = log(cumsum(randn(100000))+1000) 50 | mr = log(randn(100000)+1000) 51 | tr = log(cumsum(randn(100000)+1)+1000) 52 | 53 | # Output the Hurst Exponent for each of the above series 54 | # and the price of Google (the Adjusted Close price) for 55 | # the ADF test given above in the article 56 | print "Hurst(GBM): %s" % hurst(gbm) 57 | print "Hurst(MR): %s" % hurst(mr) 58 | print "Hurst(TR): %s" % hurst(tr) 59 | 60 | # Assuming you have run the above code to obtain 'googl'! 61 | print "Hurst(GOOGL): %s" % hurst(googl['Adj Close']) 62 | -------------------------------------------------------------------------------- /adf_cointegration.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created July 27, 2014 3 | 4 | @author: Steven Sommer 5 | @summary: Python script to download specified pairs price data from Yahoo Finance to a PANDAS DataFrame, plot the price 6 | data, construct a scatter plot of pair prices, perform the ADF cointegration test results and print out the ADF 7 | Conintegration Test results. 8 | ''' 9 | 10 | import datetime as dt 11 | import pandas as pd 12 | import pandas.io.data 13 | from numpy import * 14 | from matplotlib.pyplot import * 15 | import statsmodels.api as sm 16 | import statsmodels.tsa.stattools as ts 17 | import matplotlib as mpl 18 | import sys 19 | 20 | # Specify Matplotlib figure size 21 | mpl.rc('figure', figsize=(8, 7)) 22 | 23 | # Print Python, Pandas and Matplotlib versions 24 | print 'Python ' + sys.version 25 | print 'PANDAS ' + pd.__version__ 26 | print 'Matplotlib ' + mpl.__version__ + '\n' 27 | 28 | # Construct the ADF Cointegration Test function 29 | def cointegration_test(y, x): 30 | ols_result = sm.OLS(y, x).fit() 31 | return ts.adfuller(ols_result.resid) 32 | 33 | ######################################################################### 34 | ######################## MAIN CODE ################################## 35 | ######################################################################### 36 | 37 | if __name__ == "__main__": 38 | 39 | # Download historical price data from Yahoo Finance to a PANDAS DataFrame 40 | symbols = ['EWC','EWA'] 41 | df = pd.io.data.get_data_yahoo(symbols, 42 | start=dt.datetime(2006, 4, 26), 43 | end=dt.datetime(2012, 4, 9))['Adj Close'] 44 | 45 | # Print out the headers for the DataFrame 46 | print 'df headers' + '\n' 47 | print df.head() 48 | 49 | # Plot EWA and EWC prices 50 | #df.plot() 51 | #savefig('EWA_EWC_Cointegration_priceplot.pdf', format='pdf') 52 | 53 | # Construct the Scatter plot of EWC and EWA 54 | y = df['EWC'] 55 | x = df['EWA'] 56 | k = polyfit(x,y,1) 57 | xx = linspace(min(x),max(x),1000) 58 | yy = polyval(k,xx) 59 | 60 | # Plot the Scatter Plot of EWC and EWA 61 | plot(x,y,'o') 62 | plot(xx,yy,'r') 63 | savefig('EWA_EWC_Cointegration_plot.pdf', format='pdf') 64 | 65 | # Call the ADF Cointegration Test Function 66 | adf_coint = cointegration_test(y,x) 67 | 68 | # Print the ADF Cointegration Test Results 69 | print '\n' + 'ADF Cointegration Test' + '\n' + '\n' , adf_coint 70 | print '\n' + 'ADF:', adf_coint[0] 71 | print '\n' + 'p value:', adf_coint[1] 72 | print '\n' + 'Lag:', adf_coint[2] 73 | print '\n' + 'Observations used:', adf_coint[3] 74 | print '\n' + 'Critical Values:', adf_coint[4] 75 | -------------------------------------------------------------------------------- /Option_Pricing/american_option_price_binomial.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created 1/13/2015 3 | 4 | @author: Steven E. Sommer, MD, MBA 5 | @summary: Python implementation of the American binomial option pricing model. 6 | ''' 7 | 8 | # Imports 9 | import numpy as np 10 | import math 11 | 12 | # Define the function for the Binomial American Stock Option 13 | def binomial_am_stock_opt(S0, K, r, T, N, pu, pd, is_call_opt=True, div=0.): 14 | ''' 15 | Price an American option by the binomial tree model. 16 | 17 | S0 - current stock price 18 | K - strike price of option 19 | r - annualized risk-free rate in decimal point form 20 | T - time left to maturity in years 21 | N - number of steps in the binomial tree 22 | pu - probability of up state in decimal point form 23 | pd - probability of down state in decimal point form 24 | is_call_opt - True for a call option; False for a put option 25 | div - annualized dividend yield of the stock in decimal point form 26 | ''' 27 | N = max(1, N) 28 | M = N+1 29 | u = 1 + pu 30 | d = 1 - pd 31 | dt = T/N 32 | discount_factor = math.exp(-(r-div)*dt) 33 | qu = (math.exp((r-div)*dt)-d)/(u-d) 34 | qd = 1-qu 35 | 36 | STs = [np.array([S0])] 37 | for i in range(N): 38 | prev_branches = STs[-1] 39 | st = np.concatenate((prev_branches*u, [prev_branches[-1]*d])) 40 | STs.append(st) 41 | 42 | ''' Get terminal payoffs ''' 43 | payoffs = np.maximum(0, (STs[N]-K)if is_call_opt else(K-STs[N])) 44 | 45 | for i in reversed(range(N)): 46 | early_ex_payoff = (STs[i] - K) if is_call_opt else (K - STs[i]) 47 | rn_payoff = (payoffs[:-1]*qu + payoffs[1:]*qd)*discount_factor 48 | payoffs = np.maximum(rn_payoff, early_ex_payoff) 49 | 50 | return payoffs[0] 51 | 52 | ################################################################################## 53 | ############################## MAIN Code ####################################### 54 | ################################################################################## 55 | 56 | if __name__ == "__main__": 57 | 58 | # Call the Binomial American Stock Option Pricing Function and pass the required function arguments (variables). 59 | 60 | american_option_price = binomial_am_stock_opt(50, 50, 0.05, 0.5, 2, 0.2, 0.2, False, 0) 61 | 62 | # Print the current American Option Price 63 | # Print statement to round American Option price to 2 significant digits 64 | print 'Current American Stock Option Price (Binomial Tree Model) = $ %.2f' % american_option_price 65 | # Print statement to print all digits calculated 66 | print 'Current American Stock Option Price (Binomial Tree Model) = $', american_option_price 67 | 68 | -------------------------------------------------------------------------------- /Option_Pricing/European_Option_Price_Hilpisch.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created 1/14/2015 3 | 4 | @author: Steven E. Sommer, MD, MBA. Adapted from Hilpisch 5 | @summary: 6 | Valuation of European Call and Put Options 7 | Under Stochastic Volatility and Interest Rates 8 | Parameter Examples from Medvedev & Scaillet ( 2009 ): 9 | " Pricing American Options Under Stochastic Volatility 10 | and Stochastic Interest Rates " 11 | Working Paper No. 429 , Finrisk --- MS ( 2009 ) 12 | 13 | (c) Visixion GmbH - Dr. Y. Hilpisch 14 | Script for illustration purposes only . 15 | August 2011 16 | 17 | SVSI_Euro_Valuation.py 18 | ''' 19 | 20 | # Imports 21 | from numpy import * 22 | from scipy.integrate import * 23 | 24 | # 25 | # Example Parameters H93 Model 26 | # 27 | kappa_v = 1.5 28 | theta_v = 0.02 29 | sigma_v = 0.15 30 | rho = 0.1 31 | v0 = 0.01 32 | S0 = 100.0 33 | K = 90.0 34 | T = 1.0/12 35 | 36 | # 37 | # Valuation by Integration 38 | # 39 | def H93_Value_Call_Int ( S0 ,K ,T , B0T , kappa_v , theta_v , sigma_v , rho , v0 ): 40 | r=- log ( B0T )/ T 41 | Int = quad ( lambda u: H93_Int_Func (u ,S0 ,K ,T ,r , kappa_v , 42 | theta_v , sigma_v , rho , v0 ),0 , 1000 )[ 0 ] 43 | return max(0 ,S0 - B0T * sqrt ( S0 *K )/ pi * Int ) 44 | 45 | # 46 | # Integration Function 47 | # 48 | def H93_Int_Func (u ,S0 ,K ,T ,r , kappa_v , theta_v , sigma_v , rho , v0 ): 49 | CF = H93_Char_Func (u - 1j *0.5 ,T ,r , kappa_v , theta_v , sigma_v , rho , v0 ) 50 | return 1 /( u ** 2+ 0.25 )*( exp ( 1j * u* log ( S0 /K ))* CF ). real 51 | 52 | # 53 | # Characteristic Function 54 | # 55 | def H93_Char_Func (u ,T ,r , kappa_v , theta_v , sigma_v , rho , v0 ): 56 | c1 = kappa_v * theta_v 57 | c2 = - sqrt (( rho * sigma_v *u* 1j - kappa_v )** 2 - sigma_v ** 2 *( - u*1j - u ** 2 )) 58 | c3 = ( kappa_v - rho * sigma_v * u* 1j + c2 )/( kappa_v - rho * sigma_v *u*1j - c2 ) 59 | H1 = (r* u* 1j *T +( c1 / sigma_v ** 2 )*(( kappa_v - rho * sigma_v *u * 1j + c2 )* T 60 | -2 * log ((1 - c3 * exp ( c2 * T ))/( 1 - c3 )))) 61 | H2 = (( kappa_v - rho * sigma_v *u* 1j + c2 )/ sigma_v ** 2* 62 | ((1 - exp ( c2 * T ))/( 1 - c3 * exp ( c2 *T )))) 63 | return exp ( H1 + H2 * v0 ) 64 | 65 | # 66 | # Example Parameters CIR85 Model 67 | # 68 | kappa_r , theta_r , sigma_r , r0 ,T =0.3 , 0.04 , 0.1 , 0.04 , 1.0/ 12 69 | 70 | # 71 | # (Zero - Coupon -) Bond Valuation Formula 72 | # 73 | def gamma ( kappa_r , sigma_r ): 74 | return sqrt ( kappa_r ** 2+2* sigma_r ** 2) 75 | 76 | def b1( alpha ): 77 | kappa_r , theta_r , sigma_r , r0 ,T = alpha 78 | g = gamma ( kappa_r , sigma_r ) 79 | return (( 2* g* exp (( kappa_r +g )* T/2 ))/ 80 | (2* g +( kappa_r +g )*( exp ( g*T) -1 )))**( 2* kappa_r * theta_r / sigma_r ** 2) 81 | 82 | def b2( alpha ): 83 | kappa_r , theta_r , sigma_r , r0 ,T = alpha 84 | g = gamma ( kappa_r , sigma_r ) 85 | return (( 2 *( exp (g*T) -1 ))/ 86 | (2* g +( kappa_r +g )*( exp ( g*T) -1 ))) 87 | 88 | def B( alpha ): 89 | b_1 = b1 ( alpha ); b_2 = b2 ( alpha ) 90 | kappa_r , theta_r , sigma_r , r0 ,T = alpha 91 | return b_1 * exp ( - b_2 * r0 ) 92 | 93 | # 94 | # Example Values 95 | # 96 | B0T =B ([ kappa_r , theta_r , sigma_r ,r0 , T ]) # Discount Factor 97 | C0 = H93_Value_Call_Int (S0 ,K ,T , B0T , kappa_v , theta_v , sigma_v , rho , v0 ) 98 | P0 = C0 + K* B0T - S0 99 | print " H93 Call Value = ", C0 100 | print " H93 Put Value = ", P0 101 | -------------------------------------------------------------------------------- /Robust_Asset_Allocation/Robust_Asset_Allocation.py: -------------------------------------------------------------------------------- 1 | '''' 2 | Created May 3, 2015 3 | 4 | @author: Steven Sommer, MD, MBA 5 | @summary: Python script to download historical price data from Yahoo Finance to a PANDAS DataFrame, construct a moderate 6 | Robust Allocation Portfolio (modified Ivy Portfolio concept developed by Wesley Gray of Alpha Architect), print a graph 7 | of the cumulative returns to a PDF file, and print out the weights of the current portfolio holdings. 8 | Note: This script was developed in Python 2.7.6. 9 | ''' 10 | 11 | # Imports 12 | import datetime as dt 13 | import pandas as pd 14 | import pandas.io.data 15 | from pandas import Series, DataFrame 16 | import matplotlib.pyplot as plt 17 | import matplotlib as mpl 18 | import sys 19 | import numpy as np 20 | import math 21 | import portfolio_metrics_monthly as pmm 22 | 23 | # Specify Matplotlib figure size 24 | mpl.rc('figure', figsize=(8, 7)) 25 | 26 | # Print Python, Pandas and Matplotlib versions 27 | print 'Python ' + sys.version 28 | print 'PANDAS ' + pd.__version__ 29 | print 'Numpy ' + np.__version__ 30 | print 'Matplotlib ' + mpl.__version__ + '\n' 31 | 32 | # Define a list of ticker symbols 33 | symbols = ['PRF','PDP','GVAL','PIZ','VNQ','DBC','BND','SHY'] 34 | 35 | # Download historical price data from Yahoo Finance to a PANDAS DataFrame 36 | df = pd.io.data.get_data_yahoo(symbols, 37 | start=dt.datetime(2014, 3, 12), 38 | end=dt.datetime(2015, 12, 4))['Adj Close'] 39 | 40 | print df.head() 41 | 42 | # Calculate the daily returns 43 | rets = df.pct_change() 44 | 45 | # Define the maximum allowed fully invested asset weights for each asset 46 | # Weights used in this model correspond the the moderate Robust portfolio 47 | wt = [0.15,0.15,0.15,0.15,0.10,0.10,0.20] 48 | symbols1 = ['PRF','PDP','GVAL','PIZ','VNQ','DBC','BND'] 49 | max1 = pd.DataFrame(index=rets.index, columns=symbols1) 50 | 51 | days = 0 52 | for i in rets.index: 53 | c = 0 54 | for sym in symbols1: 55 | max1[sym][i] = wt[c] 56 | c = c + 1 57 | days = days + 1 58 | ''' 59 | # Asset weight total check (maximum asset weights must sum to 1.0) 60 | total_weight = 0 61 | for sym in symbols: 62 | total_weight = total_weight + max1[sym] 63 | if total_weight == 1: 64 | print 'Total maximal asset weight sum to 1.0!' 65 | else: 66 | print 'ERROR: Maximum assigned maximum asset weights <> 1.0!' 67 | ''' 68 | # Calculate 200 day SMA 69 | sma200 = pd.rolling_mean(df, 200) 70 | 71 | # Calculate the 200 day asset Beta (Rasset - Rf) 72 | # Step 1 - Calculate the 200 day asset returns 73 | asset_return = df.pct_change(200) 74 | 75 | # Step 2 - Calculate the 200 day asset Betas 76 | # Step 2a - Create a PANDAS DataFrame for the asset Betas 77 | beta = pd.DataFrame(index=rets.index, columns=symbols) 78 | 79 | # Step 2b - Populate the PANDAS DataFrame with the asset Betas 80 | for i in rets.index: 81 | for sym in symbols: 82 | beta[sym][i] = asset_return[sym][i] - asset_return['SHY'][i] 83 | 84 | # Calculate the dynamic asset weights 85 | # Step 1 - Create a PANDAS DataFrame for the dynamic asset weights 86 | asset_wt_ma = pd.DataFrame(index=rets.index, columns=symbols1) 87 | asset_wt_beta = pd.DataFrame(index=rets.index, columns=symbols1) 88 | asset_wt_tot = pd.DataFrame(index=rets.index, columns=symbols1) 89 | 90 | for i in rets.index: 91 | for sym in symbols1: 92 | if df[sym][i] > sma200[sym][i]: 93 | asset_wt_ma[sym][i] = max1[sym][i]/2 94 | elif df[sym][i] <= sma200[sym][i]: 95 | asset_wt_ma[sym][i] = 0 96 | if beta[sym][i] > 0: 97 | asset_wt_beta[sym][i] = max1[sym][i]/2 98 | elif beta[sym][i] <= 0: 99 | asset_wt_beta[sym][i] = 0 100 | 101 | for i in rets.index: 102 | for sym in symbols1: 103 | asset_wt_tot[sym][i] = asset_wt_ma[sym][i] + asset_wt_beta[sym][i] 104 | 105 | exposure = asset_wt_tot.sum(axis=1) 106 | shy_wt = 1 - exposure 107 | 108 | rets['Robust'] = Series(np.nan, index=rets.index) 109 | 110 | for i in rets.index: 111 | rets['Robust'][i] = (asset_wt_tot['PRF'][i] * rets['PRF'][i]) + (asset_wt_tot['PDP'][i] * rets['PDP'][i]) + (asset_wt_tot['GVAL'][i] * rets['GVAL'][i]) + (asset_wt_tot['PIZ'][i] * rets['PIZ'][i]) + \ 112 | (asset_wt_tot['VNQ'][i] * rets['VNQ'][i]) + (asset_wt_tot['DBC'][i] * rets['DBC'][i]) + (asset_wt_tot['BND'][i] * rets['BND'][i]) + (shy_wt[i] * rets['SHY'][i]) 113 | 114 | norm_rets = rets.cumsum() 115 | norm_rets.plot() 116 | plt.savefig('Robust_Asset_Allocation_-_2014_-_2015.pdf', format='pdf') 117 | 118 | print '\n' + 'Current Robust Portfolio Asset Allocations:' + '\n' 119 | 120 | for sym in symbols1: 121 | exp = asset_wt_tot[sym][-1] * 100 122 | print 'Weight %s:' %sym + ' %.2f' %exp + '%' 123 | exp_shy = shy_wt.ix[-1] * 100 124 | print 'Weight SHY: %.2f' %exp_shy + '%' 125 | 126 | -------------------------------------------------------------------------------- /MPT/MarkowitzPortfolio.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on April 10, 2014 3 | 4 | @author: Steven E. Sommer and Ange Le 5 | @summary: Python script to calculate MPT charactaristics of a given portfolio and weights. 6 | Please note that this script was originally written by Ange Le and by itself will not produce any output. 7 | You must run Markowitz_Optimization.py to call the functions created by this script. This script must be in the same 8 | folder as Markowitz_Optimization.py. 9 | ''' 10 | 11 | import urllib2 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | from pandas import * 15 | from datetime import * 16 | import scipy.stats 17 | import math 18 | import urllib2 19 | import re 20 | import os as os 21 | 22 | class MarkowitzPortfolio(object): 23 | def __init__(self, dateBegin, dateEnd, timeMarker, stockNames, weights, initialWealth): 24 | #self.dateBegin 25 | #self.dateEnd 26 | #self.timeMarker 27 | #self.initialWealth 28 | #self.stockNames 29 | #self.legend 30 | #self.weights 31 | #self.n (number of assets) 32 | #self.initialWealth 33 | #self.Matrix 34 | #self.Returns 35 | #self.meanReturns 36 | #self.varianceCovarianceReturns 37 | #self.expectedReturn 38 | #self.variance 39 | #self.globalMinimumVariance gives the weights for the safest portfolio 40 | #self.minVarianceWeights gives the weights that give the same initial expected return but for the lowest variance 41 | #self.minimumVarianceWeights pandas object 42 | #self.globalMinimumVarianceNp numpy object 43 | #self.estimate pandas object 44 | if not os.path.exists('data'): 45 | os.makedirs('data') 46 | self.dateBegin=dateBegin 47 | self.dateEnd=dateEnd 48 | self.timeMarker=timeMarker 49 | if(dateEnd=='today'): 50 | dateEnd=str(datetime.today()) 51 | dateEnd=dateEnd.split(" ") 52 | dateEnd=dateEnd[0] 53 | dateEnd=dateEnd.split("-") 54 | temp=dateEnd[2] 55 | dateEnd[2]=dateEnd[0] 56 | dateEnd[0]=dateEnd[1] 57 | dateEnd[1]=temp 58 | dateEnd='/'.join(dateEnd) 59 | 60 | self.stockNames=stockNames 61 | self.weights=np.array(weights,dtype=np.float64) 62 | self.n=self.weights.size 63 | self.initialWealth=np.array(initialWealth,dtype=np.float64) 64 | 65 | dateBeginFileFormat=dateBegin.replace("/","-") 66 | dateEndFileFormat=dateEnd.replace("/","-") 67 | stockFiles=list() 68 | N=len(stockNames) #number of assets 69 | for stock in stockNames: #download the data for each single stock 70 | self.downloadData(dateBegin, dateEnd, stock, timeMarker) 71 | stockFiles.append(stock+"-"+dateBeginFileFormat+"-to-"+dateEndFileFormat+".csv") 72 | firstStock=stockFiles[0] 73 | data = read_csv('data/'+firstStock, na_values=[" "]) 74 | close=np.array(data["Close"],dtype=np.float64) 75 | T=close.size 76 | Matrix=DataFrame(np.zeros([T, N]), columns=stockNames) 77 | Matrix[stockNames[0]]=close 78 | for k in range(1,N): 79 | stock=stockFiles[k] 80 | data = read_csv('data/'+stock, na_values=[" "]) 81 | close=np.array(data["Close"],dtype=np.float64) 82 | Matrix[stockNames[k]]=close 83 | self.Matrix=Matrix 84 | 85 | present=np.array(Matrix[:-1],dtype=np.float64) 86 | future=np.array(Matrix[1:],dtype=np.float64) 87 | Returns=(future/present)-1 88 | Returns=DataFrame(Returns, columns=stockNames) 89 | self.Returns=Returns 90 | self.meanReturns=Returns.mean() 91 | self.varianceCovarianceReturns=Returns.cov() 92 | self.expectedReturn=np.dot(self.weights,self.meanReturns) 93 | varianceTemp=np.dot(self.weights,self.varianceCovarianceReturns) 94 | self.variance=np.dot(varianceTemp,self.weights) 95 | 96 | 97 | covarianceMatrix=np.array(self.varianceCovarianceReturns) 98 | meansMatrix=np.array(self.meanReturns).reshape(self.n,1) 99 | onesMatrix=np.ones([self.n,1]) 100 | oneSingle=np.ones([1,1]) 101 | zerosMatrix=np.zeros([self.n,1]) 102 | zeroSingle=np.zeros([1,1]) 103 | 104 | A1=np.concatenate((2*covarianceMatrix, onesMatrix), axis=1) 105 | A2=np.concatenate((onesMatrix.T,zeroSingle), axis=1) 106 | A=np.concatenate((A1,A2), axis=0) 107 | b=np.concatenate((zerosMatrix, oneSingle), axis=0) 108 | z=np.dot(np.linalg.inv(A),b) 109 | x=z[:self.n] 110 | self.globalMinimumVarianceNp=x 111 | xMean=np.dot(x.T,self.meanReturns) 112 | xVarTemp=np.dot(x.T,self.varianceCovarianceReturns) 113 | xVar=np.dot(xVarTemp,x) 114 | x=np.append(x, [xMean, xVar]) 115 | legend=stockNames[:] 116 | legend.append("Expected Return") 117 | legend.append("Variance") 118 | self.legend=legend 119 | self.globalMinimumVariance=DataFrame(x.reshape(1,(self.n)+2), columns=legend) 120 | 121 | 122 | targetReturn=np.array(self.expectedReturn).reshape(1,1) 123 | self.minVarianceWeights=self.minVariance(targetReturn) 124 | minVarianceMean=np.dot(self.minVarianceWeights.T,self.meanReturns) 125 | minVarianceVarTemp=np.dot(self.minVarianceWeights.T,self.varianceCovarianceReturns) 126 | minVarianceVar=np.dot(minVarianceVarTemp,self.minVarianceWeights) 127 | temp=np.append(self.minVarianceWeights.reshape(1,self.n),minVarianceMean) 128 | temp=np.append(temp,minVarianceVar) 129 | self.minimumVarianceWeights=DataFrame(temp.reshape(1,(self.n)+2), columns=legend) 130 | temp=np.array(self.weights) 131 | temp=np.append(temp,self.expectedReturn) 132 | temp=np.append(temp,self.variance) 133 | self.estimate=DataFrame(temp.reshape(1,(self.n)+2), columns=legend) 134 | self.initialWealth=initialWealth 135 | 136 | def downloadData(self,dateBegin,dateEnd,stockName,timeMarker): #format for the dates: "month/day/year" stockName ex : "MSFT" for Microsoft 137 | #months range from [00,...,11] (00 = January and 11 = December) 138 | dateBeginTab=dateBegin.split("/") 139 | dateEndTab=dateEnd.split("/") 140 | dateBeginTab[0]=str(int(dateBeginTab[0])-1) 141 | dateEndTab[0]=str(int(dateEndTab[0])-1) 142 | if (timeMarker=='monthly'): 143 | timeMarker='m' 144 | else: 145 | timeMarker='d' 146 | dataFile = urllib2.urlopen("http://ichart.finance.yahoo.com/table.csv?s="+stockName+"&a="+dateBeginTab[0]+"&b="+dateBeginTab[1]+"&c="+dateBeginTab[2]+"&d="+dateEndTab[0]+"&e="+dateEndTab[1]+"&f="+dateEndTab[2]+"&g="+timeMarker+"&ignore=.csv") 147 | temp=dataFile.read() 148 | temp=temp.split("\n") 149 | header=temp.pop(0) 150 | temp.reverse() #ranked in chronological order 151 | temp.pop(0) #after reverse() the first element is an empty element 152 | temp.insert(0,header) 153 | temp="\n".join(temp) 154 | savingFileName=stockName+'-'+dateBegin.replace("/","-")+'-to-'+dateEnd.replace("/","-")+'.csv' 155 | output = open('data/'+savingFileName,'wb') 156 | output.write(temp) 157 | output.close() 158 | dataFile.close() 159 | return temp 160 | 161 | def minVariance(self,targetReturn): #weights for the minimum variance for a target return 162 | targetReturn=np.array(targetReturn).reshape(1,1) 163 | covarianceMatrix=np.array(self.varianceCovarianceReturns) 164 | meansMatrix=np.array(self.meanReturns).reshape(self.n,1) 165 | onesMatrix=np.ones([self.n,1]) 166 | oneSingle=np.ones([1,1]) 167 | zerosMatrix=np.zeros([self.n,1]) 168 | zeroSingle=np.zeros([1,1]) 169 | A1=np.concatenate((2*covarianceMatrix, meansMatrix, onesMatrix), axis=1) 170 | A2=np.concatenate((meansMatrix.T,zeroSingle,zeroSingle), axis=1) 171 | A3=np.concatenate((onesMatrix.T,zeroSingle,zeroSingle), axis=1) 172 | A=np.concatenate((A1,A2,A3), axis=0) 173 | b=np.concatenate((zerosMatrix,targetReturn,oneSingle), axis=0) 174 | z=np.dot(np.linalg.inv(A),b) 175 | return z[:self.n] 176 | 177 | def ComputeMinVariance(self,targetReturn): 178 | x=self.minVariance(targetReturn) 179 | xMean=np.dot(x.T,self.meanReturns) 180 | xVarTemp=np.dot(x.T,self.varianceCovarianceReturns) 181 | xVar=np.dot(xVarTemp,x) 182 | x=np.append(x, [xMean, xVar]) 183 | print DataFrame(x.reshape(1,(self.n)+2), columns=self.legend) 184 | return x 185 | 186 | def efficientFrontier(self): 187 | x=self.globalMinimumVarianceNp 188 | xMean=np.dot(x.T,self.meanReturns) 189 | xVarTemp=np.dot(x.T,self.varianceCovarianceReturns) 190 | xVar=np.dot(xVarTemp,x) 191 | yMean=np.array((self.meanReturns).max()).reshape(1,1) 192 | y=self.minVariance(yMean) 193 | yVarTemp=np.dot(y.T,self.varianceCovarianceReturns) 194 | yVar=np.dot(yVarTemp,y) 195 | xVary=np.dot(xVarTemp,y) 196 | a=np.linspace(-1,1,100) 197 | zMean=a*xMean+(1-a)*yMean 198 | zVar=np.power(a,2)*xVar+np.power(1-a,2)*yVar+2*a*(1-a)*xVary 199 | return zVar, zMean 200 | 201 | def plot(self): 202 | var, mean=self.efficientFrontier() 203 | axScatter = plt.subplot(111) 204 | axScatter.scatter(var, mean,s=1,label='Efficient Frontier') 205 | axScatter.scatter(self.variance, self.expectedReturn, marker='*', s=40, color='red',label='Your Portfolio') 206 | bestMean=np.dot(self.minVarianceWeights.T,self.meanReturns) 207 | bestVarTemp=np.dot(self.minVarianceWeights.T,self.varianceCovarianceReturns) 208 | bestVar=np.dot(bestVarTemp,self.minVarianceWeights) 209 | axScatter.scatter(bestVar, bestMean, marker='*', s=40,color='green',label='Best Portfolio') 210 | axScatter.set_xlabel("Risk (Variance)",fontsize=20) 211 | axScatter.set_ylabel("Expected Return",fontsize=20) 212 | xmin=min(0,var.min(),bestVar,self.variance) 213 | xmax=max(var.max(),bestVar,self.variance) 214 | ymin=min(mean.min(),bestMean,self.expectedReturn) 215 | ymax=max(mean.max(),bestMean,self.expectedReturn) 216 | axScatter.set_xlim([xmin, xmax]) 217 | axScatter.set_ylim([ymin, ymax]) 218 | axScatter.grid(True,linestyle='-') 219 | axScatter.legend(numpoints=1, loc='upper left') 220 | axScatter.set_title("Markowitz Representation",fontsize=20) 221 | #plt.show() 222 | plt.savefig("myPortfolio_Markowitz_Plot.pdf", format="pdf") 223 | 224 | def VaR(self,a): 225 | return (self.expectedReturn + math.sqrt(self.variance)*scipy.stats.norm.ppf(a))*self.initialWealth 226 | 227 | def sourceCode(self,url): 228 | usock = urllib2.urlopen(url) 229 | data = usock.read() 230 | usock.close() 231 | return data 232 | 233 | def fetchSymbols(self): #fetch all the NYSE symbols 234 | print "Please wait while the symbols list is being downloaded from Yahoo..." 235 | symbols=list() 236 | link="http://finance.yahoo.com/q/cp?s=^NYA&c=" 237 | page=self.sourceCode('http://finance.yahoo.com/q/cp?s=^NYA') 238 | temp2=re.findall('Next '+'\S+'+' '+'1): 248 | for k in range(2,numberOfPages+1): 249 | total=total+self.sourceCode(link+str(k)) 250 | temp1=re.findall('',total) 251 | for singleSymbol in temp1: 252 | symbols.append(singleSymbol[17:-2]) 253 | return symbols 254 | 255 | def findNextPortfolioComponent(self,targetReturn): 256 | symbols=self.fetchSymbols() 257 | first=symbols[0] 258 | stockNamesTemp=self.stockNames[:] 259 | stockNamesTemp.append(first) 260 | weightsTemp=self.weights[:] 261 | weightsTemp=np.append(weightsTemp,1) 262 | portfolioTemp=MarkowitzPortfolio(self.dateBegin, self.dateEnd, self.timeMarker, stockNamesTemp,weightsTemp,self.initialWealth) 263 | temp=portfolioTemp.ComputeMinVariance(targetReturn) 264 | best=0 265 | lowestVariance=temp[(portfolioTemp.n)+1] 266 | for k in range(1,len(symbols)): 267 | newStock=symbols[k] 268 | stockNamesTemp=self.stockNames[:] 269 | stockNamesTemp.append(newStock) 270 | weightsTemp=self.weights[:] 271 | weightsTemp=np.append(weightsTemp,1) 272 | capt=1 273 | try: 274 | portfolioTemp=MarkowitzPortfolio(self.dateBegin, self.dateEnd, self.timeMarker, stockNamesTemp,weightsTemp,self.initialWealth) 275 | except: 276 | capt=0 277 | if(capt==1): 278 | temp=portfolioTemp.ComputeMinVariance(targetReturn) 279 | if(temp[(portfolioTemp.n)+1]