Merge pull request #7 from andrewkdinh/personal-pc

Personal pc
This commit is contained in:
Andrew Dinh 2019-01-22 18:56:17 +00:00 committed by GitHub
commit 7ab39a5cec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 282 additions and 73 deletions

3
.gitignore vendored
View File

@ -3,3 +3,6 @@ __pycache__/
*.pyc *.pyc
quickstart.py quickstart.py
creds.json creds.json
test/
.vscode/
listGoogle.py

View File

@ -5,35 +5,24 @@
''' '''
Asks user for expense ratio of stock (I don't think there's an API for expense ratios) Asks user for expense ratio of stock (I don't think there's an API for expense ratios)
Runs corrrelation study (I'm not sure if I want another class for this or not) Runs corrrelation study (I'm not sure if I want another class for this or not)
''' '''
import numpy import numpy
#import urllib2, re #import urllib2, re
from urllib.request import urlopen from urllib.request import urlopen
import re import re
class ExpenseRatio:
def __init__(self):
def main(): # For testing purposes def main(): # For testing purposes
''' '''
a = [1,2,3] a = [1,2,3]
b = [2,4,6] b = [2,4,6]
c = numpy.corrcoef(a, b)[0, 1] c = numpy.corrcoef(a, b)[0, 1]
print(c) print(c)
''' '''
#http://finance.yahoo.com/q/pr?s=spy+profile
stockSymbols = [ "VDIGX", "VFIAX" ]
expenses = [ [ "Fund", "Most Recent Expense Ratio" ] ]
for stockSymbol in stockSymbols:
page = urlopen("http://finance.yahoo.com/q/pr?s=" + stockSymbol + "+profile" )
data = str(page.read())
row = re.findall("Annual Report Expense Ratio.*?</tr>", data)
if len(row) > 0:
ER = re.findall("<td.*?>(\d+\.\d+).*?</td>", row[0] )[0]
expenses.append( [ stockSymbol, ER ] )
else:
print(stockSymbol, "does not appear to be a fund with an expense ratio")
print("\n".join( i[0] + "," + i[1] for i in expenses))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

24
Functions.py Normal file
View File

@ -0,0 +1,24 @@
# Python file for general functions
class Functions:
def getNearest(items, pivot):
return min(items, key=lambda x: abs(x - pivot))
def stringToDate(date):
from datetime import datetime
#datetime_object = datetime.strptime('Jun 1 2005 1:33PM', '%b %d %Y %I:%M%p')
datetime_object = datetime.strptime(date, '%Y-%m-%d').date()
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 main():
exit()
if __name__ == "__main__":
main()

View File

@ -4,9 +4,11 @@ A project to determine indicators of overperforming mutual funds.
This project is written in Python and will examine market capitalization, persistence, turnover, and expense ratios. This project is written in Python and will examine market capitalization, persistence, turnover, and expense ratios.
### Prerequisites ### Prerequisites
```sh
$ pip install requests `$ pip install -r requirements.txt`
$ pip install numpy
``` or
`$ pip install requests`
Created by Andrew Dinh from Dr. TJ Owens Gilroy Early College Academy Created by Andrew Dinh from Dr. TJ Owens Gilroy Early College Academy

View File

