Finished basic functionalities

This commit is contained in:
Andrew Dinh 2019-02-14 12:17:22 -08:00
parent bec100cd44
commit d398924c0d
6 changed files with 676 additions and 199 deletions

3
.gitignore vendored
View File

@ -2,4 +2,5 @@ __pycache__/StockData.cpython-37.pyc
__pycache__/ __pycache__/
*.pyc *.pyc
test/ test/
.vscode/ .vscode/
requests_cache.sqlite

View File

@ -1,21 +1,17 @@
# Python file for general functions # Python file for general functions
def getNearest(items, pivot): def getNearest(items, pivot):
return min(items, key=lambda x: abs(x - pivot)) return min(items, key=lambda x: abs(x - pivot))
def stringToDate(date): def stringToDate(date):
from datetime import datetime from datetime import datetime
#datetime_object = datetime.strptime('Jun 1 2005 1:33PM', '%b %d %Y %I:%M%p') #datetime_object = datetime.strptime('Jun 1 2005 1:33PM', '%b %d %Y %I:%M%p')
datetime_object = datetime.strptime(date, '%Y-%m-%d').date() datetime_object = datetime.strptime(date, '%Y-%m-%d').date()
return(datetime_object) return(datetime_object)
'''
dateSplit = date.split('-')
year = int(dateSplit[0])
month = int(dateSplit[1])
day = int(dateSplit[2])
datetime_object = datetime.date(year, month, day)
'''
return datetime_object
def removeExtraDatesAndCloseValues(list1, list2): def removeExtraDatesAndCloseValues(list1, list2):
# Returns the two lists but with the extra dates and corresponding close values removed # Returns the two lists but with the extra dates and corresponding close values removed
@ -39,6 +35,25 @@ def removeExtraDatesAndCloseValues(list1, list2):
return returnList return returnList
def stringIsInt(s):
try:
int(s)
return True
except ValueError:
return False
def strintIsFloat(s):
try:
float(s)
return True
except ValueError:
return False
def fromCache(r):
import requests_cache
if r.from_cache == True:
print('(Response taken from cache)')
def main(): def main():
exit() exit()

787
main.py
View File

