Add comparison analysis menu with historical and correlation heatmap comparisons

This commit is contained in:
didier
2021-03-10 00:30:06 +00:00
parent 35583d762d
commit 2c8f7cbd71
5 changed files with 330 additions and 3 deletions

View File

@@ -0,0 +1,161 @@
import argparse
import requests
from gamestonk_terminal import config_terminal as cfg
from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn
from gamestonk_terminal.comparison_analysis import yahoo_finance_api as yf_api
def get_similar_companies(l_args, s_ticker):
""" Get similar companies. [Source: Polygon API] """
parser = argparse.ArgumentParser(
prog="get",
description="""Get similar companies to compare with.""",
)
l_similar = []
try:
parse_known_args_and_warn(parser, l_args)
result = requests.get(
f"https://api.polygon.io/v1/meta/symbols/{s_ticker}/company?&apiKey={cfg.API_POLYGON_KEY}"
)
if result.status_code == 200:
l_similar = result.json()["similar"]
except Exception as e:
print(e)
print("")
return l_similar
def select_similar_companies(l_args):
""" Select similar companies, e.g. NIO,XPEV,LI"""
parser = argparse.ArgumentParser(
prog="select",
description="""Select similar companies to compare with.""",
)
parser.add_argument(
"-s",
"--similar",
dest="l_similar",
type=lambda s: [str(item) for item in s.split(",")],
default=[],
help="similar companies to compare with.",
)
try:
# For the case where a user uses: 'select NIO,XPEV,LI'
if l_args:
if "-" not in l_args[0]:
l_args.insert(0, "-s")
ns_parser = parse_known_args_and_warn(parser, l_args)
print("")
return ns_parser.l_similar
except Exception as e:
print(e)
print("")
return []
def print_comparison_analysis(s_ticker, s_start, s_interval, l_similar, b_user):
""" Print help """
s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
if s_start:
print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
else:
print(f"\n{s_intraday} Stock: {s_ticker}")
s_similar_source = ("Polygon API", "User")[b_user]
if l_similar:
print(f"[{s_similar_source}] Similar Companies: {', '.join(l_similar)}")
else:
print(f"No similar companies [{s_similar_source}]")
print("\nComparison Analysis Mode:")
print(" help show this comparison analysis menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" get get similar companies [Polygon API]")
print(" select select similar companies")
print("")
print(" historical historical data comparison")
print(" corr correlation between similar companies")
print("")
return
def ca_menu(df_stock, s_ticker, s_start, s_interval):
# Add list of arguments that the comparison analysis parser accepts
ca_parser = argparse.ArgumentParser(prog="ca", add_help=False)
ca_parser.add_argument(
"cmd",
choices=[
"help",
"q",
"quit",
"get",
"select",
"historical",
"corr",
],
)
b_user = False
l_similar = get_similar_companies([], s_ticker)
print_comparison_analysis(s_ticker, s_start, s_interval, l_similar, b_user)
# Loop forever and ever
while True:
# Get input command from user
as_input = input(f"{get_flair()} (ca)> ")
# Parse fundamental analysis command of the list of possible commands
try:
(ns_known_args, l_args) = ca_parser.parse_known_args(as_input.split())
except SystemExit:
print("The command selected doesn't exist\n")
continue
if ns_known_args.cmd == "help":
print_comparison_analysis(s_ticker, s_start, s_interval, l_similar, b_user)
elif ns_known_args.cmd == "q":
# Just leave the CA menu
return False
elif ns_known_args.cmd == "quit":
# Abandon the program
return True
elif ns_known_args.cmd == "get":
l_similar = get_similar_companies(l_args, s_ticker)
b_user = False
elif ns_known_args.cmd == "select":
l_similar = select_similar_companies(l_args)
b_user = True
elif ns_known_args.cmd == "historical":
yf_api.historical(
l_args, df_stock, s_ticker, s_start, s_interval, l_similar
)
elif ns_known_args.cmd == "corr":
yf_api.correlation(
l_args, df_stock, s_ticker, s_start, s_interval, l_similar
)
else:
print("Command not recognized!")

View File

@@ -0,0 +1,157 @@
import argparse
import requests
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import yfinance as yf
import seaborn as sns
from datetime import datetime
from pandas.plotting import register_matplotlib_converters
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
register_matplotlib_converters()
def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar):
parser = argparse.ArgumentParser(
prog="historical",
description="""Historical price comparison between similar companies [Source: Yahoo Finance]
""",
)
parser.add_argument(
"-s",
"--similar",
dest="l_similar",
type=lambda s: [str(item) for item in s.split(",")],
default=[],
help="similar companies to compare with.",
)
parser.add_argument(
"-a",
"--also",
dest="l_also",
type=lambda s: [str(item) for item in s.split(",")],
default=[],
help="apart from similar companies (from Polygon API) also compare with.",
)
try:
if s_interval != "1440min":
print("Intraday historical data analysis comparison is not yet available.")
# Alpha Vantage only supports 5 calls per minute, we need another API to get intraday data
else:
ns_parser = parse_known_args_and_warn(parser, l_args)
if ns_parser.l_similar:
similar = ns_parser.l_similar
similar += ns_parser.l_also
plt.figure()
plt.title(f"Similar companies to {s_ticker}")
plt.plot(df_stock.index, df_stock["5. adjusted close"].values, lw=2)
l_min = [df_stock.index[0]]
l_leg = [s_ticker]
for symbol in similar:
df_similar_stock = yf.download(symbol, start=s_start, progress=False)
if not df_similar_stock.empty:
plt.plot(
df_similar_stock.index, df_similar_stock["Adj Close"].values
)
l_min.append(df_similar_stock.index[0])
l_leg.append(symbol)
plt.xlabel("Time")
plt.ylabel("Share Price ($)")
plt.legend(l_leg)
plt.grid(b=True, which="major", color="#666666", linestyle="-")
plt.minorticks_on()
plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
# ensures that the historical data starts from same datapoint
plt.xlim([max(l_min), df_stock.index[-1]])
plt.show()
print("")
except Exception as e:
print(e)
print("")
def correlation(l_args, df_stock, s_ticker, s_start, s_interval, similar):
parser = argparse.ArgumentParser(
prog="corr",
description=""" Correlation heatmap based on historical price comparison between similar companies. [Source: Yahoo Finance]
""",
)
parser.add_argument(
"-s",
"--similar",
dest="l_similar",
type=lambda s: [str(item) for item in s.split(",")],
default=[],
help="similar companies to compare with.",
)
parser.add_argument(
"-a",
"--also",
dest="l_also",
type=lambda s: [str(item) for item in s.split(",")],
default=[],
help="apart from similar companies (from Polygon API) also compare with.",
)
try:
if s_interval != "1440min":
print("Intraday historical data analysis comparison is not yet available.")
# Alpha Vantage only supports 5 calls per minute, we need another API to get intraday data
else:
ns_parser = parse_known_args_and_warn(parser, l_args)
if ns_parser.l_similar:
similar = ns_parser.l_similar
similar += ns_parser.l_also
if not similar:
print("Provide at least a similar company for correlation")
else:
d_stock = {}
d_stock[s_ticker] = yf.download(s_ticker, start=s_start, progress=False)
l_min = [d_stock[s_ticker].index[0]]
for symbol in similar:
d_stock[symbol] = yf.download(symbol, start=s_start, progress=False)
if not d_stock[symbol].empty:
l_min.append(d_stock[symbol].index[0])
min_start_date = max(l_min)
df_stock = d_stock[s_ticker]["Adj Close"].rename(s_ticker)
for symbol in d_stock.keys():
if symbol != s_ticker:
if not d_stock[symbol].empty:
df_stock = pd.concat(
[df_stock, d_stock[symbol]["Adj Close"].rename(symbol)],
axis=1,
)
mask = np.zeros((df_stock.shape[1], df_stock.shape[1]), dtype=bool)
mask[np.triu_indices(len(mask))] = True
sns.heatmap(
df_stock[min_start_date:].corr(),
cbar_kws={"ticks": [-1.0, -0.5, 0.0, 0.5, 1.0]},
cmap="RdYlGn",
linewidths=1,
annot=True,
vmin=-1,
vmax=1,
mask=mask,
)
plt.title("Correlation Heatmap")
plt.show()
print("")
except Exception as e:
print(e)
print("")