@ -29,20 +29,19 @@ Daily Requests = 20,000
Symbol Requests = 500 Symbol Requests = 500
''' '''
import requests, json, socket import requests, json
import importlib.util, sys # To check whether a package is installed
from datetime import datetime from datetime import datetime
class Stock: class StockData:
def __init__(self, newName = '', newFirstLastDates = [], newAbsFirstLastDates = [], newFinalDatesAndClose = [], newAllLists = []): def __init__(self, newName = '', newAbsFirstLastDates = [], newFinalDatesAndClose = [], newFinalDatesAndClose2 = [],newAllLists = []):
self.name = newName # Name of stock self.name = newName # Name of stock
self.firstLastDates = newFirstLastDates # Dates that at least 2 sources have (or should it be all?) - Maybe let user decide
self.absFirstLastDates = newAbsFirstLastDates # Absolute first and last dates from all sources self.absFirstLastDates = newAbsFirstLastDates # Absolute first and last dates from all sources
self.finalDatesAndClose = newFinalDatesAndClose # All available dates self.finalDatesAndClose = newFinalDatesAndClose # All available dates with corresponding close values
self.finalDatesAndClose2 = newFinalDatesAndClose2 # After some consideration, I decided to keep what I had already done here and make a new list that's the same except dates are in datetime format
self.allLists = newAllLists self.allLists = newAllLists
''' '''
Format: Format:
# List from each source containing: [firstDate, lastDate, allDates, values, timeFrame] # List from each source containing: [firstDate, lastDate, allDates, values, timeFrame]
# firstDate & lastDate = '2018-12-18' (year-month-date) # firstDate & lastDate = '2018-12-18' (year-month-date)
allDates = ['2018-12-17', '2018-12-14'] (year-month-date) allDates = ['2018-12-17', '2018-12-14'] (year-month-date)
@ -59,9 +58,18 @@ class Stock:
def setName(self, newName): def setName(self, newName):
self.name = newName self.name = newName
def returnName(self):
def getAllLists(self): return self.name
def returnAllLists(self):
return self.allLists return self.allLists
def returnAbsFirstLastDates(self):
return self.absFirstLastDates
def returnAllLists(self):
return self.allLists
def returnFinalDatesAndClose(self):
return self.finalDatesAndClose
def returnFinalDatesAndClose2(self):
return self.finalDatesAndClose2
def getIEX(self): def getIEX(self):
url = ''.join(('https://api.iextrading.com/1.0/stock/', self.name, '/chart/5y')) url = ''.join(('https://api.iextrading.com/1.0/stock/', self.name, '/chart/5y'))
@ -133,9 +141,17 @@ class Stock:
def getAV(self): def getAV(self):
listAV = [] listAV = []
url = ''.join(('https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=', self.name, '&apikey=', apiAV)) #url = ''.join(('https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=', self.name, '&apikey=', apiAV))
# https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=MSFT&apikey=demo # https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=MSFT&apikey=demo
#url = ''.join(('https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=', self.name, '&outputsize=full&apikey=', apiAV))
# https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo
url = ''.join(('https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=', self.name, '&outputsize=full&apikey=', apiAV))
# 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)
json_data = f.text json_data = f.text
loaded_json = json.loads(json_data) loaded_json = json.loads(json_data)
@ -148,9 +164,9 @@ class Stock:
return 'Not available' return 'Not available'
#print(loaded_json['Monthly Time Series']) #print(loaded_json['Monthly Time Series'])
monthlyTimeSeries = loaded_json['Monthly Time Series'] dailyTimeSeries = loaded_json['Time Series (Daily)']
#print(monthlyTimeSeries) #print(monthlyTimeSeries)
listOfDates = list(monthlyTimeSeries) listOfDates = list(dailyTimeSeries)
#print(listOfDates) #print(listOfDates)
firstDate = listOfDates[-1] firstDate = listOfDates[-1]
@ -171,8 +187,9 @@ class Stock:
values = [] values = []
for i in range(0, len(listOfDates), 1): for i in range(0, len(listOfDates), 1):
temp = listOfDates[i] temp = listOfDates[i]
loaded_json2 = monthlyTimeSeries[temp] loaded_json2 = dailyTimeSeries[temp]
value = loaded_json2['4. close'] #value = loaded_json2['4. close']
value = loaded_json2['5. adjusted close']
values.append(value) values.append(value)
listAV.append(values) listAV.append(values)
#print(listOfDates[0]) #print(listOfDates[0])
@ -424,13 +441,31 @@ class Stock:
# Want lists from most recent to oldest, comment this out if you don't want that # Want lists from most recent to oldest, comment this out if you don't want that
finalDates = list(reversed(finalDates)) finalDates = list(reversed(finalDates))
finalClose = list(reversed(finalClose)) finalClose = list(reversed(finalClose))
finalDatesAndClose.append(finalDates) finalDatesAndClose.append(finalDates)
finalDatesAndClose.append(finalClose) finalDatesAndClose.append(finalClose)
return finalDatesAndClose return finalDatesAndClose
def datetimeDates(self):
finalDatesAndClose2 = []
finalDatesAndClose = self.finalDatesAndClose
finalDatesStrings = finalDatesAndClose[0]
finalClose = finalDatesAndClose[1]
finalDates = []
from Functions import Functions
for i in range(0, len(finalDatesStrings), 1):
temp = Functions.stringToDate(finalDatesStrings[i])
finalDates.append(temp)
#print(finalDates)
finalDatesAndClose2.append(finalDates)
finalDatesAndClose2.append(finalClose)
return(finalDatesAndClose2)
def is_connected(): def is_connected():
import socket # To check internet connection
try: try:
# connect to the host -- tells us if the host is actually # connect to the host -- tells us if the host is actually
# reachable # reachable
@ -442,6 +477,7 @@ class Stock:
return False return False
def main(self): def main(self):
import importlib.util, sys # To check whether a package is installed
packages = ['requests'] packages = ['requests']
for i in range(0, len(packages), 1): for i in range(0, len(packages), 1):
@ -451,16 +487,18 @@ class Stock:
print(package_name +" is not installed\nPlease type in 'pip install -r requirements.txt' to install all required packages") print(package_name +" is not installed\nPlease type in 'pip install -r requirements.txt' to install all required packages")
# Test internet connection # Test internet connection
internetConnection = Stock.is_connected() internetConnection = StockData.is_connected()
if internetConnection == False: if internetConnection == False:
return return
listOfFirstLastDates = [] listOfFirstLastDates = []
self.allLists = [] self.allLists = []
print('\nNOTE: Only IEX and Alpha Vantage support adjusted returns')
# IEX # IEX
print("\nIEX") print("\nIEX")
listIEX = Stock.getIEX(self) listIEX = StockData.getIEX(self)
#print(listIEX) #print(listIEX)
if listIEX != 'Not available': if listIEX != 'Not available':
listOfFirstLastDates.append((listIEX[0], listIEX[1])) listOfFirstLastDates.append((listIEX[0], listIEX[1]))
@ -468,7 +506,7 @@ class Stock:
# Alpha Vantage # Alpha Vantage
print("\nAlpha Vantage (AV)") print("\nAlpha Vantage (AV)")
listAV = Stock.getAV(self) listAV = StockData.getAV(self)
#print(listAV) #print(listAV)
if listAV != 'Not available': if listAV != 'Not available':
listOfFirstLastDates.append((listAV[0], listAV[1])) listOfFirstLastDates.append((listAV[0], listAV[1]))
@ -477,38 +515,44 @@ class Stock:
# COMMENTED OUT FOR NOW B/C LIMITED # COMMENTED OUT FOR NOW B/C LIMITED
''' '''
print("\nTiingo") print("\nTiingo")
listTiingo = Stock.getTiingo(self) print("NOTE: Tiingo does not return adjusted returns!!")
listTiingo = StockData.getTiingo(self)
#print(listTiingo) #print(listTiingo)
if listTiingo != 'Not available': if listTiingo != 'Not available':
listOfFirstLastDates.append((listTiingo[0], listTiingo[1])) listOfFirstLastDates.append((listTiingo[0], listTiingo[1]))
self.allLists.append(listTiingo) self.allLists.append(listTiingo)
''' '''
#print(self.allLists) #print(self.allLists)
#print(listOfFirstLastDates) #print(listOfFirstLastDates)
if (len(self.allLists) > 0): if (len(self.allLists) > 0):
print("\n") print("\n")
print(len(self.allLists), "available sources for", self.name) print(len(self.allLists), "available source(s) for", self.name)
self.absFirstLastDates = Stock.getFirstLastDate(self, listOfFirstLastDates) self.absFirstLastDates = StockData.getFirstLastDate(self, listOfFirstLastDates)
print("\nThe absolute first date with close values is:", self.absFirstLastDates[0]) print("\nThe absolute first date with close values is:", self.absFirstLastDates[0])
print("The absolute last date with close values is:", self.absFirstLastDates[1]) print("The absolute last date with close values is:", self.absFirstLastDates[1])
print("\nCombining dates and averaging close values") print("\nCombining dates and averaging close values")
self.finalDatesAndClose = Stock.getFinalDatesAndClose(self) # Returns [List of Dates, List of Corresponding Close Values] self.finalDatesAndClose = StockData.getFinalDatesAndClose(self) # Returns [List of Dates, List of Corresponding Close Values]
#print("All dates available:", self.finalDatesAndClose[0]) #print("All dates available:", self.finalDatesAndClose[0])
#print("All close values:\n", self.finalDatesAndClose[1]) #print("All close values:\n", self.finalDatesAndClose[1])
finalDates = self.finalDatesAndClose[0] finalDates = self.finalDatesAndClose[0]
finalClose = self.finalDatesAndClose[1] finalClose = self.finalDatesAndClose[1]
print(len(finalDates), "unique dates:", finalDates[len(finalDates)-1], "...", finalDates[0]) print(len(finalDates), "unique dates:", finalDates[len(finalDates)-1], "...", finalDates[0])
print(len(finalClose), "close values:", finalClose[len(finalClose)-1], "...", finalClose[0]) print(len(finalClose), "close values:", finalClose[len(finalClose)-1], "...", finalClose[0])
print("\nConverting list of final dates to datetime")
self.finalDatesAndClose2 = StockData.datetimeDates(self)
#print(self.finalDatesAndClose2[0][0])
else: else:
print("No sources have data for", self.name) print("No sources have data for", self.name)
def main(): # For testing purposes def main(): # For testing purposes
stockName = 'spy' stockName = 'spy'
stock1 = Stock(stockName) stock1 = StockData(stockName)
print("Finding available dates and close values for", stock1.name) print("Finding available dates and close values for", stock1.name)
Stock.main(stock1) StockData.main(stock1)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

