diff --git a/ROADMAP.md b/ROADMAP.md
index cc9ca5476f4..3d48f982f4c 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -121,6 +121,7 @@
* [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)
### Long term
@@ -144,9 +145,10 @@
* [ ] Merge data from different brokers
* [ ] Refactor
-- [x] Add robinhood (@jmaslek) - [PR #209](https://github.com/DidierRLopes/GamestonkTerminal/pull/209)
+- [x] Add robinhood (@jmaslek) - [PR #229](https://github.com/DidierRLopes/GamestonkTerminal/pull/229)
- [ ] Add Brokers (td, alpaca, webull, etc) (@jmaslek)
- [ ] Merge data from different brokers (@jmaslek)
+
### Long term
- [ ] Summaries / tear sheets (@jmaslek)
diff --git a/gamestonk_terminal/comparison_analysis/README.md b/gamestonk_terminal/comparison_analysis/README.md
index 8306b075770..e4d6127d54c 100644
--- a/gamestonk_terminal/comparison_analysis/README.md
+++ b/gamestonk_terminal/comparison_analysis/README.md
@@ -8,14 +8,18 @@ This menu aims to compare a pre-loaded stock with similar companies, and the usa
* select similar companies
* [historical](#historical)
* historical data comparison [Yahoo Finance]
-* [corr](#corr)
- * correlation between similar companies [Yahoo Finance]
+* [hcorr](#hcorr)
+ * historical correlation between similar companies [Yahoo Finance]
* [income](#income)
* income financials comparison [Market Watch]
* [balance](#balance)
* balance financials comparison [Market Watch]
* [cashflow](#cashflow)
* cashflow financials comparison [Market Watch]
+* [sentiment](#sentiment)
+ * sentiment analysis comparison [FinBrain]
+* [scorr](#corr)
+ * sentiment correlation between similar companies [FinBrain]
## get
@@ -52,13 +56,13 @@ Historical price comparison between similar companies [Source: Yahoo Finance]

-## corr
+## hcorr
```text
-usage: corr [-s L_SIMILAR] [-a L_ALSO] [-t TYPE_CANDLE]
+usage: hcorr [-s L_SIMILAR] [-a L_ALSO] [-t TYPE_CANDLE]
```
-Historical price comparison between similar companies [Source: Yahoo Finance]
+Historical price correlation between similar companies [Source: Yahoo Finance]
* -s : similar companies to compare with. Default pre-loaded ones.
* -a : apart from loaded similar companies also compare with.
@@ -114,4 +118,31 @@ Cashflow financials comparison between similar companies [Source: Market Watch]
+## sentiment
+
+```text
+usage: sentiment [-s L_SIMILAR] [-a L_ALSO]
+```
+
+Sentiment analysis comparison [Source: FinBrain]
+
+* -s : similar companies to compare with. Default pre-loaded ones.
+* -a : apart from loaded similar companies also compare with.
+
+
+
+
+## scorr
+
+```text
+usage: scorr [-s L_SIMILAR] [-a L_ALSO] [-t TYPE_CANDLE]
+```
+
+Sentiment correlation between similar companies [Source: FinBrain]
+
+* -s : similar companies to compare with. Default pre-loaded ones.
+* -a : apart from loaded similar companies also compare with.
+
+
+
diff --git a/gamestonk_terminal/comparison_analysis/ca_controller.py b/gamestonk_terminal/comparison_analysis/ca_controller.py
index e158e504e05..dfd8f522d34 100644
--- a/gamestonk_terminal/comparison_analysis/ca_controller.py
+++ b/gamestonk_terminal/comparison_analysis/ca_controller.py
@@ -6,12 +6,13 @@ import requests
from typing import List
from datetime import datetime
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 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
+from gamestonk_terminal.comparison_analysis import finbrain_api as f_api
from gamestonk_terminal.menu import session
from prompt_toolkit.completion import NestedCompleter
@@ -27,10 +28,12 @@ class ComparisonAnalysisController:
"get",
"select",
"historical",
- "corr",
+ "hcorr",
"income",
"balance",
"cashflow",
+ "sentiment",
+ "scorr",
]
def __init__(
@@ -83,14 +86,16 @@ class ComparisonAnalysisController:
print(" get get similar companies [Polygon API]")
print(" select select similar companies")
print("")
- if self.similar:
- print(" historical historical data comparison")
- print(" corr correlation between similar companies")
- print("")
- print(" income income financials comparison")
- print(" balance balance financials comparison")
- print(" cashflow cashflow comparison")
- print("")
+ print(" historical historical price data comparison")
+ print(" hcorr historical price correlation")
+ print("")
+ print(" income income financials comparison")
+ print(" balance balance financials comparison")
+ print(" cashflow cashflow comparison")
+ print("")
+ print(" sentiment sentiment analysis comparison")
+ print(" scorr sentiment correlation")
+ print("")
return
@staticmethod
@@ -201,8 +206,8 @@ class ComparisonAnalysisController:
other_args, self.stock, self.ticker, self.start, self.interval, self.similar
)
- def call_corr(self, other_args: List[str]):
- """Process correlation command"""
+ def call_hcorr(self, other_args: List[str]):
+ """Process historical correlation command"""
yf_api.correlation(
other_args, self.stock, self.ticker, self.start, self.interval, self.similar
)
@@ -219,6 +224,14 @@ class ComparisonAnalysisController:
"""Process cashflow command"""
mw_api.compare_cashflow(other_args, self.ticker, self.similar)
+ def call_sentiment(self, other_args: List[str]):
+ """Process sentiment command"""
+ f_api.sentiment_compare(other_args, self.ticker, self.similar)
+
+ def call_scorr(self, other_args: List[str]):
+ """Process sentiment correlation command"""
+ f_api.sentiment_correlation(other_args, self.ticker, self.similar)
+
def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str):
"""Comparison Analysis Menu"""
@@ -242,6 +255,8 @@ def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str):
an_input = input(f"{get_flair()} (ca)> ")
try:
+ plt.close("all")
+
process_input = ca_controller.switch(an_input)
if process_input is not None:
diff --git a/gamestonk_terminal/comparison_analysis/finbrain_api.py b/gamestonk_terminal/comparison_analysis/finbrain_api.py
new file mode 100644
index 00000000000..45740ae44fe
--- /dev/null
+++ b/gamestonk_terminal/comparison_analysis/finbrain_api.py
@@ -0,0 +1,272 @@
+""" Comparison Analysis Finbrain API """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+import requests
+from matplotlib import pyplot as plt
+import matplotlib.dates as mdates
+import pandas as pd
+from pandas.plotting import register_matplotlib_converters
+import numpy as np
+import seaborn as sns
+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 sentiment_compare(other_args: List[str], ticker: str, similar: List[str]):
+ """Plot sentiments across similar companies
+
+ Parameters
+ ----------
+ other_args : List[str]
+ Command line arguments to be processed with argparse
+ ticker : str
+ Main ticker to compare income
+ similar : List[str]
+ Similar companies to compare income with
+ """
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="sentiment_compare",
+ description="""
+ FinBrain's sentiment comparison across similar tickers.
+ Finbrain collects the news headlines from 15+ major financial news
+ sources on a daily basis and analyzes them to generate sentiment scores
+ for more than 4500 US stocks.FinBrain Technologies develops deep learning
+ algorithms for financial analysis and prediction, which currently serves
+ traders from more than 150 countries all around the world.
+ [Source: https://finbrain.tech]
+ """,
+ )
+ parser.add_argument(
+ "-s",
+ "--similar",
+ dest="l_similar",
+ type=lambda s: [str(item).upper() for item in s.split(",")],
+ default=similar,
+ help="similar companies to compare with.",
+ )
+ parser.add_argument(
+ "-a",
+ "--also",
+ dest="l_also",
+ type=lambda s: [str(item).upper() for item in s.split(",")],
+ default=[],
+ help="apart from loaded similar companies also compare with.",
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ l_similar = ns_parser.l_similar
+ l_similar += ns_parser.l_also
+
+ # Add main ticker to similar list of companies
+ l_similar = [ticker] + l_similar
+
+ df_sentiment = get_sentiments(l_similar)
+
+ if not df_sentiment.empty:
+ plot_sentiments(df_sentiment, l_similar)
+
+ print("")
+
+ except Exception as e:
+ print(e, "\n")
+ return
+
+
+def sentiment_correlation(other_args: List[str], ticker: str, similar: List[str]):
+ """Plot correlation sentiments across similar companies
+
+ Parameters
+ ----------
+ other_args : List[str]
+ Command line arguments to be processed with argparse
+ ticker : str
+ Main ticker to compare income
+ similar : List[str]
+ Similar companies to compare income with
+ """
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="sentiment_compare",
+ description="""
+ FinBrain's sentiment correlation across similar tickers.
+ Finbrain collects the news headlines from 15+ major financial news
+ sources on a daily basis and analyzes them to generate sentiment scores
+ for more than 4500 US stocks.FinBrain Technologies develops deep learning
+ algorithms for financial analysis and prediction, which currently serves
+ traders from more than 150 countries all around the world.
+ [Source: https://finbrain.tech]
+ """,
+ )
+ parser.add_argument(
+ "-s",
+ "--similar",
+ dest="l_similar",
+ type=lambda s: [str(item).upper() for item in s.split(",")],
+ default=similar,
+ help="similar companies to compare with.",
+ )
+ parser.add_argument(
+ "-a",
+ "--also",
+ dest="l_also",
+ type=lambda s: [str(item).upper() for item in s.split(",")],
+ default=[],
+ help="apart from loaded similar companies also compare with.",
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ l_similar = ns_parser.l_similar
+ l_similar += ns_parser.l_also
+
+ # Add main ticker to similar list of companies
+ l_similar = [ticker] + l_similar
+
+ df_sentiment = get_sentiments(l_similar)
+
+ if not df_sentiment.empty:
+ plot_correlation(df_sentiment, l_similar)
+
+ print("")
+
+ except Exception as e:
+ print(e, "\n")
+ return
+
+
+def get_sentiments(similar: List[str]) -> pd.DataFrame:
+ """Gets Sentiment analysis from several tickers provided by FinBrain's API
+
+ Parameters
+ ----------
+ similar : List[str]
+ Similar tickers to get the sentiment analysis from
+
+ Returns
+ -------
+ DataFrame()
+ Contains sentiment analysis from several tickers
+ """
+ df_sentiment = pd.DataFrame()
+ for ticker in similar:
+ result = requests.get(f"https://api.finbrain.tech/v0/sentiments/{ticker}")
+ if result.status_code == 200:
+ if "sentimentAnalysis" in result.json():
+ df_sentiment[ticker] = [
+ float(val)
+ for val in list(result.json()["sentimentAnalysis"].values())
+ ]
+ else:
+ print(f"Unexpected data format from FinBrain API for {ticker}")
+
+ else:
+ print(f"Request error in retrieving {ticker} sentiment from FinBrain API")
+
+ if not df_sentiment.empty:
+ df_sentiment.index = list(result.json()["sentimentAnalysis"].keys())
+ df_sentiment.sort_index(ascending=True, inplace=True)
+
+ return df_sentiment
+
+
+def plot_sentiments(df_sentiment: pd.DataFrame, similar: List[str]):
+ """Plot Sentiment analysis comparison between similar companies
+
+ Parameters
+ ----------
+ df_sentiment : pd.DataFrame
+ Dataframe with sentiment analysis from several similar companies
+ similar : List[str]
+ List of similar companies
+ """
+ plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
+
+ for idx, ticker in enumerate(similar):
+ offset = 2 * idx
+ plt.axhline(y=offset, color="k", linestyle="--", lw=2)
+ plt.axhline(y=offset + 1, color="k", linestyle="--", lw=1)
+
+ senValues = np.array(pd.to_numeric(df_sentiment[ticker].values))
+ senNone = np.array(0 * len(df_sentiment))
+ plt.fill_between(
+ df_sentiment.index,
+ pd.to_numeric(df_sentiment[ticker].values) + offset,
+ offset,
+ where=(senValues < senNone),
+ alpha=0.60,
+ color="red",
+ interpolate=True,
+ )
+
+ plt.fill_between(
+ df_sentiment.index,
+ pd.to_numeric(df_sentiment[ticker].values) + offset,
+ offset,
+ where=(senValues >= senNone),
+ alpha=0.60,
+ color="green",
+ interpolate=True,
+ )
+
+ plt.xlabel("Time")
+ plt.ylabel("Sentiment")
+ plt.axhline(y=-1, color="k", linestyle="--", lw=1)
+ plt.grid(b=True, which="major", color="#666666", linestyle="-")
+ plt.minorticks_on()
+ plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+ plt.yticks(np.arange(len(similar)) * 2, similar)
+ plt.title(f"FinBrain's Sentiment Analysis since {df_sentiment.index[0]}")
+ plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=1))
+ plt.gcf().autofmt_xdate()
+
+ if gtff.USE_ION:
+ plt.ion()
+ plt.show()
+
+
+def plot_correlation(df_sentiment: pd.DataFrame, similar: List[str]):
+ """Plot Sentiment correlation between similar companies
+
+ Parameters
+ ----------
+ df_sentiment : pd.DataFrame
+ Dataframe with sentiment analysis from several similar companies
+ similar : List[str]
+ List of similar companies
+ """
+ plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
+
+ mask = np.zeros((len(similar), len(similar)), dtype=bool)
+ mask[np.triu_indices(len(mask))] = True
+
+ sns.heatmap(
+ df_sentiment.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,
+ )
+
+ if gtff.USE_ION:
+ plt.ion()
+ plt.show()
diff --git a/gamestonk_terminal/comparison_analysis/market_watch_api.py b/gamestonk_terminal/comparison_analysis/market_watch_api.py
index 8c564b2c483..5067cdeae38 100644
--- a/gamestonk_terminal/comparison_analysis/market_watch_api.py
+++ b/gamestonk_terminal/comparison_analysis/market_watch_api.py
@@ -77,7 +77,7 @@ def compare_income(other_args: List[str], ticker: str, similar: List[str]):
l_similar += ns_parser.l_also
# Add main ticker to similar list of companies
- l_similar.insert(0, ticker)
+ l_similar = [ticker] + l_similar
l_timeframes, ddf_financials = prepare_comparison_financials(
l_similar, "income", ns_parser.b_quarter
@@ -182,7 +182,7 @@ def compare_balance(other_args: List[str], ticker: str, similar: List[str]):
l_similar += ns_parser.l_also
# Add main ticker to similar list of companies
- l_similar.insert(0, ticker)
+ l_similar = [ticker] + l_similar
l_timeframes, ddf_financials = prepare_comparison_financials(
l_similar, "balance", ns_parser.b_quarter
@@ -287,7 +287,7 @@ def compare_cashflow(other_args: List[str], ticker: str, similar: List[str]):
l_similar += ns_parser.l_also
# Add main ticker to similar list of companies
- l_similar.insert(0, ticker)
+ l_similar = [ticker] + l_similar
l_timeframes, ddf_financials = prepare_comparison_financials(
l_similar, "cashflow", ns_parser.b_quarter