Minor improvements in overall code for consistency

This commit is contained in:
didier
2021-02-22 00:25:51 +00:00
parent d8d3586666
commit 3250f1bbda
15 changed files with 331 additions and 322 deletions

View File

@@ -19,33 +19,33 @@
# - The loss function
MultiLayer_Perceptron \
= [ {'Dense':
= [ {'Dense':
{'units':50, 'activation':'relu'} },
{'Dense':
{'Dense':
{'units':100, 'activation':'relu'} },
{'Dense':
{'Dense':
{'units':80, 'activation':'relu'} },
{'Dense':
{'Dense':
{'units':30, 'activation':'relu'} },
{'Dense':
{'Dense':
{'activation':'linear'} }]
Recurrent_Neural_Network \
= [ {'SimpleRNN':
= [ {'SimpleRNN':
{'units':100, 'activation':'linear', 'return_sequences':True} },
{'SimpleRNN':
{'SimpleRNN':
{'units':50, 'activation':'linear', 'return_sequences':True} },
{'Dropout':
{'Dropout':
{'rate':0.2} },
{'SimpleRNN':
{'SimpleRNN':
{'units':21, 'activation':'linear', 'return_sequences':False} },
{'Dense':
{'Dense':
{'activation':'linear'} }]
Long_Short_Term_Memory \
= [ {'LSTM':
= [ {'LSTM':
{'units':25, 'activation':'tanh', 'return_sequences':True} },
{'LSTM':
{'LSTM':
{'units':15, 'activation':'tanh', 'return_sequences':False} },
{'Dense':
{'activation':'linear'} }]
{'Dense':
{'activation':'linear'} }]

View File

@@ -16,10 +16,11 @@ register_matplotlib_converters()
# ------------------------------------------- PRICE_TARGET_FROM_ANALYSTS -------------------------------------------
def price_target_from_analysts(l_args, df_stock, s_ticker, s_start, s_interval):
parser = argparse.ArgumentParser(prog='price_target_from_analysts',
description="""Price target from analysts [Source: Business Insider API]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=10, help='Number of latest price targets')
parser = argparse.ArgumentParser(prog='pt',
description="""Prints price target from analysts. [Source: Business Insider]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=10,
help='number of latest price targets from analysts to print.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -38,14 +39,14 @@ def price_target_from_analysts(l_args, df_stock, s_ticker, s_start, s_interval):
s_analyst_data = script.get_text().split("config: ",1)[1].split(",\r\n",1)[0]
d_analyst_data = json.loads(s_analyst_data)
break
#pprint.pprint(d_analyst_data)
df_analyst_data = pd.DataFrame.from_dict(d_analyst_data['Markers'])
df_analyst_data = pd.DataFrame.from_dict(d_analyst_data['Markers'])
df_analyst_data = df_analyst_data[['DateLabel', 'Company', 'InternalRating', 'PriceTarget']]
df_analyst_data.columns = ['Date', 'Company', 'Rating', 'Price Target']
df_analyst_data
df_analyst_data['Rating'].replace({'gut': 'BUY',
'neutral': 'HOLD',
df_analyst_data['Rating'].replace({'gut': 'BUY',
'neutral': 'HOLD',
'schlecht':'SELL'}, inplace=True)
df_analyst_data['Date'] = pd.to_datetime(df_analyst_data['Date'])
df_analyst_data = df_analyst_data.set_index('Date')
@@ -56,7 +57,7 @@ def price_target_from_analysts(l_args, df_stock, s_ticker, s_start, s_interval):
if s_interval == "1440min":
plt.plot(df_stock.index, df_stock['5. adjusted close'].values, lw=3)
# Intraday
# Intraday
else:
plt.plot(df_stock.index, df_stock['4. close'].values, lw=3)
@@ -82,7 +83,7 @@ def price_target_from_analysts(l_args, df_stock, s_ticker, s_start, s_interval):
pd.set_option('display.max_colwidth', -1)
print(df_analyst_data.sort_index(ascending=False).head(ns_parser.n_num).to_string())
print("")
except:
print("")
return
@@ -90,8 +91,8 @@ def price_target_from_analysts(l_args, df_stock, s_ticker, s_start, s_interval):
# ----------------------------------------------- ESTIMATES -----------------------------------------------
def estimates(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='estimates',
description="""Yearly and quarter earnings estimates [Source: Business Insider API]""")
parser = argparse.ArgumentParser(prog='est',
description="""Yearly estimates and quarter earnings/revenues [Source: Business Insider]""")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -115,7 +116,7 @@ def estimates(l_args, s_ticker):
l_estimates_year_metric = list()
for estimates_year_metric in text_soup_market_business_insider.findAll('td', {'class': 'table__td black'}):
l_estimates_year_metric.append(estimates_year_metric.text)
l_estimates_quarter_metric = list()
for estimates_quarter_metric in text_soup_market_business_insider.findAll('td', {'class': 'table__td font-color-dim-gray'}):
l_estimates_quarter_metric.append(estimates_quarter_metric.text)
@@ -127,32 +128,32 @@ def estimates(l_args, s_ticker):
n_metrics = 0
b_year = True
for idx, metric_value in enumerate(text_soup_market_business_insider.findAll('td', {'class': 'table__td text-right'})):
if b_year:
# YEAR metrics
l_metrics.append(metric_value.text.strip())
# Check if we have processed all year metrics
if n_metrics > len(l_estimates_year_metric)-1:
b_year = False
n_metrics = 0
l_metrics = list()
idx_y = idx
# Add value to dictionary
if (idx+1)%len(l_estimates_year_header) == 0:
d_metric_year[l_estimates_year_metric[n_metrics]] = l_metrics
l_metrics = list()
n_metrics += 1
if not b_year:
if not b_year:
# QUARTER metrics
l_metrics.append(metric_value.text.strip())
# Check if we have processed all quarter metrics
if n_metrics > len(l_estimates_quarter_metric)-1:
break
# Add value to dictionary
if (idx-idx_y+1)%len(l_estimates_quarter_header) == 0:
if n_metrics < 4:
@@ -177,7 +178,7 @@ def estimates(l_args, s_ticker):
l_date.append('ending ' + re.split(' ending',quarter_title)[1].strip())
else:
l_date.append('-')
df_quarter_earnings.columns = l_quarter
df_quarter_earnings.loc["Date"] = l_date
df_quarter_earnings = df_quarter_earnings.reindex(["Date", "No. of Analysts", "Average Estimate", "Year Ago", "Publish Date"])
@@ -197,7 +198,7 @@ def estimates(l_args, s_ticker):
print(text_soup_market_business_insider.find('div', {'class': "text_right instrument-description"}).text.strip())
print("")
except:
print("")
return
@@ -205,9 +206,10 @@ def estimates(l_args, s_ticker):
# ----------------------------------------------- INSIDER_ACTIVITY -----------------------------------------------
def insider_activity(l_args, df_stock, s_ticker, s_start, s_interval):
parser = argparse.ArgumentParser(prog='insider_activity',
description="""Insider activity over time [Source: Business Insider API]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=10, help='Number of latest insider activity')
parser = argparse.ArgumentParser(prog='ins',
description="""Prints insider activity over time [Source: Business Insider]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=10,
help='number of latest insider activity.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -218,7 +220,7 @@ def insider_activity(l_args, df_stock, s_ticker, s_start, s_interval):
url_market_business_insider = f"https://markets.businessinsider.com/stocks/{s_ticker.lower()}-stock"
text_soup_market_business_insider = BeautifulSoup(requests.get(url_market_business_insider).text, "lxml")
d_insider = dict()
l_insider_vals = list()
for idx, insider_val in enumerate(text_soup_market_business_insider.findAll('td', {'class':"table__td text-center"})):
@@ -248,7 +250,7 @@ def insider_activity(l_args, df_stock, s_ticker, s_start, s_interval):
if s_interval == "1440min":
plt.plot(df_stock.index, df_stock['5. adjusted close'].values, lw=3)
else: # Intraday
else: # Intraday
plt.plot(df_stock.index, df_stock['4. close'].values, lw=3)
plt.title(f"{s_ticker.upper()} (Time Series) and Price Target")
@@ -269,33 +271,33 @@ def insider_activity(l_args, df_stock, s_ticker, s_start, s_interval):
ind_dt = ind
else:
ind_dt = get_next_stock_market_days(ind, 1)[0]
n_stock_price = 0
if s_interval == "1440min":
n_stock_price = df_stock['5. adjusted close'][ind_dt]
n_stock_price = df_stock['5. adjusted close'][ind_dt]
else:
n_stock_price = df_stock['4. close'][ind_dt]
plt.vlines(x=ind_dt,
ymin= n_stock_price + n_proportion * float(df_insider[df_insider['Type'] == 'Sell'].groupby(by=['Date']).sum()['Trade'][ind]),
ymax= n_stock_price,
plt.vlines(x=ind_dt,
ymin= n_stock_price + n_proportion * float(df_insider[df_insider['Type'] == 'Sell'].groupby(by=['Date']).sum()['Trade'][ind]),
ymax= n_stock_price,
colors='red', ls='-', lw=5)
for ind in df_insider[df_insider['Type'] == 'Buy'].groupby(by=['Date']).sum().index:
if ind in df_stock.index:
ind_dt = ind
else:
ind_dt = get_next_stock_market_days(ind, 1)[0]
n_stock_price = 0
if s_interval == "1440min":
n_stock_price = df_stock['5. adjusted close'][ind_dt]
n_stock_price = df_stock['5. adjusted close'][ind_dt]
else:
n_stock_price = df_stock['4. close'][ind_dt]
plt.vlines(x=ind_dt,
ymin=n_stock_price,
ymax=n_stock_price + n_proportion * float(df_insider[df_insider['Type'] == 'Buy'].groupby(by=['Date']).sum()['Trade'][ind]),
plt.vlines(x=ind_dt,
ymin=n_stock_price,
ymax=n_stock_price + n_proportion * float(df_insider[df_insider['Type'] == 'Buy'].groupby(by=['Date']).sum()['Trade'][ind]),
colors='green', ls='-', lw=5)
plt.grid(b=True, which='major', color='#666666', linestyle='-')
@@ -305,12 +307,12 @@ def insider_activity(l_args, df_stock, s_ticker, s_start, s_interval):
l_names = list()
for s_name in text_soup_market_business_insider.findAll('a', {'onclick':"silentTrackPI()"}):
l_names.append(s_name.text.strip())
l_names.append(s_name.text.strip())
df_insider['Insider'] = l_names
print(df_insider.sort_index(ascending=False).head(n=ns_parser.n_num).to_string())
print("")
except:
print("")
return

View File

@@ -53,8 +53,8 @@ def print_due_diligence(s_ticker, s_start, s_interval):
def dd_menu(df_stock, s_ticker, s_start, s_interval):
# Add list of arguments that the due diligence parser accepts
dd_parser = argparse.ArgumentParser(prog='due_diligence', add_help=False)
dd_parser.add_argument('cmd', choices=['info', 'help', 'q', 'quit',
dd_parser = argparse.ArgumentParser(prog='dd', add_help=False)
dd_parser.add_argument('cmd', choices=['info', 'help', 'q', 'quit',
'red', # Reddit
'short', # Quandl
'rating', # FMP
@@ -68,7 +68,7 @@ def dd_menu(df_stock, s_ticker, s_start, s_interval):
while True:
# Get input command from user
as_input = input('> ')
# Parse due diligence command of the list of possible commands
try:
(ns_known_args, l_args) = dd_parser.parse_known_args(as_input.split())
@@ -76,7 +76,7 @@ def dd_menu(df_stock, s_ticker, s_start, s_interval):
except SystemExit:
print("The command selected doesn't exist\n")
continue
if ns_known_args.cmd == 'help':
print_due_diligence(s_ticker, s_start, s_interval)
@@ -91,7 +91,7 @@ def dd_menu(df_stock, s_ticker, s_start, s_interval):
# REDDIT API
elif ns_known_args.cmd == 'red':
r_api.due_diligence(l_args, s_ticker)
# FINVIZ API
elif ns_known_args.cmd == 'insider':
fvz_api.insider(l_args, s_ticker)

View File

@@ -8,11 +8,11 @@ import pandas as pd
# ---------------------------------------------------- RATING ----------------------------------------------------
def rating(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='rating',
description="""Based on specific ratios, provides information whether the company
parser = argparse.ArgumentParser(prog='rating',
description="""Based on specific ratios, prints information whether the company
is a (strong) buy, neutral or a (strong) sell. The following fields are expected:
P/B, ROA, DCF, P/E, ROE, and D/E. [Source: Financial Modeling Prep API]""")
P/B, ROA, DCF, P/E, ROE, and D/E. [Source: Financial Modeling Prep]""")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -29,4 +29,3 @@ def rating(l_args, s_ticker):
print("")
return

View File

@@ -5,12 +5,13 @@ import pandas as pd
# ---------------------------------------------------- INSIDER ----------------------------------------------------
def insider(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='insider',
description="""Gives information about inside traders. The following fields are expected:
Date, Relationship, Transaction, #Shares, Cost, Value ($), #Shares Total, Insider Trading,
SEC Form 4. [Source: Finviz API]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=10, help='Number of latest inside traders')
parser = argparse.ArgumentParser(prog='insider',
description="""Prints information about inside traders. The following fields are expected:
Date, Relationship, Transaction, #Shares, Cost, Value ($), #Shares Total, Insider Trading,
SEC Form 4. [Source: Finviz]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=10,
help='number of latest inside traders.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -21,7 +22,7 @@ def insider(l_args, s_ticker):
d_finviz_insider = finviz.get_insider(s_ticker)
df_fa = pd.DataFrame.from_dict(d_finviz_insider)
df_fa.set_index("Date", inplace=True)
df_fa.set_index("Date", inplace=True)
df_fa = df_fa[['Relationship', 'Transaction', '#Shares', 'Cost', 'Value ($)', '#Shares Total', 'Insider Trading', 'SEC Form 4']]
print(df_fa.head(n=ns_parser.n_num))
@@ -34,11 +35,12 @@ def insider(l_args, s_ticker):
# ---------------------------------------------------- NEWS ----------------------------------------------------
def news(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='news',
description="""Gives latest news about company. The following fields are expected:
Title, and http link. [Source: Finviz API]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=5, help='Number of latest inside traders')
parser = argparse.ArgumentParser(prog='news',
description="""Prints latest news about company, including title and web link.
[Source: Finviz]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=5,
help='Number of latest news being printed.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -53,7 +55,7 @@ def news(l_args, s_ticker):
print(f"-> {s_news_title}")
print(f"{s_news_link}\n")
i+=1
if i > (ns_parser.n_num-1):
break
@@ -66,11 +68,11 @@ def news(l_args, s_ticker):
# ---------------------------------------------------- ANALYST ----------------------------------------------------
def analyst(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='analyst',
description="""Gives analyst prices and ratings of the company. The following fields
parser = argparse.ArgumentParser(prog='analyst',
description="""Print analyst prices and ratings of the company. The following fields
are expected: date, analyst, category, price from, price to, and rating.
[Source: Finviz API]""")
[Source: Finviz]""")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -80,9 +82,8 @@ def analyst(l_args, s_ticker):
d_finviz_analyst_price = finviz.get_analyst_price_targets(s_ticker)
df_fa = pd.DataFrame.from_dict(d_finviz_analyst_price)
df_fa.set_index("date", inplace=True)
df_fa.set_index("date", inplace=True)
print(df_fa)
print("")
except:

View File

@@ -8,12 +8,13 @@ from helper_funcs import *
# ---------------------------------------------------- SEC FILLINGS ----------------------------------------------------
def sec_fillings(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='sec',
description="""Gives SEC filings of the company. The following fields
parser = argparse.ArgumentParser(prog='sec',
description="""Prints SEC filings of the company. The following fields
are expected: Filing Date, Document Date, Type, Category, Amended, and Link.
[Source: Market Watch BS]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=5, help='Number of latest SEC filings')
[Source: Market Watch]""")
parser.add_argument('-n', "--num", action="store", dest="n_num", type=check_positive, default=5,
help='number of latest SEC filings.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -25,7 +26,7 @@ def sec_fillings(l_args, s_ticker):
pd.set_option('display.max_colwidth', -1)
url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/secfilings"
text_soup_financials = BeautifulSoup(requests.get(url_financials).text,"lxml")
a_financials_header = list()
@@ -33,20 +34,20 @@ def sec_fillings(l_args, s_ticker):
soup_financials = text_soup_financials.findAll('tr', {'class': 'table__row'})
for financials_info in soup_financials:
a_financials = financials_info.text.split('\n')
# If header has been processed and dataframe created ready to populate the SEC information
if b_ready_to_process_info:
l_financials_info = [a_financials[2]]
l_financials_info = [a_financials[2]]
l_financials_info.extend(a_financials[5:-1])
l_financials_info.append(financials_info.a['href'])
# Append data values to financials
df_financials.loc[len(df_financials.index)] = l_financials_info
if 'Filing Date' in a_financials:
l_financials_header = [a_financials[2]]
l_financials_header = [a_financials[2]]
l_financials_header.extend(a_financials[5:-1])
l_financials_header.append('Link')
df_financials = pd.DataFrame(columns=l_financials_header)
df_financials.set_index('Filing Date')
b_ready_to_process_info = True
@@ -56,7 +57,7 @@ def sec_fillings(l_args, s_ticker):
print(df_financials.head(n=ns_parser.n_num).to_string())
print("")
except:
print("")
return
@@ -64,13 +65,17 @@ def sec_fillings(l_args, s_ticker):
# ---------------------------------------------------- Sean Seah Warnings ----------------------------------------------------
def sean_seah_warnings(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='warnings',
parser = argparse.ArgumentParser(prog='warnings',
description="""Sean Seah warnings. Check: Consistent historical earnings per share;
Consistently high return on equity; Consistently high return on assets; 5x Net
Income > Long-Term Debt; and Interest coverage ratio more than 3. [Source: Market Watch BS]""")
Consistently high return on equity; Consistently high return on assets; 5x Net
Income > Long-Term Debt; and Interest coverage ratio more than 3. See
https://www.drwealth.com/gone-fishing-with-buffett-by-sean-seah/comment-page-1/
[Source: Market Watch]""")
parser.add_argument('-i', "--info", action="store_true", default=False, dest="b_info", help='Give Sean Seah books information')
parser.add_argument('-d', "--debug", action="store_true", default=False, dest="b_debug", help='Show data used to calculate warnings')
parser.add_argument('-i', "--info", action="store_true", default=False, dest="b_info",
help='provide more information about Sean Seah warning rules.')
parser.add_argument('-d', "--debug", action="store_true", default=False, dest="b_debug",
help='print insights into warnings calculation.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -88,7 +93,7 @@ def sean_seah_warnings(l_args, s_ticker):
line = fp.readline()
print("")
# From INCOME STATEMENT, get: 'EPS (Basic)', 'Net Income', 'Interest Expense', 'EBITDA'
# From INCOME STATEMENT, get: 'EPS (Basic)', 'Net Income', 'Interest Expense', 'EBITDA'
url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/income"
text_soup_financials = BeautifulSoup(requests.get(url_financials).text,"lxml")
@@ -103,7 +108,7 @@ def sean_seah_warnings(l_args, s_ticker):
soup_financials += text_soup_financials.findAll('tr', {'class': 'table__row is-highlighted'})
for financials_info in soup_financials:
a_financials_info = financials_info.text.split('\n')
l_financials = [a_financials_info[2]]
l_financials = [a_financials_info[2]]
l_financials.extend(a_financials_info[5:-2])
# Append data values to financials
df_financials.loc[len(df_financials.index)] = l_financials
@@ -114,7 +119,7 @@ def sean_seah_warnings(l_args, s_ticker):
df_sean_seah = df_financials.loc[['EPS (Basic)', 'Net Income', 'Interest Expense', 'EBITDA']]
# From BALANCE SHEET, get: 'Liabilities & Shareholders\' Equity', 'Long-Term Debt'
url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/balance-sheet"
url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/balance-sheet"
text_soup_financials = BeautifulSoup(requests.get(url_financials).text,"lxml")
# Define financials columns
@@ -130,7 +135,7 @@ def sean_seah_warnings(l_args, s_ticker):
soup_financials += text_soup_financials.findAll('tr', {'class': 'table__row is-highlighted'})
for financials_info in soup_financials:
a_financials_info = financials_info.text.split('\n')
l_financials = [a_financials_info[2]]
l_financials = [a_financials_info[2]]
l_financials.extend(a_financials_info[5:-2])
# Append data values to financials
df_financials.loc[len(df_financials.index)] = l_financials

View File

@@ -10,12 +10,14 @@ from helper_funcs import *
# -------------------------------------------------------- SHORT_INTEREST --------------------------------------------------------
def short_interest(l_args, s_ticker, s_start):
parser = argparse.ArgumentParser(prog='short',
description="""Short interest corresponds to the number of shares that have been sold short
but have not yet been covered or closed out. [Source: Quandl API]""")
parser = argparse.ArgumentParser(prog='short',
description="""Plots the short interest of a stock. This corresponds to the number of shares that
have been sold short but have not yet been covered or closed out. Either NASDAQ or NYSE [Source: Quandl]""")
parser.add_argument('-n', "--nyse", action="store_true", default=False, dest="b_nyse", help='Data from NYSE')
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=10, help='Number of latest days to see data')
parser.add_argument('-n', "--nyse", action="store_true", default=False, dest="b_nyse",
help='data from NYSE flag.')
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=10,
help='number of latest days to print data.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -45,7 +47,7 @@ def short_interest(l_args, s_ticker, s_start):
ax.set_title(f"{('NASDAQ', 'NYSE')[ns_parser.b_nyse]} Short Interest on {s_ticker} from {s_start.date()}")
else:
ax.set_title(f"{('NASDAQ', 'NYSE')[ns_parser.b_nyse]} Short Interest on {s_ticker}")
ax.legend(labels=['Short Volume', 'Total Volume'])
ax.tick_params(axis='both', which='major')
ax.yaxis.set_major_formatter(ticker.EngFormatter())
@@ -56,7 +58,7 @@ def short_interest(l_args, s_ticker, s_start):
ax_twin.tick_params(axis='y', which='major', color='green')
ax_twin.yaxis.set_major_formatter(ticker.FormatStrFormatter('%.0f%%'))
plt.xlim([df_short_interest.index[0], df_short_interest.index[-1]])
df_short_interest['% of Volume Shorted'] = df_short_interest['% of Volume Shorted'].apply(lambda x: f'{x/100:.2%}')
df_short_interest = df_short_interest.applymap(lambda x: long_number_format(x)).sort_index(ascending=False)
@@ -69,4 +71,3 @@ def short_interest(l_args, s_ticker, s_start):
except:
print("")
return

View File

@@ -14,15 +14,16 @@ import config_terminal as cfg
# -------------------------------------------------------------------------------------------------------------------
def due_diligence(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='dd',
description=""" Search for a stock's due diligence [Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5,
help='Limit of posts with the watchlist word')
parser = argparse.ArgumentParser(prog='red',
description="""Print top stock's due diligence from other users. [Source: Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5,
help='limit of posts to retrieve.')
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=3,
help="Look for a watchlist created on the past n days")
help="number of prior days to look for.")
parser.add_argument('-a', "--all", action="store_true", dest="b_all", default=False,
help=""" Search through all flairs (apart from Yolo and Meme), otherwise we focus on the
flairs: DD, technical analysis, Catalyst, News, Advice, Chart """)
help="""search through all flairs (apart from Yolo and Meme), otherwise we focus on
specific flairs: DD, technical analysis, Catalyst, News, Advice, Chart """)
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -54,12 +55,12 @@ def due_diligence(l_args, s_ticker):
if submission:
# Get more information about post using PRAW api
submission = praw_api.submission(id=submission.id)
# Ensure that the post hasn't been removed in the meanwhile
if not submission.removed_by_category:
# Either just filter out Yolo, and Meme flairs, or focus on DD, based on b_DD flag
if (submission.link_flair_text in l_flair_text,
if (submission.link_flair_text in l_flair_text,
submission.link_flair_text not in ['Yolo', 'Meme'])[ns_parser.b_all]:
# Refactor data
@@ -87,20 +88,20 @@ def due_diligence(l_args, s_ticker):
print(f"{s_datetime} - {submission.title}")
print(f"{s_link}")
t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"])
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards])
print(t_post)
print("\n")
# If needed, submission.comments could give us the top comments
# Increment count of valid posts found
n_flair_posts_found += 1
# Check if number of wanted posts found has been reached
if n_flair_posts_found > ns_parser.n_limit-1:
break
# Check if search_submissions didn't get anymore posts
else:
break

View File

@@ -75,10 +75,10 @@ def print_fundamental_analysis(s_ticker, s_start, s_interval):
# ---------------------------------------------------- INFO ----------------------------------------------------
def info(l_args, s_ticker):
parser = argparse.ArgumentParser(prog='info',
parser = argparse.ArgumentParser(prog='info',
description="""Provides information about main key metrics. Namely: EBITDA,
EPS, P/E, PEG, FCF, P/B, ROE, DPR, P/S, Dividend Yield Ratio, D/E, and Beta.""")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -96,13 +96,13 @@ def info(l_args, s_ticker):
except:
print("ERROR!\n")
return
# ---------------------------------------------------- MENU ----------------------------------------------------
def fa_menu(s_ticker, s_start, s_interval):
# Add list of arguments that the fundamental analysis parser accepts
fa_parser = argparse.ArgumentParser(prog='fundamental_analysis', add_help=False)
fa_parser = argparse.ArgumentParser(prog='fa', add_help=False)
fa_parser.add_argument('cmd', choices=['help', 'q', 'quit', #
'screener', # Finviz
'mgmt', # Business Insider
@@ -118,7 +118,7 @@ def fa_menu(s_ticker, s_start, s_interval):
while True:
# Get input command from user
as_input = input('> ')
# Parse fundamental analysis command of the list of possible commands
try:
(ns_known_args, l_args) = fa_parser.parse_known_args(as_input.split())
@@ -129,7 +129,7 @@ def fa_menu(s_ticker, s_start, s_interval):
#if ns_known_args.cmd == 'info':
# info(l_args, s_ticker)
if ns_known_args.cmd == 'help':
print_fundamental_analysis(s_ticker, s_start, s_interval)
@@ -180,7 +180,7 @@ def fa_menu(s_ticker, s_start, s_interval):
elif ns_known_args.cmd == 'cal':
yf_api.calendar_earnings(l_args, s_ticker)
# ALPHA VANTAGE API
elif ns_known_args.cmd == 'overview':
av_api.overview(l_args, s_ticker)
@@ -204,7 +204,7 @@ def fa_menu(s_ticker, s_start, s_interval):
elif ns_known_args.cmd == 'quote':
fmp_api.quote(l_args, s_ticker)
elif ns_known_args.cmd == 'enterprise':
fmp_api.enterprise(l_args, s_ticker)

View File

@@ -44,13 +44,13 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock):
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
# Daily
if s_interval == "1440min":
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=ns_parser.s_ticker, outputsize='full')
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=ns_parser.s_ticker, outputsize='full')
# Intraday
else:
df_stock, d_stock_metadata = ts.get_intraday(symbol=ns_parser.s_ticker, outputsize='full', interval=s_interval)
else:
df_stock, d_stock_metadata = ts.get_intraday(symbol=ns_parser.s_ticker, outputsize='full', interval=s_interval)
df_stock.sort_index(ascending=True, inplace=True)
except:
print("Either the ticker or the API_KEY are invalids. Try again!")
return [s_ticker, s_start, s_interval, df_stock]
@@ -72,7 +72,7 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock):
def view(l_args, s_ticker, s_start, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='view', description='Visualise historical data of a stock. An alpha_vantage key is necessary.')
if s_ticker:
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", default=s_ticker, help='Stock ticker')
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", default=s_ticker, help='Stock ticker')
else:
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", required=True, help='Stock ticker')
parser.add_argument('-s', "--start", type=valid_date, dest="s_start_date", help="The starting date (format YYYY-MM-DD) of the stock")
@@ -85,7 +85,7 @@ def view(l_args, s_ticker, s_start, s_interval, df_stock):
except SystemExit:
print("")
return
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}")
@@ -105,8 +105,8 @@ def view(l_args, s_ticker, s_start, s_interval, df_stock):
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=s_ticker, outputsize='full')
# Intraday
else:
df_stock, d_stock_metadata = ts.get_intraday(symbol=s_ticker, outputsize='full', interval=s_interval)
df_stock, d_stock_metadata = ts.get_intraday(symbol=s_ticker, outputsize='full', interval=s_interval)
except:
print("Either the ticker or the API_KEY are invalids. Try again!")
return
@@ -125,7 +125,7 @@ def view(l_args, s_ticker, s_start, s_interval, df_stock):
print("An index bigger than 4 was given, which is wrong. Try again")
return
# Append last column of df to be filtered which corresponds to: 6. Volume
ln_col_idx.append(5)
ln_col_idx.append(5)
# Intraday
else:
# The default doesn't exist for intradaily data
@@ -138,7 +138,7 @@ def view(l_args, s_ticker, s_start, s_interval, df_stock):
print("An index bigger than 3 was given, which is wrong. Try again")
return
# Append last column of df to be filtered which corresponds to: 5. Volume
ln_col_idx.append(4)
ln_col_idx.append(4)
# Plot view of the stock
plot_view_stock(df_stock.iloc[:, ln_col_idx], ns_parser.s_ticker)
@@ -155,7 +155,7 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open):
print(" clear clear a specific stock ticker from analysis")
print(" load load a specific stock ticker for analysis")
print(" view view and load a specific stock ticker for technical analysis")
s_intraday = (f'Intraday {s_interval}', 'Daily')[s_interval == "1440min"]
if s_ticker and s_start:
print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
@@ -179,7 +179,7 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open):
# -----------------------------------------------------------------------------------------------------------------------
def main():
""" Main function of the program
"""
"""
s_ticker = ""
s_start = ""
@@ -188,12 +188,12 @@ def main():
s_interval = "1440min"
# Set stock by default to speed up testing
s_ticker = "AAPL"
s_ticker = "BB"
s_start = datetime.strptime("2020-06-04", "%Y-%m-%d")
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=s_ticker, outputsize='full')
df_stock.sort_index(ascending=True, inplace=True)
df_stock = df_stock[s_start:]
df_stock = df_stock[s_start:]
# Delete above in the future
# Add list of arguments that the main parser accepts
@@ -201,7 +201,7 @@ def main():
menu_parser.add_argument('opt', choices=['help', 'quit', 'q',
'clear', 'load', 'view',
'disc', 'sen', 'res', 'fa', 'ta', 'dd', 'pred'])
# Print first welcome message and help
print("\nWelcome to Didier's Gamestonk Terminal\n")
print_help(s_ticker, s_start, s_interval, b_is_stock_market_open())
@@ -215,7 +215,7 @@ def main():
if not len(as_input):
print("")
continue
# Parse main command of the list of possible commands
try:
(ns_known_args, l_args) = menu_parser.parse_known_args(as_input.split())
@@ -230,7 +230,7 @@ def main():
elif (ns_known_args.opt == 'quit') or (ns_known_args.opt == 'q'):
print("Hope you made money today. Good bye my lover, good bye my friend.\n")
return
elif ns_known_args.opt == 'clear':
print("Clearing stock ticker to be used for analysis")
s_ticker = ""
@@ -304,7 +304,7 @@ def main():
# PREDICTION TECHNIQUES
elif ns_known_args.opt == 'pred':
if s_interval == "1440min":
b_quit = pm.pred_menu(df_stock, s_ticker, s_start, s_interval)
# If stock data is intradaily, we need to get data again as prediction techniques work on daily adjusted data

View File

@@ -2,7 +2,10 @@
from pytz import timezone
from holidays import US as holidaysUS
from datetime import datetime, time as Time
import re
import numpy as np
import sys
import iso8601
import matplotlib
import matplotlib.pyplot as plt
from datetime import timedelta
@@ -147,11 +150,11 @@ def long_number_format(num):
magnitude = 0
while abs(num) >= 1000:
magnitude += 1
num /= 1000.0
num /= 1000.0
if num.is_integer():
return '%d%s' % (num, ['', ' K', ' M', ' B', ' T', ' P'][magnitude])
else:
return '%.3f%s' % (num, ['', ' K', ' M', ' B', ' T', ' P'][magnitude])
return '%.3f%s' % (num, ['', ' K', ' M', ' B', ' T', ' P'][magnitude])
if isinstance(num, int):
num = str(num)
if num.lstrip("-").isdigit():
@@ -160,11 +163,11 @@ def long_number_format(num):
magnitude = 0
while abs(num) >= 1000:
magnitude += 1
num /= 1000.0
num /= 1000.0
if num.is_integer():
return '%d%s' % (num, ['', ' K', ' M', ' B', ' T', ' P'][magnitude])
else:
return '%.3f%s' % (num, ['', ' K', ' M', ' B', ' T', ' P'][magnitude])
return '%.3f%s' % (num, ['', ' K', ' M', ' B', ' T', ' P'][magnitude])
return num
@@ -175,10 +178,10 @@ def clean_data_values_to_float(val):
val = val[1:]
if val.endswith(')'):
val = val[:-1]
if val == '-':
val = '0'
# Convert percentage to decimal
if val.endswith('%'):
val = float(val[:-1])/100.0
@@ -206,9 +209,9 @@ def int_or_round_float(x):
# -----------------------------------------------------------------------------------------------------------------------
def divide_chunks(l, n):
# looping till length l
for i in range(0, len(l), n):
def divide_chunks(l, n):
# looping till length l
for i in range(0, len(l), n):
yield l[i:i + n]
@@ -230,5 +233,37 @@ def get_next_stock_market_days(last_stock_day, n_next_days):
else:
n_days += 1
l_pred_days.append(last_stock_day)
return l_pred_days
# -----------------------------------------------------------------------------------------------------------------------
def get_data(tweet):
if '+' in tweet['created_at']:
s_datetime = tweet['created_at'].split(' +')[0]
else:
s_datetime = iso8601.parse_date(tweet['created_at']).strftime("%Y-%m-%d %H:%M:%S")
if 'full_text' in tweet.keys():
s_text = tweet['full_text']
else:
s_text = tweet['text']
data = {'created_at': s_datetime,
'text': s_text }
return data
# -----------------------------------------------------------------------------------------------------------------------
def clean_tweet(tweet, s_ticker):
whitespace = re.compile(r"\s+")
web_address = re.compile(r"(?i)http(s):\/\/[a-z0-9.~_\-\/]+")
ticker = re.compile(r"(?i)@{}(?=\b)".format(s_ticker))
user = re.compile(r"(?i)@[a-z0-9_]+")
tweet = whitespace.sub(' ', tweet)
tweet = web_address.sub('', tweet)
tweet = ticker.sub(s_ticker, tweet)
tweet = user.sub('', tweet)
return tweet

View File

@@ -10,25 +10,25 @@ from statsmodels.tsa.arima.model import ARIMA
# -------------------------------------------------- ARIMA --------------------------------------------------
def arima(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='arima',
description="""In statistics and econometrics, and in particular in time
series analysis, an autoregressive integrated moving average (ARIMA) model
is a generalization of an autoregressive moving average (ARMA) model. Both
of these models are fitted to time series data either to better understand
the data or to predict future points in the series (forecasting).
ARIMA(p,d,q) where parameters p, d, and q are non-negative integers, p is
the order (number of time lags) of the autoregressive model, d is the degree
of differencing (the number of times the data have had past values subtracted),
description="""In statistics and econometrics, and in particular in time
series analysis, an autoregressive integrated moving average (ARIMA) model
is a generalization of an autoregressive moving average (ARMA) model. Both
of these models are fitted to time series data either to better understand
the data or to predict future points in the series (forecasting).
ARIMA(p,d,q) where parameters p, d, and q are non-negative integers, p is
the order (number of time lags) of the autoregressive model, d is the degree
of differencing (the number of times the data have had past values subtracted),
and q is the order of the moving-average model.""")
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=5,
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=5,
help='prediction days.')
parser.add_argument('-i', "--ic", action="store", dest="s_ic", type=str, default='aic',
parser.add_argument('-i', "--ic", action="store", dest="s_ic", type=str, default='aic',
choices=['aic', 'aicc', 'bic', 'hqic', 'oob'], help='information criteria.')
parser.add_argument('-s', "--seasonal", action="store_true", default=False, dest="b_seasonal",
help='weekly seasonality flag.')
parser.add_argument('-o', "--order", action="store", dest="s_order", type=str,
help='arima model order.')
parser.add_argument('-r', "--results", action="store_true", dest="b_results", default=False,
parser.add_argument('-s', "--seasonal", action="store_true", default=False, dest="b_seasonal",
help='Use weekly seasonal data.')
parser.add_argument('-o', "--order", action="store", dest="s_order", type=str,
help='arima model order (p,d,q) in format: pdq.')
parser.add_argument('-r', "--results", action="store_true", dest="b_results", default=False,
help='results about ARIMA summary flag.')
try:

View File

@@ -45,14 +45,14 @@ def print_prediction(s_ticker, s_start, s_interval):
print(" lstm Long-Short Term Memory")
print("")
# ---------------------------------------------------- MENU ----------------------------------------------------
def pred_menu(df_stock, s_ticker, s_start, s_interval):
# Add list of arguments that the prediction techniques parser accepts
pred_parser = argparse.ArgumentParser(prog='technical_analysis', add_help=False)
pred_parser = argparse.ArgumentParser(prog='pred', add_help=False)
pred_parser.add_argument('cmd', choices=['help', 'q', 'quit',
'sma', 'knn',
'sma', 'knn',
'linear', 'quadratic', 'cubic', 'regression',
'arima', 'prophet', 'mlp', 'rnn', 'lstm'])
@@ -62,7 +62,7 @@ def pred_menu(df_stock, s_ticker, s_start, s_interval):
while True:
# Get input command from user
as_input = input('> ')
# Parse prediction techniques command of the list of possible commands
try:
(ns_known_args, l_args) = pred_parser.parse_known_args(as_input.split())

View File

@@ -18,11 +18,11 @@ def get_last_time_market_was_open(dt):
# Check if it is a weekend
if dt.date().weekday() > 4:
dt = get_last_time_market_was_open(dt - timedelta(hours=24))
# Check if it is a holiday
if dt.strftime('%Y-%m-%d') in holidaysUS():
dt = get_last_time_market_was_open(dt - timedelta(hours=24))
dt = dt.replace(hour=21, minute=0, second=0)
return dt
@@ -30,9 +30,10 @@ def get_last_time_market_was_open(dt):
# -------------------------------------------------------------------------------------------------------------------
def watchlist(l_args):
parser = argparse.ArgumentParser(prog='watchlist',
description=""" Show other users watchlist [Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5, help='Limit of posts with watchlists retrieved')
parser = argparse.ArgumentParser(prog='watchlist',
description="""Print other users watchlist. [Source: Reddit]""")
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5,
help='limit of posts with watchlists retrieved.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -61,21 +62,21 @@ def watchlist(l_args):
subreddit=l_sub_reddits,
q='WATCHLIST|Watchlist|watchlist',
filter=['id'])
n_flair_posts_found = 0
while True:
submission = next(submissions, None)
if submission:
# Get more information about post using PRAW api
submission = praw_api.submission(id=submission.id)
# Ensure that the post hasn't been removed by moderator in the meanwhile,
#that there is a description and it's not just an image, that the flair is
#meaningful, and that we aren't re-considering same author's watchlist
if not submission.removed_by_category and submission.selftext \
and submission.link_flair_text not in ['Yolo', 'Meme'] \
and submission.author.name not in l_watchlist_author:
# Make sure there is at least 1 ticker found on the post text
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.selftext))
if l_tickers_found:
@@ -120,18 +121,18 @@ def watchlist(l_args):
print(f"\n{s_datetime} - {submission.title}")
print(f"{s_link}")
t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"])
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards])
print(t_post)
print("\n")
print("")
# Increment count of valid posts found
n_flair_posts_found += 1
# Check if number of wanted posts found has been reached
if n_flair_posts_found > ns_parser.n_limit-1:
break
# Check if search_submissions didn't get anymore posts
else:
break
@@ -160,15 +161,15 @@ def watchlist(l_args):
# -------------------------------------------------------------------------------------------------------------------
def popular_tickers(l_args):
parser = argparse.ArgumentParser(prog='popular',
parser = argparse.ArgumentParser(prog='popular',
description=""" Latest popular tickers [Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=30,
help='Limit of posts retrieved per sub reddit')
parser.add_argument('-s', "--sub", action="store", dest="s_subreddit", type=str,
help="""Subreddit to look for tickers. Default: pennystocks, RobinHoodPennyStocks, Daytrading,
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=30,
help='limit of posts retrieved per sub reddit.')
parser.add_argument('-s', "--sub", action="store", dest="s_subreddit", type=str,
help="""subreddit to look for tickers. Default: pennystocks, RobinHoodPennyStocks, Daytrading,
StockMarket, stocks, investing, wallstreetbets""")
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=1,
help="Look for the tickers from those n past days")
help="look for the tickers from those n past days.")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -176,7 +177,7 @@ def popular_tickers(l_args):
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}\n")
return
n_ts_after = int((datetime.today() - timedelta(days=ns_parser.n_days)).timestamp())
if ns_parser.s_subreddit:
@@ -211,41 +212,41 @@ def popular_tickers(l_args):
# Get more information about post using PRAW api
submission = praw_api.submission(id=submission.id)
# Ensure that the post hasn't been removed by moderator in the meanwhile,
# Ensure that the post hasn't been removed by moderator in the meanwhile,
#that there is a description and it's not just an image, that the flair is
#meaningful, and that we aren't re-considering same author's content
if not submission.removed_by_category and (submission.selftext or submission.title) \
and submission.link_flair_text not in ['Yolo', 'Meme'] \
and submission.author.name not in l_watchlist_author:
# Make sure there is at least 1 ticker found on the post text
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.selftext))
if not l_tickers_found:
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.title))
if l_tickers_found:
n_tickers += len(l_tickers_found)
# Make sure there is at least 1 ticker found on the post text
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.selftext))
if not l_tickers_found:
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.title))
# Add another author's name to the parsed watchlists
l_watchlist_author.append(submission.author.name)
if l_tickers_found:
# Lookup stock tickers within a watchlist
for key in l_tickers_found:
if key in d_watchlist_tickers:
# Increment stock ticker found
d_watchlist_tickers[key] += 1
else:
# Initialize stock ticker found
d_watchlist_tickers[key] = 1
n_tickers += len(l_tickers_found)
# Add another author's name to the parsed watchlists
l_watchlist_author.append(submission.author.name)
# Lookup stock tickers within a watchlist
for key in l_tickers_found:
if key in d_watchlist_tickers:
# Increment stock ticker found
d_watchlist_tickers[key] += 1
else:
# Initialize stock ticker found
d_watchlist_tickers[key] = 1
# Check if search_submissions didn't get anymore posts
else:
break
print(f" {n_tickers} tickers found.")
lt_watchlist_sorted = sorted(d_watchlist_tickers.items(), key=lambda item: item[1], reverse=True)
print("\nThe following TOP10 tickers have been mentioned in the last 24 hours:")
@@ -265,15 +266,16 @@ def popular_tickers(l_args):
except:
print("")
# -------------------------------------------------------------------------------------------------------------------
def spac(l_args):
parser = argparse.ArgumentParser(prog='spac',
parser = argparse.ArgumentParser(prog='spac',
description=""" Show other users SPACs announcement [Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5, help='Limit of posts with SPACs retrieved')
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5,
help='limit of posts with SPACs retrieved')
parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=5,
help="Look for the tickers from those n past days")
help="look for the tickers from those n past days")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -295,7 +297,7 @@ def spac(l_args):
n_ts_after = int((datetime.today() - timedelta(days=ns_parser.n_days)).timestamp())
l_sub_reddits = ['pennystocks', 'RobinHoodPennyStocks', 'Daytrading', 'StockMarket', 'stocks', 'investing', 'wallstreetbets']
warnings.filterwarnings("ignore") # To avoid printing the warning
psaw_api = PushshiftAPI()
submissions = psaw_api.search_submissions(after=n_ts_after,
@@ -308,14 +310,14 @@ def spac(l_args):
if submission:
# Get more information about post using PRAW api
submission = praw_api.submission(id=submission.id)
# Ensure that the post hasn't been removed by moderator in the meanwhile,
#that there is a description and it's not just an image, that the flair is
#meaningful, and that we aren't re-considering same author's watchlist
if not submission.removed_by_category and submission.selftext \
and submission.link_flair_text not in ['Yolo', 'Meme'] \
and submission.author.name not in l_watchlist_author:
# Make sure there is at least 1 ticker found on the post text
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.selftext))
if not l_tickers_found:
@@ -362,18 +364,18 @@ def spac(l_args):
print(f"{s_datetime} - {submission.title}")
print(f"{s_link}")
t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"])
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards])
print(t_post)
print("\n")
# Increment count of valid posts found
n_flair_posts_found += 1
# Check if number of wanted posts found has been reached
if n_flair_posts_found > ns_parser.n_limit-1:
break
# Check if search_submissions didn't get anymore posts
else:
break
@@ -402,10 +404,12 @@ def spac(l_args):
# -------------------------------------------------------------------------------------------------------------------
def spac_community(l_args):
parser = argparse.ArgumentParser(prog='spac_c',
description=""" Show other users SPACs announcement under subreddit SPACs [Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=10, help='Limit of posts with SPACs retrieved')
parser.add_argument('-p', "--popular", action="store_true", default=False, dest="b_popular", help='If popular, the posts retrieved are based on score rather than time')
parser = argparse.ArgumentParser(prog='spac_c',
description="""Print other users SPACs announcement under subreddit 'SPACs' [Source: Reddit]""")
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=10,
help='limit of posts with SPACs retrieved')
parser.add_argument('-p', "--popular", action="store_true", default=False, dest="b_popular",
help='popular flag, if true the posts retrieved are based on score rather than time')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -437,18 +441,18 @@ def spac_community(l_args):
if submission:
# Get more information about post using PRAW api
submission = praw_api.submission(id=submission.id)
# Ensure that the post hasn't been removed by moderator in the meanwhile,
#that there is a description and it's not just an image, that the flair is
#meaningful, and that we aren't re-considering same author's watchlist
if not submission.removed_by_category and submission.selftext \
and submission.author.name not in l_watchlist_author: # and submission.link_flair_text not in ['Yolo', 'Meme'] \
# Make sure there is at least 1 ticker found on the post text
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.selftext))
if not l_tickers_found:
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.title))
if l_tickers_found:
# Add another author's name to the parsed watchlists
l_watchlist_author.append(submission.author.name)
@@ -490,11 +494,11 @@ def spac_community(l_args):
print(f"{s_datetime} - {submission.title}")
print(f"{s_link}")
t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"])
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards])
print(t_post)
print("\n")
# Check if search_submissions didn't get anymore posts
else:
break
@@ -516,17 +520,19 @@ def spac_community(l_args):
print("The following stock tickers have been mentioned across the previous SPACs:")
print(s_watchlist_tickers[:-2])
print("")
except:
print("")
# -------------------------------------------------------------------------------------------------------------------
def wsb_community(l_args):
parser = argparse.ArgumentParser(prog='wsb',
description="""Show what WSB gang are up to in subreddit wallstreetbets [Reddit] """)
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=10, help='Limit of posts')
parser.add_argument('-n', "--new", action="store_true", default=False, dest="b_new", help='If new, the posts retrieved are based on more recent rather than score')
parser = argparse.ArgumentParser(prog='wsb',
description="""Print what WSB gang are up to in subreddit wallstreetbets. [Source: Reddit]""")
parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive,
default=10, help='limit of posts to print.')
parser.add_argument('-n', "--new", action="store_true", default=False, dest="b_new",
help='new flag, if true the posts retrieved are based on being more recent rather than their score.')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -542,9 +548,7 @@ def wsb_community(l_args):
password=cfg.API_REDDIT_PASSWORD)
d_submission = {}
d_watchlist_tickers = {}
l_watchlist_links = list()
l_watchlist_author = list()
psaw_api = PushshiftAPI()
@@ -552,91 +556,52 @@ def wsb_community(l_args):
submissions = praw_api.subreddit('wallstreetbets').new(limit=ns_parser.n_limit)
else:
submissions = praw_api.subreddit('wallstreetbets').hot(limit=ns_parser.n_limit)
while True:
submission = next(submissions, None)
if submission:
# Get more information about post using PRAW api
submission = praw_api.submission(id=submission.id)
# Ensure that the post hasn't been removed by moderator in the meanwhile,
#that there is a description and it's not just an image, that the flair is
#meaningful, and that we aren't re-considering same author's watchlist
if not submission.removed_by_category and submission.selftext \
and submission.author.name not in l_watchlist_author: # and submission.link_flair_text not in ['Yolo', 'Meme'] \
# Make sure there is at least 1 ticker found on the post text
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.selftext))
if not l_tickers_found:
l_tickers_found = set(re.findall("[A-Z]{3,5}", submission.title))
if l_tickers_found:
# Add another author's name to the parsed watchlists
l_watchlist_author.append(submission.author.name)
if not submission.removed_by_category:
# Lookup stock tickers within a watchlist
for key in l_tickers_found:
if key in d_watchlist_tickers:
# Increment stock ticker found
d_watchlist_tickers[key] += 1
else:
# Initialize stock ticker found
d_watchlist_tickers[key] = 1
l_watchlist_links.append(f"https://www.reddit.com{submission.permalink}")
l_watchlist_links.append(f"https://www.reddit.com{submission.permalink}")
# delte below, not necessary I reckon. Probably just link?
# Refactor data
s_datetime = datetime.utcfromtimestamp(submission.created_utc).strftime("%d/%m/%Y %H:%M:%S")
s_link = f"https://www.reddit.com{submission.permalink}"
s_all_awards = ""
for award in submission.all_awardings:
s_all_awards += f"{award['count']} {award['name']}\n"
s_all_awards = s_all_awards[:-2]
# Refactor data
s_datetime = datetime.utcfromtimestamp(submission.created_utc).strftime("%d/%m/%Y %H:%M:%S")
s_link = f"https://www.reddit.com{submission.permalink}"
s_all_awards = ""
for award in submission.all_awardings:
s_all_awards += f"{award['count']} {award['name']}\n"
s_all_awards = s_all_awards[:-2]
# Create dictionary with data to construct dataframe allows to save data
d_submission[submission.id] = {
'created_utc': s_datetime,
'subreddit': submission.subreddit,
'link_flair_text': submission.link_flair_text,
'title':submission.title,
'score': submission.score,
'link': s_link,
'num_comments': submission.num_comments,
'upvote_ratio': submission.upvote_ratio,
'awards': s_all_awards
}
# Create dictionary with data to construct dataframe allows to save data
d_submission[submission.id] = {
'created_utc': s_datetime,
'subreddit': submission.subreddit,
'link_flair_text': submission.link_flair_text,
'title':submission.title,
'score': submission.score,
'link': s_link,
'num_comments': submission.num_comments,
'upvote_ratio': submission.upvote_ratio,
'awards': s_all_awards
}
# Print post data collected so far
print(f"{s_datetime} - {submission.title}")
print(f"{s_link}")
t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"])
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards])
print(t_post)
print("\n")
# Print post data collected so far
print(f"{s_datetime} - {submission.title}")
print(f"{s_link}")
t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"])
t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score,
submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards])
print(t_post)
print("")
# Check if search_submissions didn't get anymore posts
else:
break
if d_watchlist_tickers:
lt_watchlist_sorted = sorted(d_watchlist_tickers.items(), key=lambda item: item[1], reverse=True)
s_watchlist_tickers = ""
n_tickers = 0
for t_ticker in lt_watchlist_sorted:
try:
# If try doesn't trigger exception, it means that this stock exists on finviz
#thus we can print it.
finviz.get_stock(t_ticker[0])
s_watchlist_tickers += f"{t_ticker[1]} {t_ticker[0]}, "
n_tickers += 1
except:
pass
if n_tickers:
print("The following stock tickers have been mentioned across the previous SPACs:")
print(s_watchlist_tickers[:-2])
print("")
print("")
except:
print("")

View File

@@ -55,7 +55,7 @@ def print_technical_analysis(s_ticker, s_start, s_interval):
def ta_menu(df_stock, s_ticker, s_start, s_interval):
# Add list of arguments that the technical analysis parser accepts
ta_parser = argparse.ArgumentParser(prog='technical_analysis', add_help=False)
ta_parser = argparse.ArgumentParser(prog='ta', add_help=False)
ta_parser.add_argument('cmd', choices=['help', 'q', 'quit',
'ema', 'sma', 'vwap', # overlap
'cci', 'macd', 'rsi', 'stoch', # momentum
@@ -69,7 +69,7 @@ def ta_menu(df_stock, s_ticker, s_start, s_interval):
while True:
# Get input command from user
as_input = input('> ')
# Parse fundamental analysis command of the list of possible commands
try:
(ns_known_args, l_args) = ta_parser.parse_known_args(as_input.split())
@@ -111,7 +111,7 @@ def ta_menu(df_stock, s_ticker, s_start, s_interval):
elif ns_known_args.cmd == 'stoch':
ta_momentum.stoch(l_args, s_ticker, s_interval, df_stock)
# ---------------------------------------------------- TREND ----------------------------------------------------
elif ns_known_args.cmd == 'adx':
ta_trend.adx(l_args, s_ticker, s_interval, df_stock)