141
StockReturn.py Normal file
View File

@ -0,0 +1,141 @@
# ExpenseRatio.py
# Andrew Dinh
# Python 3.6.7
# Description:
'''
Calculates return for each stock from the lists from ExpenseRatio.py
listOfReturn = [Unadjsted Return, Sharpe Ratio, Sortino Ratio, Treynor Ratio, Jensen's Alpha]
'''
from StockData import StockData
import datetime
from Functions import Functions
class Return:
def __init__(self, newListOfReturn = [], newTimeFrame = [], newBeta = 0, newStandardDeviation = 0, newNegativeStandardDeviation = 0, newMarketReturn = 0, newSize = 0, newSizeOfNeg = 0, newFirstLastDates = [], newAllLists = [], newAbsFirstLastDates = ''):
self.listOfReturn = newListOfReturn
self.timeFrame = newTimeFrame # [year, months (30 days)]
self.beta = newBeta
self.standardDeviation = newStandardDeviation
self.negativeStandardDeviation = newNegativeStandardDeviation
self.marketReturn = newMarketReturn
self.size = newSize
self.sizeOfNeg = newSizeOfNeg
self.firstLastDates = newFirstLastDates
def getFirstLastDates(self, stock):
firstLastDates = []
timeFrame = self.timeFrame
firstDate = datetime.datetime.now() - datetime.timedelta(days=timeFrame[0]*365)
firstDate = firstDate - datetime.timedelta(days=timeFrame[1]*30)
firstDate = ''.join((str(firstDate.year),'-', str(firstDate.month), '-', str(firstDate.day)))
lastDate = StockData.returnAbsFirstLastDates(stock)[1]
#print(lastDate)
firstLastDates.append(firstDate)
firstLastDates.append(lastDate)
return firstLastDates
def getFirstLastDates2(self, stock):
finalDatesAndClose = StockData.returnFinalDatesAndClose(stock)
finalDatesAndClose2 = StockData.returnFinalDatesAndClose2(stock)
firstDate = self.firstLastDates[0]
lastDate = self.firstLastDates[1]
finalDates = finalDatesAndClose[0]
firstDateExists = False
lastDateExists = False
for i in range(0, len(finalDates), 1):
if finalDates[i] == str(firstDate):
firstDateExists = True
elif finalDates[i] == lastDate:
lastDateExists = True
i = len(finalDates)
if firstDateExists == False:
print("Could not find first date. Changing first date to closest date")
tempDate = Functions.stringToDate(firstDate) # Change to datetime
print('Original first date:', tempDate)
#tempDate = datetime.date(2014,1,17)
newFirstDate = Functions.getNearest(finalDatesAndClose2[0], tempDate)
print('New first date:', newFirstDate)
firstDate = str(newFirstDate)
if lastDateExists == False:
print("Could not find final date. Changing final date to closest date")
tempDate2 = Functions.stringToDate(lastDate) # Change to datetime
print('Original final date:', tempDate2)
#tempDate2 = datetime.date(2014,1,17)
newLastDate = Functions.getNearest(finalDatesAndClose2[0], tempDate2)
print('New final date:', newLastDate)
lastDate = str(newLastDate)
firstLastDates = []
firstLastDates.append(firstDate)
firstLastDates.append(lastDate)
return firstLastDates
def getUnadjustedReturn(self, stock):
finalDatesAndClose = StockData.returnFinalDatesAndClose(stock)
finalDatesAndClose2 = StockData.returnFinalDatesAndClose2(stock)
firstDate = self.firstLastDates[0]
lastDate = self.firstLastDates[1]
finalDates = finalDatesAndClose[0]
finalClose = finalDatesAndClose[1]
for i in range(0, len(finalDates), 1):
if finalDates[i] == str(firstDate):
firstClose = finalClose[i]
elif finalDates[i] == lastDate:
lastClose = finalClose[i]
i = len(finalDates)
print('Close values:', firstClose, '...', lastClose)
unadjustedReturn = float(lastClose/firstClose)
unadjustedReturn = unadjustedReturn * 100
return unadjustedReturn
# def getBeta(self, timeFrame):
# def getStandardDeviation(self, timeFrame):
def main(self, stock):
# Find date to start from and last date
self.timeFrame = []
self.listOfReturn = []
print("\nPlease enter a time frame in years: ", end='')
#timeFrameYear = int(input())
timeFrameYear = 5
print(timeFrameYear)
self.timeFrame.append(timeFrameYear)
print("Please enter a time frame in months (30 days): ", end='')
#timeFrameMonth = int(input())
timeFrameMonth = 0
print(timeFrameMonth)
self.timeFrame.append(timeFrameMonth)
#print(self.timeFrame)
self.firstLastDates = Return.getFirstLastDates(self, stock)
print('Dates: ', self.firstLastDates)
print('\nMaking sure dates are within list...')
self.firstLastDates = Return.getFirstLastDates2(self, stock)
print('New dates: ', self.firstLastDates)
print('\nGetting unadjusted return')
unadjustedReturn = Return.getUnadjustedReturn(self, stock)
self.listOfReturn.append(unadjustedReturn)
print(self.listOfReturn[0])
print(self.listOfReturn[0]/timeFrameYear, '%')
def main():
stockName = 'spy'
stock1 = StockData(stockName)
print("Finding available dates and close values for", stock1.name)
StockData.main(stock1)
stock1Return = Return()
Return.main(stock1Return, stock1)
if __name__ == "__main__":
main()