@ -1,12 +1,24 @@
# main.py # https://github.com/andrewkdinh/fund-indicators
# Determine indicators of overperforming mutual funds
# Andrew Dinh # Andrew Dinh
# Python 3.6.7 # Python 3.6.7
# Required
import requests import requests
import json import json
import datetime import datetime
import numpy
import Functions import Functions
import numpy as np
# Required for linear regression
import matplotlib.pyplot as plt
import sys
# Optional
import requests_cache
# https://requests-cache.readthedocs.io/en/lates/user_guide.html
requests_cache.install_cache(
'requests_cache', backend='sqlite', expire_after=43200) # 12 hours
# API Keys # API Keys
apiAV = 'O42ICUV58EIZZQMU' apiAV = 'O42ICUV58EIZZQMU'
@ -14,12 +26,14 @@ apiAV = 'O42ICUV58EIZZQMU'
apiBarchart = 'f40b136c6dc4451f9136bb53b9e70ffa' apiBarchart = 'f40b136c6dc4451f9136bb53b9e70ffa'
apiTiingo = '2e72b53f2ab4f5f4724c5c1e4d5d4ac0af3f7ca8' apiTiingo = '2e72b53f2ab4f5f4724c5c1e4d5d4ac0af3f7ca8'
apiTradier = 'n26IFFpkOFRVsB5SNTVNXicE5MPD' apiTradier = 'n26IFFpkOFRVsB5SNTVNXicE5MPD'
apiQuandl = 'KUh3U3hxke9tCimjhWEF'
# apiIntrinio = 'OmNmN2E5YWI1YzYxN2Q4NzEzZDhhOTgwN2E2NWRhOWNl'
# If you're going to take these API keys and abuse it, you should really reconsider your life priorities # If you're going to take these API keys and abuse it, you should really reconsider your life priorities
''' '''
API Keys: API Keys:
Alpha Vantage API Key: O42ICUV58EIZZQMU Alpha Vantage API Key: O42ICUV58EIZZQMU
Barchart API Key: a17fab99a1c21cd6f847e2f82b592838 Barchart API Key: a17fab99a1c21cd6f847e2f82b592838
Possible other one? f40b136c6dc4451f9136bb53b9e70ffa Possible other one? f40b136c6dc4451f9136bb53b9e70ffa
150 getHistory queries per day 150 getHistory queries per day
Tiingo API Key: 2e72b53f2ab4f5f4724c5c1e4d5d4ac0af3f7ca8 Tiingo API Key: 2e72b53f2ab4f5f4724c5c1e4d5d4ac0af3f7ca8
@ -28,20 +42,35 @@ API Keys:
Hourly Requests = 500 Hourly Requests = 500
Daily Requests = 20,000 Daily Requests = 20,000
Symbol Requests = 500 Symbol Requests = 500
Quandl API Key: KUh3U3hxke9tCimjhWEF
Intrinio API Key: OmNmN2E5YWI1YzYxN2Q4NzEzZDhhOTgwN2E2NWRhOWNl
Mutual funds: Mutual funds?
Yes: Alpha Vantage, Tiingo Yes: Alpha Vantage, Tiingo
No: IEX, Barchart No: IEX, Barchart
Adjusted?
Yes: Alpha Vantage, IEX
No: Tiingo
''' '''
class Stock: class Stock:
# GLOBAL VARIABLES # GLOBAL VARIABLES
timeFrame = [] timeFrame = 0
riskFreeRate = 0
indicator = ''
# BENCHMARK VALUES
benchmarkDates = [] benchmarkDates = []
benchmarkCloseValues = [] benchmarkCloseValues = []
benchmarkUnadjustedReturn = 0 benchmarkAverageAnnualReturn = 0
benchmarkStandardDeviation = 0
# INDICATOR VALUES
indicatorCorrelation = []
indicatorRegression = []
def __init__(self): def __init__(self):
# BASIC DATA # BASIC DATA
@ -54,24 +83,20 @@ class Stock:
self.closeValuesMatchBenchmark = [] self.closeValuesMatchBenchmark = []
# CALCULATED RETURN # CALCULATED RETURN
self.unadjustedReturn = 0 self.averageAnnualReturn = 0
self.sortino = 0 self.annualReturn = []
self.sharpe = 0 self.sharpe = 0
self.sortino = 0
self.treynor = 0 self.treynor = 0
self.alpha = 0 self.alpha = 0
self.beta = 0 self.beta = 0
self.standardDeviation = 0 self.standardDeviation = 0
self.negStandardDeviation = 0 self.downsideDeviation = 0
self.kurtosis = 0
self.skewness = 0 # Not sure if I need this
self.linearRegression = [] # for y=mx+b, this list has [m,b]
# INDICATOR VALUES self.indicatorValue = ''
self.expenseRatio = 0
self.assetSize = 0
self.turnover = 0
self.persistence = [] # [Years, Months]
# CALCULATED VALUES FOR INDICATORS
self.correlation = 0
self.regression = 0
def setName(self, newName): def setName(self, newName):
self.name = newName self.name = newName
@ -89,9 +114,10 @@ class Stock:
print('IEX') print('IEX')
url = ''.join( url = ''.join(
('https://api.iextrading.com/1.0/stock/', self.name, '/chart/5y')) ('https://api.iextrading.com/1.0/stock/', self.name, '/chart/5y'))
#link = "https://api.iextrading.com/1.0/stock/spy/chart/5y" # link = "https://api.iextrading.com/1.0/stock/spy/chart/5y"
print("\nSending request to:", url) print("\nSending request to:", url)
f = requests.get(url) f = requests.get(url)
Functions.fromCache(f)
json_data = f.text json_data = f.text
if json_data == 'Unknown symbol' or f.status_code == 404: if json_data == 'Unknown symbol' or f.status_code == 404:
print("IEX not available") print("IEX not available")
@ -129,8 +155,8 @@ class Stock:
# https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=MSFT&outputsize=full&apikey=demo # https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=MSFT&outputsize=full&apikey=demo
print("\nSending request to:", url) print("\nSending request to:", url)
print("(This will take a while)")
f = requests.get(url) f = requests.get(url)
Functions.fromCache(f)
json_data = f.text json_data = f.text
loaded_json = json.loads(json_data) loaded_json = json.loads(json_data)
@ -148,9 +174,9 @@ class Stock:
for i in range(0, len(listOfDates), 1): for i in range(0, len(listOfDates), 1):
temp = listOfDates[i] temp = listOfDates[i]
loaded_json2 = dailyTimeSeries[temp] loaded_json2 = dailyTimeSeries[temp]
#value = loaded_json2['4. close'] # value = loaded_json2['4. close']
value = loaded_json2['5. adjusted close'] value = loaded_json2['5. adjusted close']
values.append(value) values.append(float(value))
# listAV.append(values) # listAV.append(values)
listAV.append(list(reversed(values))) listAV.append(list(reversed(values)))
print(len(listAV[1]), "close values") print(len(listAV[1]), "close values")
@ -167,8 +193,9 @@ class Stock:
url = ''.join(('https://api.tiingo.com/tiingo/daily/', self.name)) url = ''.join(('https://api.tiingo.com/tiingo/daily/', self.name))
print("\nSending request to:", url) print("\nSending request to:", url)
f = requests.get(url, headers=headers) f = requests.get(url, headers=headers)
Functions.fromCache(f)
loaded_json = f.json() loaded_json = f.json()
if len(loaded_json) == 1 or f.status_code == 404: if len(loaded_json) == 1 or f.status_code == 404 or loaded_json['startDate'] == None:
print("Tiingo not available") print("Tiingo not available")
return 'Not available' return 'Not available'
@ -187,6 +214,7 @@ class Stock:
# https://api.tiingo.com/tiingo/daily/<ticker>/prices?startDate=2012-1-1&endDate=2016-1-1 # https://api.tiingo.com/tiingo/daily/<ticker>/prices?startDate=2012-1-1&endDate=2016-1-1
print("\nSending request to:", url2, '\n') print("\nSending request to:", url2, '\n')
requestResponse2 = requests.get(url2, headers=headers) requestResponse2 = requests.get(url2, headers=headers)
Functions.fromCache(requestResponse2)
loaded_json2 = requestResponse2.json() loaded_json2 = requestResponse2.json()
for i in range(0, len(loaded_json2)-1, 1): for i in range(0, len(loaded_json2)-1, 1):
line = loaded_json2[i] line = loaded_json2[i]
@ -210,12 +238,12 @@ class Stock:
def datesAndClose(self): def datesAndClose(self):
print('\n', Stock.getName(self), sep='') print('\n', Stock.getName(self), sep='')
# sourceList = ['AV', 'Tiingo', 'IEX'] # Change back to this later sourceList = ['AV', 'IEX', 'Tiingo']
sourceList = ['Tiingo', 'IEX', 'AV'] # sourceList = ['IEX', 'Tiingo', 'AV']
# Use each source until you get a value # Use each source until you get a value
for j in range(0, len(sourceList), 1): for j in range(0, len(sourceList), 1):
source = sourceList[j] source = sourceList[j]
print('\nSource being used: ', source) print('\nSource being used:', source)
if source == 'AV': if source == 'AV':
datesAndCloseList = Stock.AV(self) datesAndCloseList = Stock.AV(self)
@ -227,11 +255,11 @@ class Stock:
if datesAndCloseList != 'Not available': if datesAndCloseList != 'Not available':
break break
else: else:
#print(sourceList[j], 'does not have data available')
if j == len(sourceList)-1: if j == len(sourceList)-1:
print('\nNo sources have data for', self.name) print('\nNo sources have data for', self.name)
return print('Removing', self.name,
# FIGURE OUT WHAT TO DO HERE 'from list of stocks to ensure compatibility later')
return 'Not available'
# Convert dates to datetime # Convert dates to datetime
allDates = datesAndCloseList[0] allDates = datesAndCloseList[0]
@ -241,7 +269,7 @@ class Stock:
return datesAndCloseList return datesAndCloseList
def datesAndClose2(self): def datesAndCloseFitTimeFrame(self):
print('Shortening list to fit time frame') print('Shortening list to fit time frame')
# Have to do this because if I just make dates = self.allDates & closeValues = self.allCloseValues, then deleting from dates & closeValues also deletes it from self.allDates & self.allCloseValues (I'm not sure why) # Have to do this because if I just make dates = self.allDates & closeValues = self.allCloseValues, then deleting from dates & closeValues also deletes it from self.allDates & self.allCloseValues (I'm not sure why)
dates = [] dates = []
@ -251,9 +279,8 @@ class Stock:
closeValues.append(self.allCloseValues[i]) closeValues.append(self.allCloseValues[i])
firstDate = datetime.datetime.now().date() - datetime.timedelta( firstDate = datetime.datetime.now().date() - datetime.timedelta(
days=self.timeFrame[0]*365) - datetime.timedelta(days=self.timeFrame[1]*30) days=self.timeFrame*365)
print('\n', self.timeFrame[0], ' years and ', print('\n', self.timeFrame, ' years ago: ', firstDate, sep='')
self.timeFrame[1], ' months ago: ', firstDate, sep='')
closestDate = Functions.getNearest(dates, firstDate) closestDate = Functions.getNearest(dates, firstDate)
if closestDate != firstDate: if closestDate != firstDate:
print('Closest date available for', self.name, ':', closestDate) print('Closest date available for', self.name, ':', closestDate)
@ -278,21 +305,199 @@ class Stock:
return datesAndCloseList2 return datesAndCloseList2
def unadjustedReturn(self): def calcAverageAnnualReturn(self): # pylint: disable=E0202
unadjustedReturn = (float(self.closeValues[len( # averageAnnualReturn = (float(self.closeValues[len(self.closeValues)-1]/self.closeValues[0])**(1/(self.timeFrame)))-1
self.closeValues)-1]/self.closeValues[0])**(1/(self.timeFrame[0]+(self.timeFrame[1])*.1)))-1 # averageAnnualReturn = averageAnnualReturn * 100
print('Annual unadjusted return:', unadjustedReturn) averageAnnualReturn = sum(self.annualReturn)/self.timeFrame
return unadjustedReturn print('Average annual return:', averageAnnualReturn)
return averageAnnualReturn
def beta(self, benchmarkMatchDatesAndCloseValues): def calcAnnualReturn(self):
beta = numpy.corrcoef(self.closeValuesMatchBenchmark, annualReturn = []
benchmarkMatchDatesAndCloseValues[1])[0, 1]
# Calculate annual return in order from oldest to newest
annualReturn = []
for i in range(0, self.timeFrame, 1):
firstDate = datetime.datetime.now().date() - datetime.timedelta(
days=(self.timeFrame-i)*365)
secondDate = datetime.datetime.now().date() - datetime.timedelta(
days=(self.timeFrame-i-1)*365)
# Find closest dates to firstDate and lastDate
firstDate = Functions.getNearest(self.dates, firstDate)
secondDate = Functions.getNearest(self.dates, secondDate)
if firstDate == secondDate:
print('Closest date is', firstDate,
'which is after the given time frame.')
return 'Not available'
# Get corresponding close values and calculate annual return
for i in range(0, len(self.dates), 1):
if self.dates[i] == firstDate:
firstClose = self.closeValues[i]
elif self.dates[i] == secondDate:
secondClose = self.closeValues[i]
break
annualReturnTemp = (secondClose/firstClose)-1
annualReturnTemp = annualReturnTemp * 100
annualReturn.append(annualReturnTemp)
print('Annual return over the past',
self.timeFrame, 'years:', annualReturn)
return annualReturn
def calcCorrelation(self, closeList):
correlation = np.corrcoef(
self.closeValuesMatchBenchmark, closeList)[0, 1]
print('Correlation with benchmark:', correlation)
return correlation
def calcStandardDeviation(self):
numberOfValues = self.timeFrame
mean = self.averageAnnualReturn
standardDeviation = (
(sum((self.annualReturn[x]-mean)**2 for x in range(0, numberOfValues, 1)))/(numberOfValues-1))**(1/2)
print('Standard Deviation:', standardDeviation)
return standardDeviation
def calcDownsideDeviation(self):
numberOfValues = self.timeFrame
targetReturn = self.averageAnnualReturn
downsideDeviation = (
(sum(min(0, (self.annualReturn[x]-targetReturn))**2 for x in range(0, numberOfValues, 1)))/(numberOfValues-1))**(1/2)
print('Downside Deviation:', downsideDeviation)
return downsideDeviation
def calcKurtosis(self):
numberOfValues = self.timeFrame
mean = self.averageAnnualReturn
kurtosis = (sum((self.annualReturn[x]-mean)**4 for x in range(
0, numberOfValues, 1)))/((numberOfValues-1)*(self.standardDeviation ** 4))
print('Kurtosis:', kurtosis)
return kurtosis
def calcSkewness(self):
numberOfValues = self.timeFrame
mean = self.averageAnnualReturn
skewness = (sum((self.annualReturn[x]-mean)**3 for x in range(
0, numberOfValues, 1)))/((numberOfValues-1)*(self.standardDeviation ** 3))
print('Skewness:', skewness)
return skewness
def calcBeta(self):
beta = self.correlation * \
(self.standardDeviation/Stock.benchmarkStandardDeviation)
print('Beta:', beta) print('Beta:', beta)
return beta return beta
def calcAlpha(self):
alpha = self.averageAnnualReturn - \
(Stock.riskFreeRate+((Stock.benchmarkAverageAnnualReturn -
Stock.riskFreeRate) * self.beta))
print('Alpha:', alpha)
return alpha
def calcSharpe(self):
sharpe = (self.averageAnnualReturn - Stock.riskFreeRate) / \
self.standardDeviation
print('Sharpe Ratio:', sharpe)
return sharpe
def calcSortino(self):
sortino = (self.averageAnnualReturn - self.riskFreeRate) / \
self.downsideDeviation
print('Sortino Ratio:', sortino)
return sortino
def calcTreynor(self):
treynor = (self.averageAnnualReturn - Stock.riskFreeRate)/self.beta
print('Treynor Ratio:', treynor)
return treynor
def calcLinearRegression(self):
dates = self.dates
y = self.closeValues
# First change dates to integers (days from first date)
x = datesToDays(dates)
x = np.array(x)
y = np.array(y)
# Estimate coefficients
# number of observations/points
n = np.size(x)
# mean of x and y vector
m_x, m_y = np.mean(x), np.mean(y)
# calculating cross-deviation and deviation about x
SS_xy = np.sum(y*x) - n*m_y*m_x
SS_xx = np.sum(x*x) - n*m_x*m_x
# calculating regression coefficients
b_1 = SS_xy / SS_xx
b_0 = m_y - b_1*m_x
b = [b_0, b_1]
formula = ''.join(
('y = ', str(round(float(b[0]), 2)), 'x + ', str(round(float(b[1]), 2))))
print('Linear regression formula:', formula)
# Stock.plot_regression_line(self, x, y, b)
regression = []
regression.append(b[0])
regression.append(b[1])
return regression
def plot_regression_line(self, x, y, b):
# plotting the actual points as scatter plot
plt.scatter(self.dates, y, color="m",
marker="o", s=30)
# predicted response vector
y_pred = b[0] + b[1]*x
# plotting the regression line
plt.plot(self.dates, y_pred, color="g")
# putting labels
plt.title(self.name)
plt.xlabel('Dates')
plt.ylabel('Close Values')
# function to show plot
plt.show(block=False)
for i in range(3, 0, -1):
if i == 1:
sys.stdout.write('Keeping plot open for ' +
str(i) + ' second \r')
else:
sys.stdout.write('Keeping plot open for ' +
str(i) + ' seconds \r')
plt.pause(1)
sys.stdout.flush()
plt.close()
def datesToDays(dates):
days = []
firstDate = dates[0]
days.append(0)
for i in range(1, len(dates), 1):
# Calculate days from first date to current date
daysDiff = (dates[i]-firstDate).days
days.append(daysDiff)
return days
def isConnected(): def isConnected():
import socket # To check internet connection import socket # To check internet connection
print('Checking internet connection')
try: try:
# connect to the host -- tells us if the host is actually reachable # connect to the host -- tells us if the host is actually reachable
socket.create_connection(("www.andrewkdinh.com", 80)) socket.create_connection(("www.andrewkdinh.com", 80))
@ -327,17 +532,31 @@ def benchmarkInit():
while benchmarkTicker == '': while benchmarkTicker == '':
benchmarks = ['S&P500', 'DJIA', 'Russell 3000', 'MSCI EAFE'] benchmarks = ['S&P500', 'DJIA', 'Russell 3000', 'MSCI EAFE']
benchmarksTicker = ['SPY', 'DJIA', 'VTHR', 'EFT'] benchmarksTicker = ['SPY', 'DJIA', 'VTHR', 'EFT']
print('\nList of benchmarks:', benchmarks) print('\nList of benchmarks:')
# benchmark = str(input('Benchmark to compare to: '))
benchmark = 'S&P500'
for i in range(0, len(benchmarks), 1): for i in range(0, len(benchmarks), 1):
if benchmark == benchmarks[i]: print(str(i+1) + '. ' +
benchmarkTicker = benchmarksTicker[i] benchmarks[i] + ' (' + benchmarksTicker[i] + ')')
benchmark = str(input('Please choose a benchmark from the list: '))
# benchmark = 'SPY' # TESTING
if Functions.stringIsInt(benchmark) == True:
if int(benchmark) <= len(benchmarks):
benchmarkInt = int(benchmark)
benchmark = benchmarks[benchmarkInt-1]
benchmarkTicker = benchmarksTicker[benchmarkInt-1]
else:
for i in range(0, len(benchmarks), 1):
if benchmark == benchmarks[i]:
benchmarkTicker = benchmarksTicker[i]
break
if benchmark == benchmarksTicker[i] or benchmark == benchmarksTicker[i].lower():
benchmark = benchmarks[i]
benchmarkTicker = benchmarksTicker[i]
break
if benchmarkTicker == '': if benchmarkTicker == '':
print('Benchmark not found. Please type in a benchmark from the list') print('Benchmark not found. Please use a benchmark from the list')
print(benchmark, ' (', benchmarkTicker, ')', sep='') print(benchmark, ' (', benchmarkTicker, ')', sep='')
@ -350,18 +569,31 @@ def benchmarkInit():
def stocksInit(): def stocksInit():
listOfStocks = [] listOfStocks = []
# numberOfStocks = int(input('\nHow many stocks/mutual funds/ETFs would you like to analyze? ')) isInteger = False
numberOfStocks = 1 while isInteger == False:
temp = input('\nNumber of stocks to analyze (2 minimum): ')
isInteger = Functions.stringIsInt(temp)
if isInteger == True:
numberOfStocks = int(temp)
else:
print('Please type an integer')
print('\nHow many stocks/mutual funds/ETFs would you like to analyze? ', numberOfStocks) # numberOfStocks = 5 # TESTING
# print('How many stocks would you like to analyze? ', numberOfStocks)
print('\nThis program can analyze stocks (GOOGL), mutual funds (VFINX), and ETFs (SPY)')
print('For simplicity, all of them will be referred to as "stock"\n')
# listOfGenericStocks = ['googl', 'aapl', 'vfinx', 'tsla', 'vthr']
for i in range(0, numberOfStocks, 1): for i in range(0, numberOfStocks, 1):
print('Stock', i + 1, ': ', end='') print('Stock', i + 1, end=' ')
#stockName = str(input()) stockName = str(input('ticker: '))
stockName = 'FBGRX' # stockName = listOfGenericStocks[i]
print(stockName) # print(':', stockName)
stockName = stockName.upper()
listOfStocks.append(stockName) listOfStocks.append(stockName)
listOfStocks[i] = Stock() listOfStocks[i] = Stock()
listOfStocks[i].setName(stockName) listOfStocks[i].setName(stockName)
@ -370,49 +602,94 @@ def stocksInit():
def timeFrameInit(): def timeFrameInit():
print('\nPlease enter the time frame in years and months (30 days)') isInteger = False
print("Years: ", end='') while isInteger == False:
#years = int(input()) print(
years = 5 '\nPlease enter the time frame in years (10 years or less recommended):', end='')
print(years) temp = input(' ')
print("Months: ", end='') isInteger = Functions.stringIsInt(temp)
#months = int(input()) if isInteger == True:
months = 0 years = int(temp)
print(months) else:
print('Please type an integer')
timeFrame = [] # years = 5 # TESTING
timeFrame.append(years) # print('Years:', years)
timeFrame.append(months)
timeFrame = years
return timeFrame return timeFrame
def dataMain(listOfStocks): def dataMain(listOfStocks):
print('\nGathering dates and close values') print('\nGathering dates and close values')
for i in range(0, len(listOfStocks), 1): i = 0
while i < len(listOfStocks):
datesAndCloseList = Stock.datesAndClose(listOfStocks[i]) datesAndCloseList = Stock.datesAndClose(listOfStocks[i])
listOfStocks[i].allDates = datesAndCloseList[0] if datesAndCloseList == 'Not available':
listOfStocks[i].allCloseValues = datesAndCloseList[1] del listOfStocks[i]
if len(listOfStocks) == 0:
print('No stocks to analyze. Ending program')
exit()
else:
listOfStocks[i].allDates = datesAndCloseList[0]
listOfStocks[i].allCloseValues = datesAndCloseList[1]
# Clip list to fit time frame # Clip list to fit time frame
datesAndCloseList2 = Stock.datesAndClose2(listOfStocks[i]) datesAndCloseList2 = Stock.datesAndCloseFitTimeFrame(
listOfStocks[i].dates = datesAndCloseList2[0] listOfStocks[i])
listOfStocks[i].closeValues = datesAndCloseList2[1] listOfStocks[i].dates = datesAndCloseList2[0]
listOfStocks[i].closeValues = datesAndCloseList2[1]
i += 1
def riskFreeRate():
print('Quandl')
url = ''.join(
('https://www.quandl.com/api/v3/datasets/USTREASURY/LONGTERMRATES.json?api_key=', apiQuandl))
# https://www.quandl.com/api/v3/datasets/USTREASURY/LONGTERMRATES.json?api_key=KUh3U3hxke9tCimjhWEF
print("\nSending request to:", url)
f = requests.get(url)
Functions.fromCache(f)
json_data = f.text
loaded_json = json.loads(json_data)
riskFreeRate = (loaded_json['dataset']['data'][0][1])/100
riskFreeRate = riskFreeRate * 100
riskFreeRate = round(riskFreeRate, 2)
print('Risk-free rate:', riskFreeRate, end='\n\n')
if f.status_code == 404:
print("Quandl not available")
print('Returning 2.50 as risk-free rate', end='\n\n')
# return 0.0250
return 2.50
return riskFreeRate
def returnMain(benchmark, listOfStocks): def returnMain(benchmark, listOfStocks):
print('\nCalculating unadjusted return, Sharpe ratio, Sortino ratio, and Treynor ratio\n') print('\nCalculating unadjusted return, Sharpe ratio, Sortino ratio, and Treynor ratio\n')
print(benchmark.name) print('Getting risk-free rate from current 10-year treasury bill rates', end='\n\n')
benchmark.unadjustedReturn = Stock.unadjustedReturn(benchmark) Stock.riskFreeRate = riskFreeRate()
print(benchmark.name, end='\n\n')
benchmark.annualReturn = Stock.calcAnnualReturn(benchmark)
if benchmark.annualReturn == 'Not available':
print('Please use a lower time frame\nEnding program')
exit()
benchmark.averageAnnualReturn = Stock.calcAverageAnnualReturn(benchmark)
benchmark.standardDeviation = Stock.calcStandardDeviation(benchmark)
# Make benchmark data global # Make benchmark data global
# Maybe remove this later
Stock.benchmarkDates = benchmark.dates Stock.benchmarkDates = benchmark.dates
Stock.benchmarkCloseValues = benchmark.closeValues Stock.benchmarkCloseValues = benchmark.closeValues
Stock.benchmarkUnadjustedReturn = benchmark.unadjustedReturn Stock.benchmarkAverageAnnualReturn = benchmark.averageAnnualReturn
Stock.benchmarkStandardDeviation = benchmark.standardDeviation
for i in range(0, len(listOfStocks), 1): i = 0
print(listOfStocks[i].name) while i < len(listOfStocks):
print('\n' + listOfStocks[i].name, end='\n\n')
# Make sure each date has a value for both the benchmark and the stock # Make sure each date has a value for both the benchmark and the stock
list1 = [] list1 = []
@ -426,10 +703,241 @@ def returnMain(benchmark, listOfStocks):
listOfStocks[i].closeValuesMatchBenchmark = temp[0][1] listOfStocks[i].closeValuesMatchBenchmark = temp[0][1]
benchmarkMatchDatesAndCloseValues = temp[1] benchmarkMatchDatesAndCloseValues = temp[1]
listOfStocks[i].unadjustedReturn = Stock.unadjustedReturn( # Calculate everything for each stock
listOfStocks[i]) listOfStocks[i].annualReturn = Stock.calcAnnualReturn(listOfStocks[i])
listOfStocks[i].beta = Stock.beta( if listOfStocks[i].annualReturn == 'Not available':
listOfStocks[i], benchmarkMatchDatesAndCloseValues) print('Removing', listOfStocks[i].name, 'from list of stocks')
del listOfStocks[i]
if len(listOfStocks) == 0:
print('No stocks to analyze. Ending program')
exit()
else:
listOfStocks[i].averageAnnualReturn = Stock.calcAverageAnnualReturn(
listOfStocks[i])
listOfStocks[i].correlation = Stock.calcCorrelation(
listOfStocks[i], benchmarkMatchDatesAndCloseValues[1])
listOfStocks[i].standardDeviation = Stock.calcStandardDeviation(
listOfStocks[i])
listOfStocks[i].downsideDeviation = Stock.calcDownsideDeviation(
listOfStocks[i])
listOfStocks[i].kurtosis = Stock.calcKurtosis(
listOfStocks[i])
listOfStocks[i].skewness = Stock.calcSkewness(
listOfStocks[i])
listOfStocks[i].beta = Stock.calcBeta(listOfStocks[i])
listOfStocks[i].alpha = Stock.calcAlpha(listOfStocks[i])
listOfStocks[i].sharpe = Stock.calcSharpe(listOfStocks[i])
listOfStocks[i].sortino = Stock.calcSortino(listOfStocks[i])
listOfStocks[i].treynor = Stock.calcTreynor(listOfStocks[i])
listOfStocks[i].linearRegression = Stock.calcLinearRegression(
listOfStocks[i])
i += 1
print('\nNumber of stocks from original list that fit time frame:',
len(listOfStocks))
def indicatorInit():
# Runs correlation or regression study
indicatorFound = False
listOfIndicators = ['Expense Ratio',
'Market Capitalization', 'Turnover', 'Persistence']
print('\n', end='')
while indicatorFound == False:
print('List of indicators:')
for i in range(0, len(listOfIndicators), 1):
print(str(i + 1) + '. ' + listOfIndicators[i])
indicator = str(input('Choose an indicator from the list: '))
# indicator = 'expense ratio' # TESTING
if Functions.stringIsInt(indicator) == True:
if int(indicator) <= 4:
indicator = listOfIndicators[int(indicator)-1]
indicatorFound = True
else:
indicatorFormats = [
indicator.upper(), indicator.lower(), indicator.title()]
for i in range(0, len(indicatorFormats), 1):
for j in range(0, len(listOfIndicators), 1):
if listOfIndicators[j] == indicatorFormats[i]:
indicator = listOfIndicators[j]
indicatorFound = True
break
if indicatorFound == False:
print('Please choose an indicator from the list')
return indicator
def calcIndicatorCorrelation(listOfIndicatorValues, listOfReturns):
correlationList = []
for i in range(0, len(listOfReturns), 1):
correlation = np.corrcoef(
listOfIndicatorValues, listOfReturns[i])[0, 1]
correlationList.append(correlation)
return correlationList
def calcIndicatorRegression(listOfIndicatorValues, listOfReturns):
regressionList = []
x = np.array(listOfIndicatorValues)
for i in range(0, len(listOfReturns), 1):
y = np.array(listOfReturns[i])
# Estimate coefficients
# number of observations/points
n = np.size(x)
# mean of x and y vector
m_x, m_y = np.mean(x), np.mean(y)
# calculating cross-deviation and deviation about x
SS_xy = np.sum(y*x) - n*m_y*m_x
SS_xx = np.sum(x*x) - n*m_x*m_x
# calculating regression coefficients
b_1 = SS_xy / SS_xx
b_0 = m_y - b_1*m_x
b = [b_0, b_1]
regression = []
regression.append(b[0])
regression.append(b[1])
regressionList.append(regression)
# plot_regression_line(x, y, b, i)
return regressionList
def plot_regression_line(x, y, b, i):
# plotting the actual points as scatter plot
plt.scatter(x, y, color="m",
marker="o", s=30)
# predicted response vector
y_pred = b[0] + b[1]*x
# plotting the regression line
plt.plot(x, y_pred, color="g")
# putting labels
listOfReturnStrings = ['Average Annual Return',
'Sharpe Ratio', 'Sortino Ratio', 'Treynor Ratio', 'Alpha']
plt.title(Stock.indicator + ' and ' + listOfReturnStrings[i])
if Stock.indicator == 'Expense Ratio':
plt.xlabel(Stock.indicator + ' (%)')
else:
plt.xlabel(Stock.indicator)
if i == 0:
plt.ylabel(listOfReturnStrings[i] + ' (%)')
else:
plt.ylabel(listOfReturnStrings[i])
# function to show plot
plt.show(block=False)
for i in range(2, 0, -1):
if i == 1:
sys.stdout.write('Keeping plot open for ' +
str(i) + ' second \r')
else:
sys.stdout.write('Keeping plot open for ' +
str(i) + ' seconds \r')
plt.pause(1)
sys.stdout.flush()
sys.stdout.write(
' \r')
sys.stdout.flush()
plt.close()
def indicatorMain(listOfStocks):
Stock.indicator = indicatorInit()
print(Stock.indicator, end='\n\n')
# indicatorValuesGenericExpenseRatio = [2.5, 4.3, 3.1, 2.6, 4.2] # TESTING
listOfStocksIndicatorValues = []
for i in range(0, len(listOfStocks), 1):
indicatorValueFound = False
while indicatorValueFound == False:
if Stock.indicator == 'Expense Ratio':
indicatorValue = str(
input(Stock.indicator + ' for ' + listOfStocks[i].name + ' (%): '))
elif Stock.indicator == 'Persistence':
indicatorValue = str(
input(Stock.indicator + ' for ' + listOfStocks[i].name + ' (years): '))
elif Stock.indicator == 'Turnover':
indicatorValue = str(input(
Stock.indicator + ' for ' + listOfStocks[i].name + ' in the last ' + str(Stock.timeFrame) + ' years: '))
elif Stock.indicator == 'Market Capitalization':
indicatorValue = str(
input(Stock.indicator + ' of ' + listOfStocks[i].name + ': '))
else:
print('Something is wrong. Indicator was not found. Ending program.')
exit()
if Functions.strintIsFloat(indicatorValue) == True:
listOfStocks[i].indicatorValue = float(indicatorValue)
indicatorValueFound = True
else:
print('Please enter a number')
# listOfStocks[i].indicatorValue = indicatorValuesGenericExpenseRatio[i] # TESTING
listOfStocksIndicatorValues.append(listOfStocks[i].indicatorValue)
listOfReturns = [] # A list that matches the above list with return values [[averageAnnualReturn1, aAR2, aAR3], [sharpe1, sharpe2, sharpe3], etc.]
tempListOfReturns = []
for i in range(0, len(listOfStocks), 1):
tempListOfReturns.append(listOfStocks[i].averageAnnualReturn)
listOfReturns.append(tempListOfReturns)
tempListOfReturns = []
for i in range(0, len(listOfStocks), 1):
tempListOfReturns.append(listOfStocks[i].sharpe)
listOfReturns.append(tempListOfReturns)
tempListOfReturns = []
for i in range(0, len(listOfStocks), 1):
tempListOfReturns.append(listOfStocks[i].sortino)
listOfReturns.append(tempListOfReturns)
tempListOfReturns = []
for i in range(0, len(listOfStocks), 1):
tempListOfReturns.append(listOfStocks[i].treynor)
listOfReturns.append(tempListOfReturns)
tempListOfReturns = []
for i in range(0, len(listOfStocks), 1):
tempListOfReturns.append(listOfStocks[i].alpha)
listOfReturns.append(tempListOfReturns)
# Create list of each indicator (e.g. expense ratio)
listOfIndicatorValues = []
for i in range(0, len(listOfStocks), 1):
listOfIndicatorValues.append(listOfStocks[i].indicatorValue)
Stock.indicatorCorrelation = calcIndicatorCorrelation(
listOfIndicatorValues, listOfReturns)
listOfReturnStrings = ['Average Annual Return',
'Sharpe Ratio', 'Sortino Ratio', 'Treynor Ratio', 'Alpha']
print('\n', end='')
for i in range(0, len(Stock.indicatorCorrelation), 1):
print('Correlation with ' + Stock.indicator.lower() + ' and ' +
listOfReturnStrings[i].lower() + ': ' + str(Stock.indicatorCorrelation[i]))
Stock.indicatorRegression = calcIndicatorRegression(
listOfIndicatorValues, listOfReturns)
print('\n', end='')
for i in range(0, len(Stock.indicatorCorrelation), 1):
formula = ''.join(
('y = ', str(round(float(Stock.indicatorRegression[i][0]), 2)), 'x + ', str(round(float(Stock.indicatorRegression[i][1]), 2))))
print('Linear regression equation for ' + Stock.indicator.lower() + ' and ' +
listOfReturnStrings[i].lower() + ': ' + formula)
def main(): def main():
@ -463,110 +971,11 @@ def main():
# Calculate return for benchmark and stock(s) # Calculate return for benchmark and stock(s)
returnMain(benchmark, listOfStocks) returnMain(benchmark, listOfStocks)
# Choose indicator and calculate correlation with indicator
indicatorMain(listOfStocks)
exit()
if __name__ == "__main__": if __name__ == "__main__":
main() main()
'''
from StockData import StockData
from StockReturn import Return
listOfStocksData = []
listOfStocksReturn = []
# numberOfStocks = int(input("How many stocks or mutual funds would you like to analyze? ")) # CHANGE BACK LATER
numberOfStocks = 1
for i in range(0, numberOfStocks, 1):
print("Stock", i+1, ": ", end='')
stockName = str(input())
listOfStocksData.append(i)
listOfStocksData[i] = StockData()
listOfStocksData[i].setName(stockName)
# print(listOfStocksData[i].name)
# listOfStocksReturn.append(i)
# listOfStocksReturn[i] = StockReturn()
# Decide on a benchmark
benchmarkTicker = ''
while benchmarkTicker == '':
listOfBenchmarks = ['S&P500', 'DJIA', 'Russell 3000', 'MSCI EAFE']
listOfBenchmarksTicker = ['SPY', 'DJIA', 'VTHR', 'EFT']
print('\nList of benchmarks:', listOfBenchmarks)
# benchmark = str(input('Benchmark to compare to: '))
benchmark = 'S&P500'
for i in range(0,len(listOfBenchmarks), 1):
if benchmark == listOfBenchmarks[i]:
benchmarkTicker = listOfBenchmarksTicker[i]
i = len(listOfBenchmarks)
if benchmarkTicker == '':
print('Benchmark not found. Please type in a benchmark from the list')
print('\n', benchmark, ' (', benchmarkTicker, ')', sep='')
benchmarkName = str(benchmark)
benchmark = StockData()
benchmark.setName(benchmarkName)
StockData.main(benchmark)
benchmarkReturn = Return()
Return.mainBenchmark(benchmarkReturn, benchmark)
timeFrame = Return.returnTimeFrame(benchmarkReturn)
print('Time Frame [years, months]:', timeFrame)
sumOfListLengths = 0
for i in range(0, numberOfStocks, 1):
print('\n', listOfStocksData[i].name, sep='')
StockData.main(listOfStocksData[i])
# Count how many stocks are available
sumOfListLengths = sumOfListLengths + len(StockData.returnAllLists(listOfStocksData[i]))
if sumOfListLengths == 0:
print("No sources have data for given stocks")
exit()
# Find return over time using either Jensen's Alpha, Sharpe Ratio, Sortino Ratio, or Treynor Ratio
for i in range(0, numberOfStocks, 1):
print('\n', listOfStocksData[i].name, sep='')
# StockReturn.main(listOfStocksReturn[i])
# Runs correlation or regression study
# print(listOfStocksData[0].name, listOfStocksData[0].absFirstLastDates, listOfStocksData[0].finalDatesAndClose)
indicatorFound = False
while indicatorFound == False:
print("1. Expense Ratio\n2. Asset Size\n3. Turnover\n4. Persistence\nWhich indicator would you like to look at? ", end='')
# indicator = str(input()) # CHANGE BACK TO THIS LATER
indicator = 'Expense Ratio'
print(indicator, end='')
indicatorFound = True
print('\n', end='')
if indicator == 'Expense Ratio' or indicator == '1' or indicator == 'expense ratio':
# from ExpenseRatio import ExpenseRatio
print('\nExpense Ratio')
elif indicator == 'Asset Size' or indicator == '2' or indicator == 'asset size':
print('\nAsset Size')
elif indicator == 'Turnover' or indicator == '3' or indicator == 'turnover':
print('\nTurnover')
elif indicator == 'Persistence' or indicator == '4' or indicator == 'persistence':
print('\nPersistence')
else:
indicatorFound = False
print('Invalid input, please enter indicator again')
stockName = 'IWV'
stock1 = Stock(stockName)
print("Finding available dates and close values for", stock1.name)
StockData.main(stock1)
'''

