mirror of
https://github.com/andrewkdinh/fund-indicators.git
synced 2024-11-23 21:04:19 -08:00
Merge pull request #10 from andrewkdinh/andrewkdinh-patch-1
Fix errors from removing stocks from listOfStocks
This commit is contained in:
commit
67abe49945
@ -247,7 +247,7 @@ def trueOrFalse():
|
|||||||
elif answer.lower() == 'no':
|
elif answer.lower() == 'no':
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
print('Please either choose a number or type an answer')
|
print('Please choose a number or type an answer')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -20,7 +20,6 @@ fund-indicators is a cross-platform Python application that allows users to easi
|
|||||||
- Optional graphs to easily visualize linear regression results
|
- Optional graphs to easily visualize linear regression results
|
||||||
- A new joke every time
|
- A new joke every time
|
||||||
- Cross-platform (tested on Windows and Linux)
|
- Cross-platform (tested on Windows and Linux)
|
||||||
- Simple to use
|
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
@ -29,7 +28,8 @@ Give it a try at [repl.run](https://fund-indicators.andrewkdinh.repl.run) or [re
|
|||||||
If you would like to clone to your own machine:
|
If you would like to clone to your own machine:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/andrewkdinh/fund-indicators.git && cd fund-indicators
|
git clone https://github.com/andrewkdinh/fund-indicators.git
|
||||||
|
cd fund-indicators
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
python main.py
|
python main.py
|
||||||
```
|
```
|
||||||
|
111
main.py
111
main.py
@ -268,6 +268,7 @@ class Stock:
|
|||||||
cprint('Get:' + url, 'white', attrs=['dark'])
|
cprint('Get:' + url, 'white', attrs=['dark'])
|
||||||
with Halo(spinner='dots'):
|
with Halo(spinner='dots'):
|
||||||
t = requests.get(url)
|
t = requests.get(url)
|
||||||
|
Functions.fromCache(t)
|
||||||
if t.history:
|
if t.history:
|
||||||
print('Yahoo Finance does not have data for', self.name)
|
print('Yahoo Finance does not have data for', self.name)
|
||||||
print('Yahoo not available')
|
print('Yahoo not available')
|
||||||
@ -330,8 +331,8 @@ class Stock:
|
|||||||
else:
|
else:
|
||||||
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)
|
||||||
print('Removing ' + self.name +
|
cprint('Removing ' + self.name +
|
||||||
' from list of stocks to ensure compatibility later')
|
' because no data was found', 'yellow')
|
||||||
return 'N/A'
|
return 'N/A'
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
@ -346,8 +347,8 @@ class Stock:
|
|||||||
for i in datesAndCloseList[1]:
|
for i in datesAndCloseList[1]:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
print('Found close value of 0. This is likely something like ticker RGN (Daily Time Series with Splits and Dividend Events)')
|
print('Found close value of 0. This is likely something like ticker RGN (Daily Time Series with Splits and Dividend Events)')
|
||||||
print('Removing ' + self.name +
|
cprint('Removing ' + self.name +
|
||||||
'from list of stocks to ensure compability later')
|
'from list of stocks to ensure compability later', 'yellow')
|
||||||
return 'N/A'
|
return 'N/A'
|
||||||
|
|
||||||
return datesAndCloseList
|
return datesAndCloseList
|
||||||
@ -363,7 +364,7 @@ class Stock:
|
|||||||
|
|
||||||
firstDate = datetime.datetime.now().date() - datetime.timedelta(
|
firstDate = datetime.datetime.now().date() - datetime.timedelta(
|
||||||
days=self.timeFrame*30)
|
days=self.timeFrame*30)
|
||||||
print(self.timeFrame, ' months ago: ', firstDate, sep='')
|
# print(self.timeFrame, ' 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)
|
||||||
@ -409,8 +410,8 @@ class Stock:
|
|||||||
secondDate = Functions.getNearest(self.dates, secondDate)
|
secondDate = Functions.getNearest(self.dates, secondDate)
|
||||||
|
|
||||||
if firstDate == secondDate:
|
if firstDate == secondDate:
|
||||||
print('Closest date is', firstDate,
|
print('Closest date is ' + str(firstDate) +
|
||||||
'which is after the given time frame.')
|
', which is after the given time frame')
|
||||||
return 'N/A'
|
return 'N/A'
|
||||||
|
|
||||||
# Get corresponding close values and calculate monthly return
|
# Get corresponding close values and calculate monthly return
|
||||||
@ -739,7 +740,9 @@ class Stock:
|
|||||||
# https://finance.yahoo.com/quote/SPY/profile?p=SPY
|
# https://finance.yahoo.com/quote/SPY/profile?p=SPY
|
||||||
cprint('Get:' + url, 'white', attrs=['dark'])
|
cprint('Get:' + url, 'white', attrs=['dark'])
|
||||||
with Halo(spinner='dots'):
|
with Halo(spinner='dots'):
|
||||||
raw_html = requests.get(url).text
|
t = requests.get(url)
|
||||||
|
Functions.fromCache(t)
|
||||||
|
raw_html = t.text
|
||||||
soup = BeautifulSoup(raw_html, 'html.parser')
|
soup = BeautifulSoup(raw_html, 'html.parser')
|
||||||
|
|
||||||
r = soup.find_all(
|
r = soup.find_all(
|
||||||
@ -777,9 +780,8 @@ class Stock:
|
|||||||
indicatorValue = str(
|
indicatorValue = str(
|
||||||
input(Stock.indicator + ' of ' + self.name + ': '))
|
input(Stock.indicator + ' of ' + self.name + ': '))
|
||||||
else:
|
else:
|
||||||
# print('Something is wrong. Indicator was not found. Ending program.')
|
|
||||||
cprint(
|
cprint(
|
||||||
'Something is wrong. Indicator was not found. Ending program.', 'white', 'on_red')
|
'Something is wrong. Indicator was not found. Ending program', 'white', 'on_red')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
if Functions.strintIsFloat(indicatorValue) is True:
|
if Functions.strintIsFloat(indicatorValue) is True:
|
||||||
@ -838,7 +840,7 @@ def benchmarkInit():
|
|||||||
break
|
break
|
||||||
|
|
||||||
if benchmarkTicker == '':
|
if benchmarkTicker == '':
|
||||||
print('Benchmark not found. Please use a benchmark from the list')
|
print('Benchmark not found')
|
||||||
|
|
||||||
print(benchmark, ' (', benchmarkTicker, ')', sep='')
|
print(benchmark, ' (', benchmarkTicker, ')', sep='')
|
||||||
|
|
||||||
@ -862,8 +864,7 @@ def stocksInit():
|
|||||||
'Kiplinger top-performing funds (50)',
|
'Kiplinger top-performing funds (50)',
|
||||||
'TheStreet top-rated mutual funds (20)',
|
'TheStreet top-rated mutual funds (20)',
|
||||||
'Money best mutual funds (50)',
|
'Money best mutual funds (50)',
|
||||||
'Investors Business Daily best mutual funds (~45)',
|
'Investors Business Daily best mutual funds (~45)']
|
||||||
'Yahoo top mutual funds (25)']
|
|
||||||
|
|
||||||
for i in range(0, len(methods), 1):
|
for i in range(0, len(methods), 1):
|
||||||
print('[' + str(i+1) + '] ' + methods[i])
|
print('[' + str(i+1) + '] ' + methods[i])
|
||||||
@ -872,7 +873,7 @@ def stocksInit():
|
|||||||
if Functions.stringIsInt(method) is True:
|
if Functions.stringIsInt(method) is True:
|
||||||
method = int(method)
|
method = int(method)
|
||||||
if method == 0 or method > len(methods):
|
if method == 0 or method > len(methods):
|
||||||
print('Please choose a valid method')
|
print('Please choose a number from 1 to', len(methods))
|
||||||
else:
|
else:
|
||||||
method = 0
|
method = 0
|
||||||
print('Please choose a number')
|
print('Please choose a number')
|
||||||
@ -1073,36 +1074,6 @@ def stocksInit():
|
|||||||
|
|
||||||
print('\n' + str(len(listOfStocks)) + ' mutual funds total')
|
print('\n' + str(len(listOfStocks)) + ' mutual funds total')
|
||||||
|
|
||||||
elif method == 7:
|
|
||||||
listOfStocks = []
|
|
||||||
url = 'https://finance.yahoo.com/screener/predefined/top_mutual_funds/'
|
|
||||||
headers = {
|
|
||||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}
|
|
||||||
cprint('Get:' + url, 'white', attrs=['dark'])
|
|
||||||
with Halo(spinner='dots'):
|
|
||||||
f = requests.get(url, headers=headers)
|
|
||||||
Functions.fromCache(f)
|
|
||||||
raw_html = f.text
|
|
||||||
soup = BeautifulSoup(raw_html, 'html.parser')
|
|
||||||
|
|
||||||
file = open('yahoo-stocks.txt', 'w')
|
|
||||||
r = soup.find_all('a', attrs={'class': 'Fw(600)'})
|
|
||||||
|
|
||||||
for k in r:
|
|
||||||
t = k.text.strip()
|
|
||||||
if len(t) == 5 and t == t.upper():
|
|
||||||
print(t, end=' ')
|
|
||||||
listOfStocks.append(k.text.strip())
|
|
||||||
file.write(str(k.text.strip()) + '\n')
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
for i in range(0, len(listOfStocks), 1):
|
|
||||||
stockName = listOfStocks[i].upper()
|
|
||||||
listOfStocks[i] = Stock()
|
|
||||||
listOfStocks[i].setName(stockName)
|
|
||||||
|
|
||||||
print('\n' + str(len(listOfStocks)) + ' mutual funds total')
|
|
||||||
|
|
||||||
if len(listOfStocks) < 2:
|
if len(listOfStocks) < 2:
|
||||||
print('Please choose another method')
|
print('Please choose another method')
|
||||||
else:
|
else:
|
||||||
@ -1159,14 +1130,18 @@ def sendAsync(url):
|
|||||||
|
|
||||||
def timeFrameInit():
|
def timeFrameInit():
|
||||||
isInteger = False
|
isInteger = False
|
||||||
|
print('')
|
||||||
while isInteger is False:
|
while isInteger is False:
|
||||||
print(
|
print(
|
||||||
'\nPlease enter the time frame in months (<60 recommended):', end='')
|
'Please enter the time frame in months (<60 recommended):', end='')
|
||||||
temp = input(' ')
|
temp = input(' ')
|
||||||
isInteger = Functions.stringIsInt(temp)
|
isInteger = Functions.stringIsInt(temp)
|
||||||
if isInteger is True:
|
if isInteger is True:
|
||||||
if int(temp) > 1 and int(temp) < 1000:
|
if int(temp) > 1 and int(temp) < 1000:
|
||||||
months = int(temp)
|
months = int(temp)
|
||||||
|
elif int(temp) >= 1000:
|
||||||
|
print('Please enter a number less than 1000')
|
||||||
|
isInteger = False
|
||||||
else:
|
else:
|
||||||
print('Please enter a number greater than 1')
|
print('Please enter a number greater than 1')
|
||||||
isInteger = False
|
isInteger = False
|
||||||
@ -1270,7 +1245,7 @@ def returnMain(benchmark, listOfStocks):
|
|||||||
listOfStocks[i].monthlyReturn = Stock.calcMonthlyReturn(
|
listOfStocks[i].monthlyReturn = Stock.calcMonthlyReturn(
|
||||||
listOfStocks[i])
|
listOfStocks[i])
|
||||||
if listOfStocks[i].monthlyReturn == 'N/A':
|
if listOfStocks[i].monthlyReturn == 'N/A':
|
||||||
print('Removing ' + listOfStocks[i].name + ' from list of stocks')
|
cprint('Removing ' + listOfStocks[i].name + ' from list of stocks', 'yellow')
|
||||||
del listOfStocks[i]
|
del listOfStocks[i]
|
||||||
if len(listOfStocks) == 0:
|
if len(listOfStocks) == 0:
|
||||||
print('No stocks fit time frame. Ending program')
|
print('No stocks fit time frame. Ending program')
|
||||||
@ -1303,31 +1278,15 @@ def returnMain(benchmark, listOfStocks):
|
|||||||
cprint('\nNumber of stocks that fit time frame: ' +
|
cprint('\nNumber of stocks that fit time frame: ' +
|
||||||
str(len(listOfStocks)), 'green')
|
str(len(listOfStocks)), 'green')
|
||||||
if len(listOfStocks) < 2:
|
if len(listOfStocks) < 2:
|
||||||
# print('Cannot proceed to the next step. Exiting program.')
|
# print('Cannot proceed to the next step. Exiting program')
|
||||||
cprint('Cannot proceed to the next step. Exiting program.',
|
cprint('Cannot proceed to the next step. Exiting program',
|
||||||
'white', 'on_red')
|
'white', 'on_red')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
def outlierChoice():
|
def outlierChoice():
|
||||||
print('\nWould you like to remove indicator outliers?')
|
print('\nWould you like to remove indicator outliers?')
|
||||||
print('[1] Yes\n[2] No')
|
return Functions.trueOrFalse()
|
||||||
found = False
|
|
||||||
while found is False:
|
|
||||||
outlierChoice = str(input('Choice: '))
|
|
||||||
if Functions.stringIsInt(outlierChoice):
|
|
||||||
if int(outlierChoice) == 1:
|
|
||||||
return True
|
|
||||||
elif int(outlierChoice) == 2:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
print('Please enter 1 or 2')
|
|
||||||
elif outlierChoice.lower() == 'yes':
|
|
||||||
return True
|
|
||||||
elif outlierChoice.lower() == 'no':
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
print('Not valid. Please enter a number or yes or no.')
|
|
||||||
|
|
||||||
|
|
||||||
def indicatorInit():
|
def indicatorInit():
|
||||||
@ -1359,7 +1318,7 @@ def indicatorInit():
|
|||||||
break
|
break
|
||||||
|
|
||||||
if indicatorFound is False:
|
if indicatorFound is False:
|
||||||
print('Please choose an indicator from the list\n')
|
print('Please choose a number from 1 to', len(listOfIndicators), 'or type an answer')
|
||||||
|
|
||||||
return indicator
|
return indicator
|
||||||
|
|
||||||
@ -1478,7 +1437,9 @@ def indicatorMain(listOfStocks):
|
|||||||
cprint('\n' + str(Stock.indicator) + '\n', 'white', attrs=['underline'])
|
cprint('\n' + str(Stock.indicator) + '\n', 'white', attrs=['underline'])
|
||||||
|
|
||||||
listOfStocksIndicatorValues = []
|
listOfStocksIndicatorValues = []
|
||||||
for i in range(0, len(listOfStocks), 1):
|
|
||||||
|
i = 0
|
||||||
|
while i < len(listOfStocks):
|
||||||
cprint(listOfStocks[i].name, 'cyan')
|
cprint(listOfStocks[i].name, 'cyan')
|
||||||
if Stock.indicator == 'Persistence':
|
if Stock.indicator == 'Persistence':
|
||||||
listOfStocks[i].indicatorValue = Stock.calcPersistence(
|
listOfStocks[i].indicatorValue = Stock.calcPersistence(
|
||||||
@ -1496,15 +1457,17 @@ def indicatorMain(listOfStocks):
|
|||||||
listOfStocks[i].indicatorValue = Stock.indicatorManual(
|
listOfStocks[i].indicatorValue = Stock.indicatorManual(
|
||||||
listOfStocks[i])
|
listOfStocks[i])
|
||||||
elif listOfStocks[i].indicatorValue == 'Stock':
|
elif listOfStocks[i].indicatorValue == 'Stock':
|
||||||
print('Removing ' + listOfStocks[i].name + ' from list of stocks')
|
cprint('Removing ' + listOfStocks[i].name + ' from list of stocks', 'yellow')
|
||||||
del listOfStocks[i]
|
del listOfStocks[i]
|
||||||
if len(listOfStocks) < 2:
|
if len(listOfStocks) < 2:
|
||||||
# print('Not able to go to the next step. Ending program')
|
# print('Not able to go to the next step. Ending program')
|
||||||
cprint('Not able to go to the next step. Ending program',
|
cprint('Not able to go to the next step. Ending program',
|
||||||
'white', 'on_red')
|
'white', 'on_red')
|
||||||
exit()
|
exit()
|
||||||
|
else:
|
||||||
listOfStocksIndicatorValues.append(listOfStocks[i].indicatorValue)
|
listOfStocks[i].indicatorValue = float(listOfStocks[i].indicatorValue)
|
||||||
|
listOfStocksIndicatorValues.append(listOfStocks[i].indicatorValue)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
# Remove outliers
|
# Remove outliers
|
||||||
if Stock.removeOutliers is True:
|
if Stock.removeOutliers is True:
|
||||||
@ -1518,11 +1481,10 @@ def indicatorMain(listOfStocks):
|
|||||||
# print('Original list:', listOfStocksIndicatorValues)
|
# print('Original list:', listOfStocksIndicatorValues)
|
||||||
listOfStocksIndicatorValues = temp[0]
|
listOfStocksIndicatorValues = temp[0]
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(listOfStocks)-1:
|
while i < len(listOfStocks):
|
||||||
for j in temp[1]:
|
for j in temp[1]:
|
||||||
if listOfStocks[i].indicatorValue == j:
|
if listOfStocks[i].indicatorValue == j:
|
||||||
print('Removing', listOfStocks[i].name, 'because it has a',
|
cprint('Removing ' + listOfStocks[i].name + ' because it has a ' + str(Stock.indicator.lower()) + ' value of ' + str(listOfStocks[i].indicatorValue), 'yellow')
|
||||||
Stock.indicator.lower(), 'value of', listOfStocks[i].indicatorValue)
|
|
||||||
del listOfStocks[i]
|
del listOfStocks[i]
|
||||||
i = i - 1
|
i = i - 1
|
||||||
break
|
break
|
||||||
@ -1534,7 +1496,7 @@ def indicatorMain(listOfStocks):
|
|||||||
cprint('Calculating correlation and linear regression\n',
|
cprint('Calculating correlation and linear regression\n',
|
||||||
'white', attrs=['underline'])
|
'white', attrs=['underline'])
|
||||||
|
|
||||||
listOfReturns = [] # A list that matches the above list with return values [[averageMonthlyReturn1, aAR2, aAR3], [sharpe1, sharpe2, sharpe3], etc.]
|
listOfReturns = [] # A list that matches the above list with return values [[averageMonthlyReturn1, aMR2, aMR3], [sharpe1, sharpe2, sharpe3], etc.]
|
||||||
tempListOfReturns = []
|
tempListOfReturns = []
|
||||||
for i in range(0, len(listOfStocks), 1):
|
for i in range(0, len(listOfStocks), 1):
|
||||||
tempListOfReturns.append(listOfStocks[i].averageMonthlyReturn)
|
tempListOfReturns.append(listOfStocks[i].averageMonthlyReturn)
|
||||||
@ -1748,6 +1710,7 @@ def main():
|
|||||||
runningProgram = continueProgram()
|
runningProgram = continueProgram()
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
print('Goodbye!\n')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user