58
main.py
View File

@ -1,7 +1,7 @@
# main.py # main.py
# Andrew Dinh # Andrew Dinh
# Python 3.6.1 # Python 3.6.1
# Description: # Description:
''' '''
Asks users for mutual funds/stocks to compare Asks users for mutual funds/stocks to compare
Asks to be compared (expense ratio, turnover, market capitalization, or persistence) Asks to be compared (expense ratio, turnover, market capitalization, or persistence)
@ -15,7 +15,7 @@ Gives correlation value using equation at the end (from 0 to 1)
FIRST TESTING WITH EXPENSE RATIO FIRST TESTING WITH EXPENSE RATIO
''' '''
from StockData import Stock from StockData import StockData
listOfStocks = [] listOfStocks = []
numberOfStocks = int(input("How many stocks or mutual funds would you like to analyze? ")) numberOfStocks = int(input("How many stocks or mutual funds would you like to analyze? "))
@ -23,48 +23,54 @@ for i in range(0, numberOfStocks, 1):
print("Stock", i+1, ": ", end='') print("Stock", i+1, ": ", end='')
stockName = str(input()) stockName = str(input())
listOfStocks.append(i) listOfStocks.append(i)
listOfStocks[i] = Stock() listOfStocks[i] = StockData()
listOfStocks[i].setName(stockName) listOfStocks[i].setName(stockName)
#print(listOfStocks[i].name) #print(listOfStocks[i].name)
sumOfListLengths = 0 sumOfListLengths = 0
for i in range(0, numberOfStocks, 1): for i in range(0, numberOfStocks, 1):
print(listOfStocks[i].name) print(listOfStocks[i].name)
Stock.main(listOfStocks[i]) StockData.main(listOfStocks[i])
# Count how many stocks are available # Count how many stocks are available
temp = Stock.getAllLists(listOfStocks[i]) temp = StockData.returnAllLists(listOfStocks[i])
sumOfListLengths = sumOfListLengths + len(temp) sumOfListLengths = sumOfListLengths + len(temp)
if sumOfListLengths == 0: if sumOfListLengths == 0:
print("No sources have stock data for given stocks") print("No sources have data for given stocks")
exit()
else: # Find return over time using either Jensen's Alpha, Sharpe Ratio, Sortino Ratio, or Treynor Ratio
#print(listOfStocks[0].name, listOfStocks[0].absFirstLastDates, listOfStocks[0].finalDatesAndClose) #from StockReturn import Return
indicatorFound = False
while indicatorFound == False:
print("\n1. Expense Ratio\n2. Asset Size\n3. Turnover\n4. Persistence\nWhich indicator would you like to look at? ", end='')
indicator = str(input())
indicatorFound = True
if indicator == 'Expense Ratio' or indicator == '1' or indicator == 'expense ratio':
print('\nExpense Ratio')
elif indicator == 'Asset Size' or indicator == '2' or indicator == 'asset size': # Runs correlation or regression study
print('\nAsset Size') #print(listOfStocks[0].name, listOfStocks[0].absFirstLastDates, listOfStocks[0].finalDatesAndClose)
indicatorFound = False
while indicatorFound == False:
print("\n1. Expense Ratio\n2. Asset Size\n3. Turnover\n4. Persistence\nWhich indicator would you like to look at? ", end='')
indicator = str(input())
indicatorFound = True
elif indicator == 'Turnover' or indicator == '3' or indicator == 'turnover': if indicator == 'Expense Ratio' or indicator == '1' or indicator == 'expense ratio':
print('\nTurnover') #from ExpenseRatio import ExpenseRatio
print('\nExpense Ratio')
elif indicator == 'Persistence' or indicator == '4' or indicator == 'persistence': elif indicator == 'Asset Size' or indicator == '2' or indicator == 'asset size':
print('\nPersistence') print('\nAsset Size')
else: elif indicator == 'Turnover' or indicator == '3' or indicator == 'turnover':
indicatorFound = False print('\nTurnover')
print('\nInvalid input, please enter indicator again')
elif indicator == 'Persistence' or indicator == '4' or indicator == 'persistence':
print('\nPersistence')
else:
indicatorFound = False
print('\nInvalid input, please enter indicator again')
''' '''
stockName = 'IWV' stockName = 'IWV'
stock1 = Stock(stockName) stock1 = Stock(stockName)
print("Finding available dates and close values for", stock1.name) print("Finding available dates and close values for", stock1.name)
Stock.main(stock1) StockData.main(stock1)
''' '''