diff --git a/README.md b/README.md index f615e2a..ebb6232 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,17 @@ # Mutual Fund Indicators 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 3 and will examine market capitalization, persistence, turnover, and expense ratios. ### Prerequisites `$ pip install -r requirements.txt` -or - -`$ pip install requests` - -`$ pip install numpy` - ### Quickstart To begin, run -`$ python(3) main.py` +`$ python main.py` Some ticker values to try: SPY, VFINX, AAPL, GOOGL diff --git a/StockData.py b/StockData.py index e2a90a9..d515d3a 100644 --- a/StockData.py +++ b/StockData.py @@ -477,6 +477,8 @@ class StockData: return False def main(self): + print('Beginning StockData.py') + import importlib.util, sys # To check whether a package is installed packages = ['requests'] @@ -495,6 +497,7 @@ class StockData: self.allLists = [] print('\nNOTE: Only IEX and Alpha Vantage support adjusted returns') + print('NOTE: Only Alpha Vantage and Tiingo support mutual fund data') # IEX print("\nIEX") @@ -526,7 +529,7 @@ class StockData: #print(self.allLists) #print(listOfFirstLastDates) if (len(self.allLists) > 0): - print("\n") + print("\n", end='') print(len(self.allLists), "available source(s) for", self.name) self.absFirstLastDates = StockData.getFirstLastDate(self, listOfFirstLastDates) print("\nThe absolute first date with close values is:", self.absFirstLastDates[0]) @@ -541,7 +544,7 @@ class StockData: print(len(finalDates), "unique dates:", finalDates[len(finalDates)-1], "...", finalDates[0]) print(len(finalClose), "close values:", finalClose[len(finalClose)-1], "...", finalClose[0]) - print("\nConverting list of final dates to datetime") + print("\nConverting list of final dates to datetime\n") self.finalDatesAndClose2 = StockData.datetimeDates(self) #print(self.finalDatesAndClose2[0][0]) diff --git a/StockReturn.py b/StockReturn.py index 44e36bb..3911de5 100644 --- a/StockReturn.py +++ b/StockReturn.py @@ -4,7 +4,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] +listOfReturn = [Unadjusted Return, Sharpe Ratio, Sortino Ratio, Treynor Ratio, Jensen's Alpha] ''' from StockData import StockData @@ -14,7 +14,7 @@ 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.timeFrame = newTimeFrame # [years, months (30 days)] self.beta = newBeta self.standardDeviation = newStandardDeviation self.negativeStandardDeviation = newNegativeStandardDeviation @@ -23,6 +23,12 @@ class Return: self.sizeOfNeg = newSizeOfNeg self.firstLastDates = newFirstLastDates + def returnTimeFrame(self): + return self.timeFrame + + def setTimeFrame(self, newTimeFrame): + self.timeFrame = newTimeFrame + def getFirstLastDates(self, stock): firstLastDates = [] timeFrame = self.timeFrame @@ -77,7 +83,6 @@ class Return: def getUnadjustedReturn(self, stock): finalDatesAndClose = StockData.returnFinalDatesAndClose(stock) - finalDatesAndClose2 = StockData.returnFinalDatesAndClose2(stock) firstDate = self.firstLastDates[0] lastDate = self.firstLastDates[1] finalDates = finalDatesAndClose[0] @@ -91,15 +96,34 @@ class Return: i = len(finalDates) print('Close values:', firstClose, '...', lastClose) - unadjustedReturn = float(lastClose/firstClose) - unadjustedReturn = unadjustedReturn * 100 + fullUnadjustedReturn = float(lastClose/firstClose) + unadjustedReturn = fullUnadjustedReturn**(1/(self.timeFrame[0]+(self.timeFrame[1])*.1)) return unadjustedReturn -# def getBeta(self, timeFrame): + def getBeta(self): + # Can be calculated with correlation + import numpy as np + + finalDatesAndClose = StockData.returnFinalDatesAndClose(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] +55ggbh + #list1 = + list2 = [1,2,4,1] + + print(numpy.corrcoef(list1, list2)[0, 1]) # def getStandardDeviation(self, timeFrame): - def main(self, stock): + def mainBenchmark(self, stock): + print('Beginning StockReturn.py') + # Find date to start from and last date self.timeFrame = [] self.listOfReturn = [] @@ -125,8 +149,31 @@ class Return: print('\nGetting unadjusted return') unadjustedReturn = Return.getUnadjustedReturn(self, stock) self.listOfReturn.append(unadjustedReturn) - print(self.listOfReturn[0]) - print(self.listOfReturn[0]/timeFrameYear, '%') + print('Average annual return for the past', self.timeFrame[0], 'years and', self.timeFrame[1], 'months: ', end='') + print((self.listOfReturn[0]-1)*100, '%', sep='') + + + def main(self, stock): + print('Beginning StockReturn.py') + + # Find date to start from and last date + self.listOfReturn = [] + + 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('Average annual return for the past', self.timeFrame[0], 'years and', self.timeFrame[1], 'months: ', end='') + print((self.listOfReturn[0]-1)*100, '%', sep='') + + #print('\nGetting beta') + #beta = Return.getBeta(self, stock) def main(): stockName = 'spy' @@ -135,6 +182,8 @@ def main(): StockData.main(stock1) stock1Return = Return() + Return.setTimeFrame(stock1Return, [5, 0]) + Return.main(stock1Return, stock1) if __name__ == "__main__": diff --git a/main.py b/main.py index ccf3692..138b810 100644 --- a/main.py +++ b/main.py @@ -16,40 +16,83 @@ FIRST TESTING WITH EXPENSE RATIO ''' from StockData import StockData +from StockReturn import Return -listOfStocks = [] -numberOfStocks = int(input("How many stocks or mutual funds would you like to analyze? ")) +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()) - listOfStocks.append(i) - listOfStocks[i] = StockData() - listOfStocks[i].setName(stockName) - #print(listOfStocks[i].name) + 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(listOfStocks[i].name) - StockData.main(listOfStocks[i]) + print('\n', listOfStocksData[i].name, sep='') + StockData.main(listOfStocksData[i]) # Count how many stocks are available - temp = StockData.returnAllLists(listOfStocks[i]) - sumOfListLengths = sumOfListLengths + len(temp) + 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 -#from StockReturn import Return +for i in range(0, numberOfStocks, 1): + print('\n', listOfStocksData[i].name, sep='') + #StockReturn.main(listOfStocksReturn[i]) # Runs correlation or regression study -#print(listOfStocks[0].name, listOfStocks[0].absFirstLastDates, listOfStocks[0].finalDatesAndClose) +# print(listOfStocksData[0].name, listOfStocksData[0].absFirstLastDates, listOfStocksData[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()) + 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 @@ -66,7 +109,7 @@ while indicatorFound == False: else: indicatorFound = False - print('\nInvalid input, please enter indicator again') + print('Invalid input, please enter indicator again') ''' stockName = 'IWV'