mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 13:01:38 +00:00
Add comparison analysis menu with historical and correlation heatmap comparisons
This commit is contained in:
161
gamestonk_terminal/comparison_analysis/ca_menu.py
Normal file
161
gamestonk_terminal/comparison_analysis/ca_menu.py
Normal 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!")
|
||||
157
gamestonk_terminal/comparison_analysis/yahoo_finance_api.py
Normal file
157
gamestonk_terminal/comparison_analysis/yahoo_finance_api.py
Normal 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("")
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user