View File

@@ -18,6 +18,9 @@ API_REDDIT_USERNAME = os.getenv("GT_API_REDDIT_USERNAME") or "REPLACE_ME"
API_REDDIT_USER_AGENT = os.getenv("GT_API_REDDIT_USER_AGENT") or "REPLACE_ME"
API_REDDIT_PASSWORD = os.getenv("GT_API_REDDIT_PASSWORD") or "REPLACE_ME"
# https://polygon.io
API_POLYGON_KEY = os.getenv("GT_API_POLYGON_KEY") or "REPLACE_ME"
# https://developer.twitter.com
API_TWITTER_KEY = os.getenv("GT_API_TWITTER_KEY") or "REPLACE_ME"
API_TWITTER_SECRET_KEY = os.getenv("GT_API_TWITTER_SECRET_KEY") or "REPLACE_ME"

View File

@@ -51,6 +51,9 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open):
print(
" res research web page, \t e.g.: macroaxis, yahoo finance, fool"
)
print(
" ca comparison analysis, \t e.g.: historical, correlation, financials"
)
print(
" fa fundamental analysis, \t e.g.: income, balance, cash, earnings"
)

View File

@@ -13,6 +13,7 @@ from gamestonk_terminal.due_diligence import dd_menu as ddm
from gamestonk_terminal.discovery import disc_menu as dm
from gamestonk_terminal.sentiment import sen_menu as sm
from gamestonk_terminal.papermill import papermill_menu as mill
from gamestonk_terminal.comparison_analysis import ca_menu as cam
from gamestonk_terminal import res_menu as rm
from gamestonk_terminal import config_terminal as cfg
@@ -56,6 +57,7 @@ def main():
"mill",
"sen",
"res",
"ca",
"fa",
"ta",
"dd",
@@ -64,9 +66,7 @@ def main():
)
# Print first welcome message and help
print("")
print("🚀🚀 Welcome to Didier's Gamestonk Terminal!")
print("")
print("\nWelcome to Gamestonk Terminal 🚀\n")
should_print_help = True
# Loop forever and ever
@@ -131,6 +131,9 @@ def main():
elif ns_known_args.opt == "res":
b_quit = rm.res_menu(s_ticker, s_start, s_interval)
elif ns_known_args.opt == "ca":
b_quit = cam.ca_menu(df_stock, s_ticker, s_start, s_interval)
elif ns_known_args.opt == "fa":
b_quit = fam.fa_menu(s_ticker, s_start, s_interval)