diff --git a/ROADMAP.md b/ROADMAP.md index b7c80d2c599..febc5b2afde 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -87,7 +87,8 @@ ## Due Diligence * [x] Add dark pools (ATS) vs Non-ATS data over time (@didier) - [PR #363](https://github.com/DidierRLopes/GamestonkTerminal/pull/363) -* [x] Add failure to deliver command (@hinxx) - [PR #366](#https://github.com/DidierRLopes/GamestonkTerminal/pull/366) +* [x] Add failure to deliver command (@hinxx) - [PR #366](https://github.com/DidierRLopes/GamestonkTerminal/pull/366) +* [x] Ratings over time (@didier) - [PR #431](https://github.com/DidierRLopes/GamestonkTerminal/pull/431) **NEXT** @@ -197,7 +198,7 @@ ___ --- ## Cryptocurrencies -* [x] Add Coingecko (@jmaslek) - [PR #283](#https://github.com/DidierRLopes/GamestonkTerminal/pull/283) +* [x] Add Coingecko (@jmaslek) - [PR #283](https://github.com/DidierRLopes/GamestonkTerminal/pull/283) * [x] view top coins from coinmarketcap (@jmaslek) - [PR #378](https://github.com/DidierRLopes/GamestonkTerminal/pull/378) * [x] Add binance (@jmaslek) [PR #428](#https://github.com/DidierRLopes/GamestonkTerminal/pull/428) diff --git a/gamestonk_terminal/README.md b/gamestonk_terminal/README.md index 32a42a6e67a..a16aea31db1 100644 --- a/gamestonk_terminal/README.md +++ b/gamestonk_terminal/README.md @@ -212,6 +212,7 @@ Command|Description|Source `analyst` |analyst prices and ratings of the company |[Finviz](https://finviz.com/) `rating` |rating of the company from strong sell to strong buy | [FMP](https://financialmodelingprep.com/) `pt` |price targets over time |[Business Insider](https://www.businessinsider.com/) +`rot` |ratings over time |[Finnhub](https://finnhub.io) `est` |quarter and year analysts earnings estimates |[Business Insider](https://www.businessinsider.com/) `ins` |insider activity over time |[Business Insider](https://www.businessinsider.com/) `insider` |insider trading of the company |[Finviz](https://finviz.com/) diff --git a/gamestonk_terminal/due_diligence/README.md b/gamestonk_terminal/due_diligence/README.md index cb8854b78e5..7a88574392a 100644 --- a/gamestonk_terminal/due_diligence/README.md +++ b/gamestonk_terminal/due_diligence/README.md @@ -12,6 +12,8 @@ This menu aims to help in due-diligence of a pre-loaded stock, and the usage of * rating of the company from strong sell to strong buy [FMP] * [pt](#pt) * price targets over time [Business Insider] +* [rot](#rot) + * ratings over time [Finnhub] * [est](#est) * quarter and year analysts earnings estimates [Business Insider] * [ins](#ins) @@ -89,6 +91,18 @@ Prints price target from analysts. [Source: Business Insider] pt2 + +## rot + +```text +usage: rot +``` + +Plots ratings over time. [Source: Finnhub] + +![rot](https://user-images.githubusercontent.com/25267873/116864981-ad282980-ac00-11eb-9e86-7163782a8ef6.png) + + ## est ```text diff --git a/gamestonk_terminal/due_diligence/dd_controller.py b/gamestonk_terminal/due_diligence/dd_controller.py index 27efe9eb880..f24ddcad017 100644 --- a/gamestonk_terminal/due_diligence/dd_controller.py +++ b/gamestonk_terminal/due_diligence/dd_controller.py @@ -15,6 +15,7 @@ from gamestonk_terminal.due_diligence import reddit_view as r_view from gamestonk_terminal.due_diligence import news_view from gamestonk_terminal.due_diligence import finra_view from gamestonk_terminal.due_diligence import sec_view +from gamestonk_terminal.due_diligence import finnhub_view from gamestonk_terminal import feature_flags as gtff from gamestonk_terminal.helper_funcs import get_flair from gamestonk_terminal.menu import session @@ -32,6 +33,7 @@ class DueDiligenceController: "short", "rating", "pt", + "rot", "est", "ins", "insider", @@ -91,6 +93,9 @@ class DueDiligenceController: " rating rating of the company from strong sell to strong buy [FMP]" ) print(" pt price targets over time [Business Insider]") + print( + " rot rating over timefrom strong sell to strong buy [Finnhub]" + ) print( " est quarter and year analysts earnings estimates [Business Insider]" ) @@ -155,6 +160,10 @@ class DueDiligenceController: other_args, self.stock, self.ticker, self.start, self.interval ) + def call_rot(self, other_args: List[str]): + """Process rot command""" + finnhub_view.rating_over_time(other_args, self.ticker) + def call_est(self, other_args: List[str]): """Process est command""" bi_view.estimates(other_args, self.ticker) diff --git a/gamestonk_terminal/due_diligence/finnhub_view.py b/gamestonk_terminal/due_diligence/finnhub_view.py new file mode 100644 index 00000000000..112032ea462 --- /dev/null +++ b/gamestonk_terminal/due_diligence/finnhub_view.py @@ -0,0 +1,108 @@ +import argparse +from typing import List +import requests +import pandas as pd +from matplotlib import pyplot as plt +from pandas.plotting import register_matplotlib_converters +from gamestonk_terminal import config_terminal as cfg +from gamestonk_terminal.helper_funcs import ( + parse_known_args_and_warn, + plot_autoscale, +) +from gamestonk_terminal.config_plot import PLOT_DPI +from gamestonk_terminal import feature_flags as gtff + +register_matplotlib_converters() + + +def get_rating_over_time(ticker: str) -> pd.DataFrame: + """Get rating over time + + Parameters + ---------- + ticker : str + Ticker to get ratings from + + Returns + ------- + pd.DataFrame + Get dataframe with economic calendar events + """ + response = requests.get( + f"https://finnhub.io/api/v1/stock/recommendation?symbol={ticker}&token={cfg.API_FINNHUB_KEY}" + ) + if response.status_code == 200: + return pd.DataFrame(response.json()) + + return pd.DataFrame() + + +def plot_rating_over_time(rot: pd.DataFrame, ticker: str): + """Plot rating over time + + Parameters + ---------- + rot : pd.DataFrame + Rating over time + ticker : str + Ticker associated with ratings + + """ + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + + rot.sort_values("period", inplace=True) + plt.plot(pd.to_datetime(rot["period"]), rot["strongBuy"], c="green", lw=3) + plt.plot(pd.to_datetime(rot["period"]), rot["buy"], c="lightgreen", lw=3) + plt.plot(pd.to_datetime(rot["period"]), rot["hold"], c="grey", lw=3) + plt.plot(pd.to_datetime(rot["period"]), rot["sell"], c="pink", lw=3) + plt.plot(pd.to_datetime(rot["period"]), rot["strongSell"], c="red", lw=3) + plt.xlim( + pd.to_datetime(rot["period"].values[0]), + pd.to_datetime(rot["period"].values[-1]), + ) + plt.grid() + plt.title(f"{ticker}'s ratings over time") + plt.xlabel("Time") + plt.ylabel("Rating") + plt.legend(["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"]) + + if gtff.USE_ION: + plt.ion() + + plt.show() + + +def rating_over_time(other_args: List[str], ticker: str): + """Rating over time + + Parameters + ---------- + other_args : List[str] + Command line arguments to be processed with argparse + ticker : str + Ticker to get ratings from + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="rot", + description=""" + Rating over time. [Source: https://finnhub.io] + """, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + df_rot = get_rating_over_time(ticker) + + if df_rot.empty: + print("No ratings over time found\n") + return + + plot_rating_over_time(df_rot, ticker) + print("") + + except Exception as e: + print(e, "\n")