From e49c754f500c44a8f660a6e2743ffb5f4529d78c Mon Sep 17 00:00:00 2001 From: didier Date: Thu, 8 Apr 2021 22:31:14 +0100 Subject: [PATCH] Use Finviz to get similar companies based on Industry Sector Country --- ROADMAP.md | 3 +- .../comparison_analysis/README.md | 8 ++- .../comparison_analysis/ca_controller.py | 66 ++++++++++++++----- .../comparison_analysis/yahoo_finance_api.py | 41 +++++++++--- 4 files changed, 89 insertions(+), 29 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 2e5c86b6dd2..36bddcdafbf 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -108,9 +108,10 @@ * [x] Add multi-ticker historical data comparison (@didier) - [PR #141](https://github.com/DidierRLopes/GamestonkTerminal/pull/141) * [x] Add multi-ticker financials comparison (@didier) - [PR #237](https://github.com/DidierRLopes/GamestonkTerminal/pull/237) * [x] Add multi-ticker sentiment comparison (@didier) - [PR #250](https://github.com/DidierRLopes/GamestonkTerminal/pull/250) +* [x] Get similar companies from Finviz based on Industry and Sector (and possibly country) from Finviz (@didier) - [PR #321](https://github.com/DidierRLopes/GamestonkTerminal/pull/321) **NEXT** -* [ ] Get similar companies from Finviz based on Industry and Sector (and possibly country) from Finviz (@didier) + * [ ] Perform quick screening across similar companies based on key metrics (overview, performance, financial, valuation) from Finviz (@didier) --- diff --git a/gamestonk_terminal/comparison_analysis/README.md b/gamestonk_terminal/comparison_analysis/README.md index e4d6127d54c..19210c56f74 100644 --- a/gamestonk_terminal/comparison_analysis/README.md +++ b/gamestonk_terminal/comparison_analysis/README.md @@ -3,7 +3,7 @@ This menu aims to compare a pre-loaded stock with similar companies, and the usage of the following commands along with an example will be exploited below. * [get](#get) - * get similar companies [Polygon] + * get similar companies [Finviz or Polygon] * [select](#select) * select similar companies * [historical](#historical) @@ -25,11 +25,13 @@ This menu aims to compare a pre-loaded stock with similar companies, and the usa ## get ```text -get +get [-p] [--nocountry] ``` -Get similar companies to compare with. [Source: Polygon] +Get similar companies to compare with. [Source: Finviz by default] +* -p : get similar companies using polygon source. Default False, i.e. using Finviz source. +* --nocountry : when getting similar companies from Finviz, we filter by same Industry, Sector and Country. However, if we don't want to filter by same country we can set this flag. For this flag to work, the `-p` flag can't be selected ## select diff --git a/gamestonk_terminal/comparison_analysis/ca_controller.py b/gamestonk_terminal/comparison_analysis/ca_controller.py index dfd8f522d34..4ed4f897364 100644 --- a/gamestonk_terminal/comparison_analysis/ca_controller.py +++ b/gamestonk_terminal/comparison_analysis/ca_controller.py @@ -9,6 +9,7 @@ import pandas as pd from matplotlib import pyplot as plt from gamestonk_terminal import feature_flags as gtff from gamestonk_terminal import config_terminal as cfg +from finvizfinance.screener.overview import Overview 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 from gamestonk_terminal.comparison_analysis import market_watch_api as mw_api @@ -47,7 +48,7 @@ class ComparisonAnalysisController: ): """Constructor""" self.similar = similar - self.user = user + self.user = "" self.stock = stock self.ticker = ticker self.start = start @@ -71,12 +72,10 @@ class ComparisonAnalysisController: else: print(f"\n{s_intraday} Stock: {self.ticker}") - s_similar_source = ("Polygon API", "User")[self.user] - if self.similar: - print(f"[{s_similar_source}] Similar Companies: {', '.join(self.similar)}") - else: - print(f"No similar companies [{s_similar_source}]") + print(f"[{self.user}] Similar Companies: {', '.join(self.similar)}") + #else: + # print(f"No similar companies [{self.user}]") print("\nComparison Analysis Mode:") print(" help show this comparison analysis menu again") @@ -106,22 +105,59 @@ class ComparisonAnalysisController: prog="get", description="""Get similar companies to compare with.""", ) + parser.add_argument( + "-p", + "--polygon", + action="store_true", + default=False, + dest="b_polygon", + help="Polygon data source flag.", + ) + + # If polygon source not selected, the user may want to get + # similar companies based on Industry and Sector only, and not + # on the fact that they are based on the same country + if '-p' not in other_args and '--polygon' not in other_args: + parser.add_argument( + "--nocountry", + action="store_true", + default=False, + dest="b_no_country", + help="Similar stocks from finviz using only Industry and Sector.", + ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return - result = requests.get( - f"https://api.polygon.io/v1/meta/symbols/{self.ticker.upper()}/company?&apiKey={cfg.API_POLYGON_KEY}" - ) + if ns_parser.b_polygon: + result = requests.get( + f"https://api.polygon.io/v1/meta/symbols/{self.ticker.upper()}/company?&apiKey={cfg.API_POLYGON_KEY}" + ) + + if result.status_code == 200: + self.similar = result.json()["similar"] + self.user = "Polygon" + else: + print(result.json()["error"]) - if result.status_code == 200: - self.similar = result.json()["similar"] - print(f"[Polygon API] Similar Companies: {', '.join(self.similar)}") - self.user = False else: - print(result.json()["error"]) + if ns_parser.b_no_country: + compare_list = ['Sector', 'Industry'] + else: + compare_list = ['Sector', 'Industry', 'Country'] + + self.similar = Overview().compare(self.ticker, compare_list, verbose=0)['Ticker'].to_list() + self.user = "Finviz" + + if self.similar: + print(f"\n[{self.user}] Similar Companies: {', '.join(self.similar)}") + + if len(self.similar) > 10: + print("\nThe limit of stocks to compare with are 10. Hence, the similar stocks list will be:") + self.similar = self.similar[:10] + print(', '.join(self.similar)) except Exception as e: print(e) @@ -157,7 +193,7 @@ class ComparisonAnalysisController: return self.similar = ns_parser.l_similar - self.user = True + self.user = "User" except Exception as e: print(e) diff --git a/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py b/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py index 163ff3c09d7..09f4330cc50 100644 --- a/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py +++ b/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py @@ -81,22 +81,43 @@ def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar): plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.title(f"Similar companies to {s_ticker}") - df_stock = yf.download(s_ticker, start=s_start, progress=False) + df_stock = yf.download(s_ticker, start=s_start, progress=False, threads=False) plt.plot( df_stock.index, df_stock[d_candle_types[ns_parser.type_candle]].values ) # 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[d_candle_types[ns_parser.type_candle]].values, - ) - l_min.append(df_similar_stock.index[0]) - l_leg.append(symbol) + + l_stocks = similar[:] + + while l_stocks: + l_parsed_stocks = list() + for symbol in l_stocks: + try: + df_similar_stock = yf.download(symbol, start=s_start, progress=False, threads=False) + if not df_similar_stock.empty: + plt.plot( + df_similar_stock.index, + df_similar_stock[d_candle_types[ns_parser.type_candle]].values, + ) + l_min.append(df_similar_stock.index[0]) + l_leg.append(symbol) + + l_parsed_stocks.append(symbol) + except Exception as e: + print("") + print(e) + print( + "Disregard previous error, which is due to API Rate limits from Yahoo Finance." + ) + print( + f"Because we like '{symbol}', and we won't leave without getting data from it." + ) + + for parsed_stock in l_parsed_stocks: + l_stocks.remove(parsed_stock) + plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.legend(l_leg)