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]
+
+## rot
+
+```text
+usage: rot
+```
+
+Plots ratings over time. [Source: Finnhub]
+
+
+
+
## 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")