mirror of
https://github.com/andrewkdinh/fund-indicators.git
synced 2024-11-24 08:14:17 -08:00
Finished basic functionalities
This commit is contained in:
parent
bec100cd44
commit
d398924c0d
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@ __pycache__/StockData.cpython-37.pyc
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
test/
|
test/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
requests_cache.sqlite
|
31
Functions.py
31
Functions.py
@ -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
787
main.py
@ -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
51
output.bin
Normal 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>
|
@ -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
|
Loading…
Reference in New Issue
Block a user