51
output.bin Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script src="/cdn-cgi/apps/head/GA7wuz-FE88SDVynGgn9Aq5W6rI.js"></script><link rel="apple-touch-icon" sizes="57x57" href="/images/logo/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/images/logo/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/images/logo/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/images/logo/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/images/logo/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/images/logo/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/images/logo/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/logo/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/images/logo/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/logo/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/images/logo/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<title>Andrew Dinh</title>
<meta name="description" content="Andrew Dinh is a young professional delving into the world of computer science to expand financial literacy." />
<meta name="keywords" content="Andrew Dinh, Andrew K Dinh, Gilroy, GECA, Gavilan College, Dr. TJ Owens Gilroy Early College Academy, computer science" />
<meta property="og:title" content="Andrew Dinh" />
<meta property="og:description" content="A young professional delving into the world of computer science to expand financial literacy" />
<meta property="og:image" content="/images/profile.jpg" />
<meta name="apple-mobile-web-app-capable" content="yes">
<script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(chref=d.href).replace(e.href,"").indexOf("#")&&(!/^[a-z\+\.\-]+:/i.test(chref)||chref.indexOf(e.protocol+"//"+e.host)===0)&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone");</script>
<script> function myFunction() {var x = document.getElementById("myTopnav");if (x.className === "topnav") {x.className += " responsive";} else {x.className = "topnav";}}</script>
<script>window.onload=function(){function a(a,b){var c=/^(?:file):/,d=new XMLHttpRequest,e=0;d.onreadystatechange=function(){4==d.readyState&&(e=d.status),c.test(location.href)&&d.responseText&&(e=200),4==d.readyState&&200==e&&(a.outerHTML=d.responseText)};try{d.open("GET",b,!0),d.send()}catch(f){}}var b,c=document.getElementsByTagName("*");for(b in c)c[b].hasAttribute&&c[b].hasAttribute("data-include")&&a(c[b],c[b].getAttribute("data-include"))};</script>
<link rel="stylesheet preload" title="classic" href="/css/general.css" media="screen" />
</head>
<body>
<div data-include="/html/menu.html"></div>
<main>
</main>
</body>
</html>

View File

@ -1,2 +1,3 @@
requests~=2.21.0 requests~=2.21.0
numpy~=1.15.4 numpy~=1.15.4
requests-cache~=0.4.13 # NOT REQUIRED

0
test.html Normal file
View File