diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 860ceb1ca81..382a74b02e7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: - run: pip install bandit black codespell flake8 mypy pyupgrade safety pylint - run: bandit -r . || true - run: black --check . - - run: codespell --ignore-words-list="mape" --quiet-level=2 --skip=".git" + - run: codespell --ignore-words-list="mape","ba" --quiet-level=2 --skip=".git" - run: flake8 . --count --ignore=E203,W503 --max-line-length=122 --show-source --statistics - run: mypy --ignore-missing-imports . - run: shopt -s globstar && pyupgrade --py36-plus **/*.py diff --git a/ROADMAP.md b/ROADMAP.md index a18f1c02854..8989040cbad 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -19,7 +19,7 @@ * [Frontend](#Frontend) * [Developer Experience](#Developer-Experience) * [User Experience](#User-Experience) - +* [Options](#Options) --- ## Discovery @@ -152,6 +152,7 @@ ### Short term - [ ] Add Coingecko +- [ ] Add [Coinpaprika](https://coinpaprika.com/api/) - [ ] Add crypto charts ### Long term @@ -204,3 +205,17 @@ ### Long term - [ ] Add a WHL installation + + +--- + +## Options + +### Short term + +- [ ] Add Volume graph (@lolrenx) +- [ ] Add Open Interest graph (@lolrenx) + +### Long term + +- [ ] Add max pain graph diff --git a/gamestonk_terminal/README.md b/gamestonk_terminal/README.md index aaf9a94e512..208ff4bcd21 100644 --- a/gamestonk_terminal/README.md +++ b/gamestonk_terminal/README.md @@ -2,7 +2,7 @@ ### Table of contents * [Discover Stocks](#Discover-Stocks-) -* [Market Sentiment](#Market-Sentiment-) +* [Behavioural Analysis](#Behavioural-Analysis-) * [Research Web pages](#Research-Web-pages) * [Fundamental Analysis](#Fundamental-Analysis-) * [Technical Analysis](#Technical-Analysis-) @@ -66,7 +66,7 @@ Command|Description|Source   -## Market Sentiment [»](sentiment/README.md) +## Behavioural Analysis [»](behavioural_analysis/README.md) Command|Description ----|---- [Reddit](https://reddit.com)| diff --git a/gamestonk_terminal/__init__.py b/gamestonk_terminal/__init__.py index f46858e0d22..bc157798fe5 100644 --- a/gamestonk_terminal/__init__.py +++ b/gamestonk_terminal/__init__.py @@ -4,5 +4,5 @@ from . import due_diligence from . import fundamental_analysis from . import papermill from . import prediction_techniques -from . import sentiment +from . import behavioural_analysis from . import technical_analysis diff --git a/gamestonk_terminal/sentiment/README.md b/gamestonk_terminal/behavioural_analysis/README.md similarity index 88% rename from gamestonk_terminal/sentiment/README.md rename to gamestonk_terminal/behavioural_analysis/README.md index 1a9e973c128..4a926a0c1e7 100644 --- a/gamestonk_terminal/sentiment/README.md +++ b/gamestonk_terminal/behavioural_analysis/README.md @@ -1,6 +1,8 @@ -# MARKET SENTIMENT +# BEHAVIOURAL ANALYSIS -This menu aims to extrapolate market's sentiment regarding a pre-loaded ticker, and the usage of the following commands along with an example will be exploited below. +This menu aims to extrapolate behavioural analysis regarding a pre-loaded ticker, and the usage of the following commands along with an example will be exploited below. + + * [finbrain](#finbrain) [REDDIT](#REDDIT) * [wsb](#wsb) @@ -12,11 +14,11 @@ This menu aims to extrapolate market's sentiment regarding a pre-loaded ticker, * [spac_c](#spac_c) - show other users spacs announcements from subreddit SPACs community * [spac](#spac) - - show other users spacs announcements from other subs + - show other users spacs announcements from other subs [STOCKTWITS](#STOCKTWITS) * [bullbear](#bullbear) - - estimate quick sentiment from last 30 messages on board + - estimate quick sentiment from last 30 messages on board * [messages](#messages) - output up to the 30 last messages on the board * [trending](#trending) @@ -29,7 +31,7 @@ This menu aims to extrapolate market's sentiment regarding a pre-loaded ticker, - infer about stock's sentiment from latest tweets * [sentiment](#sentiment) - in-depth sentiment prediction from tweets over time - + [GOOGLE](#GOOGLE) * [mentions](#mentions) - interest over time based on stock's mentions @@ -41,6 +43,17 @@ This menu aims to extrapolate market's sentiment regarding a pre-loaded ticker, - top rising related queries with stock +## finbrain +``` +usage: finbrain +``` +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: See https://finbrain.tech] + +![finbrain2](https://user-images.githubusercontent.com/25267873/111629515-49c97000-87e9-11eb-92a6-a9eebb4b4bd9.png) + +Captura de ecrã 2021-03-18, às 12 53 31 + + # REDDIT ## wsb @@ -106,7 +119,7 @@ usage: bullbear [-t S_TICKER] ``` Print bullbear sentiment based on last 30 messages on the board. Also prints the watchlist_count. [Source: Stocktwits] * -t : ticker to gather sentiment from. - + sentiment @@ -156,7 +169,7 @@ Print quick sentiment inference from last tweets that contain the ticker. This m ``` usage: sentiment [-n N_NUM] [-d N_DAYS_PAST] ``` -Plot in-depth sentiment extracted from tweets from last days that contain pre-defined ticker. This model splits the text into character-level tokens and uses the DistilBERT model to make predictions. DistilBERT is a distilled version of the powerful BERT transformer model. Note that a big num of tweets extracted per hour in conjunction with a high number of days in the past, will make the algorithm take a long period of time to estimate sentiment. Inspired by https://towardsdatascience.com/sentiment-analysis-for-stock-price-prediction-in-python-bed40c65d178. [Source: Twitter] +Plot in-depth sentiment extracted from tweets from last days that contain pre-defined ticker. This model splits the text into character-level tokens and uses the DistilBERT model to make predictions. DistilBERT is a distilled version of the powerful BERT transformer model. Note that a big num of tweets extracted per hour in conjunction with a high number of days in the past, will make the algorithm take a long period of time to estimate sentiment. Inspired by https://towardsdatascience.com/sentiment-analysis-for-stock-price-prediction-in-python-bed40c65d178. [Source: Twitter] * -n : num of tweets to extract per hour. Default 100. * -d : num of days in the past to extract tweets. Default 7. diff --git a/gamestonk_terminal/sentiment/__init__.py b/gamestonk_terminal/behavioural_analysis/__init__.py similarity index 100% rename from gamestonk_terminal/sentiment/__init__.py rename to gamestonk_terminal/behavioural_analysis/__init__.py diff --git a/gamestonk_terminal/behavioural_analysis/ba_controller.py b/gamestonk_terminal/behavioural_analysis/ba_controller.py new file mode 100644 index 00000000000..57e9a66cbe6 --- /dev/null +++ b/gamestonk_terminal/behavioural_analysis/ba_controller.py @@ -0,0 +1,249 @@ +"""Behavioural Analysis Controller Module""" +__docformat__ = "numpy" + +import argparse +from typing import List +from datetime import datetime + +from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.helper_funcs import get_flair +from gamestonk_terminal.menu import session +from gamestonk_terminal.behavioural_analysis import ( + google_view, + reddit_view, + stocktwits_view, + finbrain_view, +) +from prompt_toolkit.completion import NestedCompleter + + +class BehaviouralAnalysisController: + """Behavioural Analysis Controller class""" + + # Command choices + CHOICES = [ + "help", + "q", + "quit", + "watchlist", + "spac", + "spac_c", + "wsb", + "popular", + "bullbear", + "messages", + "trending", + "stalker", + "infer", + "sentiment", + "mentions", + "regions", + "queries", + "rise", + "finbrain", + ] + + def __init__(self, ticker: str, start: datetime): + """Constructor""" + self.ticker = ticker + self.start = start + self.ba_parser = argparse.ArgumentParser(add_help=False, prog="ba") + self.ba_parser.add_argument( + "cmd", + choices=self.CHOICES, + ) + + @staticmethod + def print_help(): + """Print help""" + + print("\nBehavioural Analysis:") + print(" help show this behavioural analysis menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print("") + print(" finbrain sentiment from 15+ major news headlines") + print("") + print("Reddit:") + print( + " wsb show what WSB gang is up to in subreddit wallstreetbets" + ) + print(" watchlist show other users watchlist") + print(" popular show popular tickers") + print( + " spac_c show other users spacs announcements from subreddit SPACs community" + ) + print(" spac show other users spacs announcements from other subs") + print("") + print("Stocktwits:") + print( + " bullbear estimate quick sentiment from last 30 messages on board" + ) + print(" messages output up to the 30 last messages on the board") + print(" trending trending stocks") + print(" stalker stalk stocktwits user's last messages") + print("") + print("Twitter:") + print(" infer infer about stock's sentiment from latest tweets") + print(" sentiment in-depth sentiment prediction from tweets over time") + print("") + print("Google:") + print(" mentions interest over time based on stock's mentions") + print(" regions regions that show highest interest in stock") + print(" queries top related queries with this stock") + print(" rise top rising related queries with stock") + print("") + + def switch(self, an_input: str): + """Process and dispatch input + + Returns + ------- + True, False or None + False - quit the menu + True - quit the program + None - continue in the menu + """ + (known_args, other_args) = self.ba_parser.parse_known_args(an_input.split()) + + return getattr( + self, "call_" + known_args.cmd, lambda: "Command not recognized!" + )(other_args) + + def call_help(self, _): + """Process Help command""" + self.print_help() + + def call_q(self, _): + """Process Q command - quit the menu""" + return False + + def call_quit(self, _): + """Process Quit command - quit the program""" + return True + + def call_watchlist(self, other_args: List[str]): + """Process watchlist command""" + reddit_view.watchlist(other_args) + + def call_spac(self, other_args: List[str]): + """Process spac command""" + reddit_view.spac(other_args) + + def call_spac_c(self, other_args: List[str]): + """Process spac_c command""" + reddit_view.spac_community(other_args) + + def call_wsb(self, other_args: List[str]): + """Process wsb command""" + reddit_view.wsb_community(other_args) + + def call_popular(self, other_args: List[str]): + """Process popular command""" + reddit_view.popular_tickers(other_args) + + def call_bullbear(self, other_args: List[str]): + """Process bullbear command""" + stocktwits_view.bullbear(other_args, self.ticker) + + def call_messages(self, other_args: List[str]): + """Process messages command""" + stocktwits_view.messages(other_args, self.ticker) + + def call_trending(self, other_args: List[str]): + """Process trending command""" + stocktwits_view.trending(other_args) + + def call_stalker(self, other_args: List[str]): + """Process stalker command""" + stocktwits_view.stalker(other_args) + + def call_mentions(self, other_args: List[str]): + """Process mentions command""" + google_view.mentions(other_args, self.ticker, self.start) + + def call_regions(self, other_args: List[str]): + """Process regions command""" + google_view.regions(other_args, self.ticker) + + def call_queries(self, other_args: List[str]): + """Process queries command""" + google_view.queries(other_args, self.ticker) + + def call_rise(self, other_args: List[str]): + """Process rise command""" + google_view.rise(other_args, self.ticker) + + def call_infer(self, other_args: List[str]): + """Process infer command""" + if not gtff.ENABLE_PREDICT: + print("Predict is not enabled in feature_flags.py") + print("Twitter inference menu is disabled", "\n") + return + + try: + # pylint: disable=import-outside-toplevel + from gamestonk_terminal.behavioural_analysis import twitter_view + except ModuleNotFoundError as e: + print("Optional packages need to be installed") + print(e, "\n") + return + except Exception as e: + print(e, "\n") + return + + twitter_view.inference(other_args, self.ticker) + + def call_sentiment(self, other_args: List[str]): + """Process sentiment command""" + if not gtff.ENABLE_PREDICT: + print("Predict is not enabled in feature_flags.py") + print("Twitter inference menu is disabled", "\n") + return + + try: + # pylint: disable=import-outside-toplevel + from gamestonk_terminal.behavioural_analysis import twitter_view + except ModuleNotFoundError as e: + print("Optional packages need to be installed") + print(e, "\n") + return + except Exception as e: + print(e, "\n") + return + + twitter_view.sentiment(other_args, self.ticker) + + def call_finbrain(self, other_args: List[str]): + """Process finbrain command""" + finbrain_view.sentiment_analysis(other_args, self.ticker) + + +def menu(ticker: str, start: datetime): + """Behavioural Analysis Menu""" + + ba_controller = BehaviouralAnalysisController(ticker, start) + ba_controller.call_help(None) + + while True: + # Get input command from user + if session and gtff.USE_PROMPT_TOOLKIT: + completer = NestedCompleter.from_nested_dict( + {c: None for c in ba_controller.CHOICES} + ) + an_input = session.prompt( + f"{get_flair()} (ba)> ", + completer=completer, + ) + else: + an_input = input(f"{get_flair()} (ba)> ") + + try: + process_input = ba_controller.switch(an_input) + + if process_input is not None: + return process_input + + except SystemExit: + print("The command selected doesn't exist\n") + continue diff --git a/gamestonk_terminal/behavioural_analysis/finbrain_view.py b/gamestonk_terminal/behavioural_analysis/finbrain_view.py new file mode 100644 index 00000000000..efc530aa77f --- /dev/null +++ b/gamestonk_terminal/behavioural_analysis/finbrain_view.py @@ -0,0 +1,161 @@ +"""Finbrain View Module""" +__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 +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 +from colorama import Fore, Style + + +register_matplotlib_converters() + + +def sentiment_coloring(val: float, last_val: float) -> str: + if float(val) > last_val: + color = Fore.GREEN + else: + color = Fore.RED + return f"{color}{val}{Style.RESET_ALL}" + + +def get_sentiment(ticker: str) -> pd.DataFrame: + """Gets Sentiment analysis provided by FinBrain's API + + Parameters + ---------- + ticker : str + Ticker to get the sentiment analysis from + + Returns + ------- + DataFrame() + Empty if there was an issue with data retrieval + """ + result = requests.get(f"https://api.finbrain.tech/v0/sentiments/{ticker}") + sentiment = pd.DataFrame() + if result.status_code == 200: + if "sentimentAnalysis" in result.json(): + sentiment = pd.DataFrame.from_dict( + result.json()["sentimentAnalysis"], orient="index" + ) + sentiment.index = pd.to_datetime(sentiment.index).to_pydatetime() + sentiment.index.name = "date" + sentiment.columns = ["Sentiment Analysis"] + else: + print("Unexpected data format from FinBrain API") + else: + print("Request error in retrieving sentiment from FinBrain API") + + return sentiment + + +def plot_sentiment(sentiment: pd.DataFrame, ticker: str): + """Plot Sentiment analysis provided by FinBrain's API + + Parameters + ---------- + sentiment : pd.DataFrame + Dataframe with sentiment data to plot + ticker : str + Ticker to get the sentiment analysis from + """ + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + for index, row in sentiment.iterrows(): + if float(row["Sentiment Analysis"]) >= 0: + plt.scatter(index, float(row["Sentiment Analysis"]), s=100, c="green") + else: + plt.scatter(index, float(row["Sentiment Analysis"]), s=100, c="red") + plt.axhline(y=0, color="k", linestyle="--", lw=2) + plt.xlabel("Time") + plt.ylabel("Sentiment") + plt.grid(b=True, which="major", color="#666666", linestyle="-") + plt.minorticks_on() + plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) + start_date = sentiment.index[-1].strftime("%Y/%m/%d") + plt.title(f"FinBrain's Sentiment Analysis for {ticker.upper()} since {start_date}") + plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d")) + plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=1)) + plt.gcf().autofmt_xdate() + plt.ylim([-1.1, 1.1]) + senValues = np.array(pd.to_numeric(sentiment["Sentiment Analysis"].values)) + senNone = np.array(0 * len(sentiment)) + plt.fill_between( + sentiment.index, + pd.to_numeric(sentiment["Sentiment Analysis"].values), + 0, + where=(senValues < senNone), + alpha=0.30, + color="red", + interpolate=True, + ) + plt.fill_between( + sentiment.index, + pd.to_numeric(sentiment["Sentiment Analysis"].values), + 0, + where=(senValues >= senNone), + alpha=0.30, + color="green", + interpolate=True, + ) + if gtff.USE_ION: + plt.ion() + plt.show() + + +def sentiment_analysis(other_args: List[str], ticker: str): + """Sentiment analysis from FinBrain + + Parameters + ---------- + other_args : List[str] + Command line arguments to be processed with argparse + ticker : str + Ticker to get the sentiment analysis from + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="finbrain", + description="""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]""", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + df_sentiment = get_sentiment(ticker) + + if not df_sentiment.empty: + plot_sentiment(df_sentiment, ticker) + + df_sentiment.sort_index(ascending=True, inplace=True) + + if gtff.USE_COLOR: + print( + df_sentiment["Sentiment Analysis"] + .apply(sentiment_coloring, last_val=0) + .to_string() + ) + else: + print(df_sentiment.to_string()) + print("") + + except Exception as e: + print(e, "\n") + print("") diff --git a/gamestonk_terminal/sentiment/google_api.py b/gamestonk_terminal/behavioural_analysis/google_view.py similarity index 100% rename from gamestonk_terminal/sentiment/google_api.py rename to gamestonk_terminal/behavioural_analysis/google_view.py diff --git a/gamestonk_terminal/sentiment/reddit_api.py b/gamestonk_terminal/behavioural_analysis/reddit_view.py similarity index 100% rename from gamestonk_terminal/sentiment/reddit_api.py rename to gamestonk_terminal/behavioural_analysis/reddit_view.py diff --git a/gamestonk_terminal/sentiment/stocktwits_api.py b/gamestonk_terminal/behavioural_analysis/stocktwits_view.py similarity index 100% rename from gamestonk_terminal/sentiment/stocktwits_api.py rename to gamestonk_terminal/behavioural_analysis/stocktwits_view.py diff --git a/gamestonk_terminal/sentiment/twitter_api.py b/gamestonk_terminal/behavioural_analysis/twitter_view.py similarity index 99% rename from gamestonk_terminal/sentiment/twitter_api.py rename to gamestonk_terminal/behavioural_analysis/twitter_view.py index dcad4037e8d..ca31ee737a7 100644 --- a/gamestonk_terminal/sentiment/twitter_api.py +++ b/gamestonk_terminal/behavioural_analysis/twitter_view.py @@ -357,7 +357,6 @@ def sentiment(l_args, s_ticker): df_tweets["created_at"].values[0], "%Y-%m-%d %H:%M:%S" ).day n_idx = 0 - n_next_idx = 0 for n_next_idx, dt_created in enumerate(df_tweets["created_at"]): if datetime.strptime(dt_created, "%Y-%m-%d %H:%M:%S").day > n_day: l_xticks.append(n_next_idx) diff --git a/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py b/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py index 31d2c662a21..edd3e726d4d 100644 --- a/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py +++ b/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py @@ -6,11 +6,11 @@ import matplotlib.pyplot as plt import yfinance as yf import seaborn as sns -from gamestonk_terminal.helper_funcs import parse_known_args_and_warn +from gamestonk_terminal.helper_funcs import parse_known_args_and_warn, plot_autoscale +from gamestonk_terminal.config_plot import PLOT_DPI register_matplotlib_converters() - d_candle_types = { "o": "Open", "h": "High", @@ -79,7 +79,7 @@ def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar): similar += ns_parser.l_also - plt.figure() + 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) plt.plot( diff --git a/gamestonk_terminal/config_terminal.py b/gamestonk_terminal/config_terminal.py index f1b8757890d..6939d823cee 100644 --- a/gamestonk_terminal/config_terminal.py +++ b/gamestonk_terminal/config_terminal.py @@ -25,3 +25,6 @@ API_POLYGON_KEY = os.getenv("GT_API_POLYGON_KEY") or "REPLACE_ME" 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" API_TWITTER_BEARER_TOKEN = os.getenv("GT_API_TWITTER_BEARER_TOKEN") or "REPLACE_ME" + +# https://fred.stlouisfed.org/docs/api/api_key.html +API_FRED_KEY = os.getenv("GT_FRED_API_KEY") or "REPLACE_ME" diff --git a/gamestonk_terminal/fred/README.md b/gamestonk_terminal/fred/README.md new file mode 100644 index 00000000000..f781a1ac1e4 --- /dev/null +++ b/gamestonk_terminal/fred/README.md @@ -0,0 +1,124 @@ +# FRED + +https://fred.stlouisfed.org + +The purpose of fred is to have the ability to look at economic data. This page offers 2 options: + +* [predefined](#gdp) + * Get predefined data +* [cust](#cust) + * Get custom fred data + +The current predefined options are +* GDP +* 1,5,10,30 Year Treasury Rates +* 30 Year Mortgage Rates +* Unemployment Rate +* Effective Federal Funds rate +* Moody's AAA Corporate Bond +* CAD to USD Conversion. + +## predefined +```text +usage: selected [-n N_TO_GET] [-s START_DATE] [--noplot] [--hidedata] +``` +Gets predefined data. Arguments +* selected : Key from the predefined list. +* -s : Start Date. Format YYYY-mm-dd. First point to get. Defaults to Jan 1 2019 +* --noplot : Flag to hide plot +* --hidedata : Flag to suppress printing output. Useful for data released daily/weekly. + +To plot the 30-Year Mortgage rates since 2018-01-01 suppressing the output. +```` +mort30 -s 2018-01-01 --hidedata +```` + +![mort30](https://user-images.githubusercontent.com/18151143/111521185-3d80dc80-872f-11eb-989d-c2bb256aa213.png) + +To show all GDP data since 1/1/2016, with no plot. +```` +gdp -s 2016-01-01 --noplot +```` +Output: +```` + GDP +Date +2016-01-01 18470.156 +2016-04-01 18656.207 +2016-07-01 18821.359 +2016-10-01 19032.580 +2017-01-01 19237.435 +2017-04-01 19379.232 +2017-07-01 19617.288 +2017-10-01 19937.963 +2018-01-01 20242.215 +2018-04-01 20552.653 +2018-07-01 20742.723 +2018-10-01 20909.853 +2019-01-01 21115.309 +2019-04-01 21329.877 +2019-07-01 21540.325 +2019-10-01 21747.394 +2020-01-01 21561.139 +2020-04-01 19520.114 +2020-07-01 21170.252 +2020-10-01 21487.896 +```` + + +## cust + +The fred database has many different datasets freely available. They each have their own custom SERIES_ID which can be obtained through the website. + +```` +usage: cust [-i --id] [-s START_DATE] [--noplot] [--hidedata] +```` +* -i/--id : Series ID for FRED data. Required argument +* -s : Start Date. Format YYYY-mm-dd. First point to get. Defaults to Jan 1 2015. +* --noplot : Flag to suppress output plot. +* --hidedata : Flag to suppress data output + +An example of custom data could be the USD/EURO exchange rate. +According to https://fred.stlouisfed.org/series/DEXUSEU , the series ID is DEXUSEU. So to plot this from the start of February 2021 to now (3/17) + +```` +cust --id DEXUSEU -s 2021-02-01 +```` +This will plot and display: +![cust](https://user-images.githubusercontent.com/18151143/111521481-92bcee00-872f-11eb-8a02-e7346e56e462.png) + +```` + DEXUSEU +Date +2021-02-01 1.2070 +2021-02-02 1.2020 +2021-02-03 1.2025 +2021-02-04 1.1974 +2021-02-05 1.2035 +2021-02-08 1.2045 +2021-02-09 1.2106 +2021-02-10 1.2132 +2021-02-11 1.2127 +2021-02-12 1.2126 +2021-02-15 NaN +2021-02-16 1.2107 +2021-02-17 1.2042 +2021-02-18 1.2078 +2021-02-19 1.2136 +2021-02-22 1.2155 +2021-02-23 1.2142 +2021-02-24 1.2143 +2021-02-25 1.2229 +2021-02-26 1.2093 +2021-03-01 1.2054 +2021-03-02 1.2079 +2021-03-03 1.2073 +2021-03-04 1.2045 +2021-03-05 1.1914 +2021-03-08 1.1849 +2021-03-09 1.1885 +2021-03-10 1.1900 +2021-03-11 1.1978 +```` + +Note the NaN on 2-15, which corresponds to President's Day. \ No newline at end of file diff --git a/gamestonk_terminal/fred/__init__.py b/gamestonk_terminal/fred/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gamestonk_terminal/fred/fred_api.py b/gamestonk_terminal/fred/fred_api.py new file mode 100644 index 00000000000..1b90ca10e87 --- /dev/null +++ b/gamestonk_terminal/fred/fred_api.py @@ -0,0 +1,191 @@ +import argparse +import pandas as pd +from pandas.plotting import register_matplotlib_converters +import matplotlib.pyplot as plt +from fredapi import Fred +from gamestonk_terminal.helper_funcs import ( + parse_known_args_and_warn, + valid_date, + plot_autoscale, +) +from gamestonk_terminal.config_plot import PLOT_DPI +from gamestonk_terminal.config_terminal import API_FRED_KEY +from gamestonk_terminal import feature_flags as gtff + +register_matplotlib_converters() + +api_map = { + "gdp": "GDP", + "t10": "DGS10", + "t1": "DGS1", + "t5": "DGS5", + "t30": "DGS30", + "mort30": "MORTGAGE30US", + "fedrate": "FEDFUNDS", + "moodAAA": "AAA", + "usdcad": "DEXCAUS", + "unemp": "UNRATE", +} +title_map = { + "gdp": "Gross Domestic Product", + "t10": "10-Year Treasury Constant Maturity Rate", + "t1": "1-Year Treasury Constant Maturity Rate", + "t5": "5-Year Treasury Constant Maturity Rate", + "t30": "30-Year Treasury Constant Maturity Rate", + "mort30": "30-Year Mortgage Rate", + "fedrate": "Effective Federal Funds Rate", + "moodAAA": "Moody's Seasoned AAA Corporate Bond Yield", + "usdcad": "Canada / U.S. Foreign Exchange Rate", + "unemp": "Unemployment Rate", +} + + +def get_fred_data(l_args, choice): + fred = Fred(api_key=API_FRED_KEY) + + parser = argparse.ArgumentParser( + add_help=False, + prog="Custom", + description=""" + Custom Data + """, + ) + + parser.add_argument( + "-s", + dest="start_date", + type=valid_date, + default="2019-01-01", + required=False, + help="Starting date (YYYY-MM-DD) of data", + ) + + parser.add_argument( + "--noplot", + action="store_false", + default=True, + dest="noplot", + help="Suppress output plot", + ) + + parser.add_argument( + "--hidedata", + action="store_false", + default=True, + dest="hidedata", + help="Suppress data display plot", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + + if not ns_parser: + return + + string_to_get = api_map[choice] + title = title_map[choice] + data = fred.get_series(string_to_get, ns_parser.start_date) + + data = pd.DataFrame(data, columns=[f"{string_to_get}"]) + data.index.name = "Date" + if ns_parser.hidedata: + print(data) + print("") + if ns_parser.noplot: + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + plt.plot(data.index, data.iloc[:, 0], "-ok") + plt.xlabel("Time") + plt.xlim(data.index[0], data.index[-1]) + plt.ylabel(f"{string_to_get}") + 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.title(title) + plt.show() + print("") + + if gtff.USE_ION: + plt.ion() + + except SystemExit: + print("") + except Exception as e: + print(e) + print("") + return + + +def custom_data(l_args): + fred = Fred(api_key=API_FRED_KEY) + + parser = argparse.ArgumentParser( + add_help=False, + prog="Custom", + description=""" + Custom Data + """, + ) + parser.add_argument( + "-i", "--id", dest="series_id", required=True, type=str, help="FRED Series ID" + ) + + parser.add_argument( + "-s", + dest="start_date", + type=valid_date, + default="2019-01-01", + required=False, + help="Starting date (YYYY-MM-DD) of data", + ) + + parser.add_argument( + "--noplot", + action="store_false", + default=True, + dest="noplot", + help="Suppress output plot", + ) + + parser.add_argument( + "--hidedata", + action="store_false", + default=True, + dest="hidedata", + help="Suppress data display plot", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + + if not ns_parser: + return + + data = fred.get_series(ns_parser.series_id, ns_parser.start_date) + + data = pd.DataFrame(data, columns=[f"{ns_parser.series_id}"]) + data.index.name = "Date" + if ns_parser.hidedata: + print(data) + print("") + if ns_parser.noplot: + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + plt.plot(data.index, data.iloc[:, 0], "-ok") + plt.xlabel("Time") + plt.xlim(data.index[0], data.index[-1]) + plt.ylabel(f"{ns_parser.series_id}") + 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.title(f"FRED {ns_parser.series_id} Series") + plt.show() + print("") + + if gtff.USE_ION: + plt.ion() + + except SystemExit: + print("") + except Exception as e: + print(e) + print("") + return diff --git a/gamestonk_terminal/fred/fred_menu.py b/gamestonk_terminal/fred/fred_menu.py new file mode 100644 index 00000000000..5a7734835be --- /dev/null +++ b/gamestonk_terminal/fred/fred_menu.py @@ -0,0 +1,90 @@ +import argparse +from matplotlib import pyplot as plt +from prompt_toolkit.completion import NestedCompleter +from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.helper_funcs import get_flair +from gamestonk_terminal.menu import session +from gamestonk_terminal.fred import fred_api + + +def print_fred(): + """ Print help """ + + print("\nFred Economic Data:") + print(" help show this menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print(" ") + print(" gdp GDP") + print(" unemp Unemployment Rate") + print(" t1 1-Year Treasury Constant Maturity Rate") + print(" t5 5-Year Treasury Constant Maturity Rate") + print(" t10 10-Year Treasury Constant Maturity Rate") + print(" t30 30-Year Treasury Constant Maturity Rate") + print(" mort30 30-Year Fixed Rate Mortgage Average") + print(" fedrate Effective Federal Funds Rate") + print(" moodAAA Moody's Seasoned AAA Corporate Bond Yield") + print(" usdcad Canada / U.S. Foreign Exchange Rate (CAD per 1 USD)") + print("") + print(" cust User Specified FRED Data - Please Specify --id") + print("") + return + + +def fred_menu(): + plt.close("all") + fred_parser = argparse.ArgumentParser(prog="fred", add_help=False) + defined_choices = [ + "gdp", + "unemp", + "t1", + "t5", + "t10", + "t30", + "mort30", + "fedrate", + "moodAAA", + "usdcad", + ] + choices = ["help", "q", "quit", "cust"] + defined_choices + + fred_parser.add_argument("cmd", choices=choices) + completer = NestedCompleter.from_nested_dict({c: None for c in choices}) + + should_print_help = True + while True: + if should_print_help: + print_fred() + should_print_help = False + + # Get input command from user + if session and gtff.USE_PROMPT_TOOLKIT: + as_input = session.prompt( + f"{get_flair()} (fred)> ", + completer=completer, + ) + else: + as_input = input(f"{get_flair()} (fred)> ") + try: + (ns_known_args, l_args) = fred_parser.parse_known_args(as_input.split()) + + except SystemExit: + print("The command selected doesn't exist\n") + continue + + if ns_known_args.cmd == "help": + should_print_help = True + + elif ns_known_args.cmd == "q": + # Leave the fred menu + return False + + elif ns_known_args.cmd == "quit": + # Abandon the program + return True + + elif ns_known_args.cmd in defined_choices: + fred_api.get_fred_data(l_args, ns_known_args.cmd) + + elif ns_known_args.cmd == "cust": + fred_api.custom_data(l_args) diff --git a/gamestonk_terminal/helper_funcs.py b/gamestonk_terminal/helper_funcs.py index 17e255bba25..1f0ab039d11 100644 --- a/gamestonk_terminal/helper_funcs.py +++ b/gamestonk_terminal/helper_funcs.py @@ -357,6 +357,16 @@ def get_flair() -> str: return "" +def str_to_bool(value): + if isinstance(value, bool): + return value + if value.lower() in {"false", "f", "0", "no", "n"}: + return False + if value.lower() in {"true", "t", "1", "yes", "y"}: + return True + raise ValueError(f"{value} is not a valid boolean value") + + def get_screeninfo(): screens = get_monitors() # Get all available monitors if len(screens) - 1 < cfgPlot.MONITOR: # Check to see if chosen monitor is detected diff --git a/gamestonk_terminal/main_helper.py b/gamestonk_terminal/main_helper.py index 30e9905287c..f83dd224180 100644 --- a/gamestonk_terminal/main_helper.py +++ b/gamestonk_terminal/main_helper.py @@ -51,9 +51,13 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open): ) print(" mill papermill menu, \t\t\t menu to generate notebook reports") print( - " sen sentiment of the market, \t from: reddit, stocktwits, twitter" + " fred economic data, \t\t\t from: Federal Reserve Bank of St. Louis " ) + if s_ticker: + print( + " ba behavioural analysis, \t from: reddit, stocktwits, twitter" + ) print( " res research web page, \t e.g.: macroaxis, yahoo finance, fool" ) @@ -72,6 +76,7 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open): print( " pred prediction techniques, \t e.g.: regression, arima, rnn, lstm, prophet" ) + print(" op options info, \t e.g.: volume") print("") diff --git a/gamestonk_terminal/options/README.md b/gamestonk_terminal/options/README.md new file mode 100644 index 00000000000..da19584da2a --- /dev/null +++ b/gamestonk_terminal/options/README.md @@ -0,0 +1,18 @@ +# OPTIONS DATA + +This menu aims to give insight on options. options can cause significant share price movement, and option pricing gives info about market sentiment for a ticker. + +* [volume](#volume) + * Show traded options for a given expiry [Yahoo Finance] + + + +## volume + +```text +usage: volume -d 'yyyy-mm-dd' +``` + +Display volume graph for a date. [Source: Yahoo Finance] + +* -d : expiration date. diff --git a/gamestonk_terminal/options/op_menu.py b/gamestonk_terminal/options/op_menu.py new file mode 100644 index 00000000000..a386a584ec2 --- /dev/null +++ b/gamestonk_terminal/options/op_menu.py @@ -0,0 +1,59 @@ +import argparse + +from prompt_toolkit.completion import NestedCompleter +from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.helper_funcs import get_flair +from gamestonk_terminal.options import volume as vol +from gamestonk_terminal.menu import session + + +def opt_menu(s_ticker): + + # Add list of arguments that the options parser accepts + opt_parser = argparse.ArgumentParser(prog="opt", add_help=False) + choices = ["help", "q", "quit", "volume", "oi"] + opt_parser.add_argument("cmd", choices=choices) + completer = NestedCompleter.from_nested_dict({c: None for c in choices}) + + # print_options(s_ticker, s_start, s_interval) + + # Loop forever and ever + while True: + # Get input command from user + if session and gtff.USE_PROMPT_TOOLKIT: + as_input = session.prompt( + f"{get_flair()} (opt)> ", + completer=completer, + ) + else: + as_input = input(f"{get_flair()} (opt)> ") + + # Parse fundamental analysis command of the list of possible commands + try: + (ns_known_args, l_args) = opt_parser.parse_known_args(as_input.split()) + + except SystemExit: + print("The command selected doesn't exist\n") + continue + + if ns_known_args.cmd == "help": + pass + # print_options(s_ticker) + + elif ns_known_args.cmd == "q": + # Just leave the options menu + return False + + elif ns_known_args.cmd == "quit": + # Abandon the program + return True + + elif ns_known_args.cmd == "volume": + # call the volume graph + vol.volume_graph(l_args, s_ticker) + + elif ns_known_args.cmd == "oi": + # call the volume graph + vol.open_interest_graph(l_args, s_ticker) + else: + print("Command not recognized!") diff --git a/gamestonk_terminal/options/volume.py b/gamestonk_terminal/options/volume.py new file mode 100644 index 00000000000..14440ef101e --- /dev/null +++ b/gamestonk_terminal/options/volume.py @@ -0,0 +1,144 @@ +import argparse +import yfinance as yf +import seaborn as sns +import pandas as pd +import matplotlib.pyplot as plt +import plotly.express as px +from gamestonk_terminal.helper_funcs import ( + parse_known_args_and_warn, + valid_date, +) + + +def open_interest_graph(l_args, s_ticker): + """ Show traded options volume. [Source: Yahoo Finance] """ + parser = argparse.ArgumentParser( + add_help=False, + prog="volume", + description="""Display volume graph for a date. [Source: Yahoo Finance].""", + ) + parser.add_argument( + "-e", + "--expiry", + type=valid_date, + dest="s_expiry_date", + help="The expiry date (format YYYY-MM-DD) for the option chain", + required=True, + ) + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + if not ns_parser: + return + + __get_open_interest_graph( + s_ticker, ns_parser.s_expiry_date.strftime("%Y-%m-%d") + ) + + except SystemExit: + print("") + except Exception as e: + print(e) + + +def volume_graph(l_args, s_ticker): + """ Show traded options volume. [Source: Yahoo Finance] """ + parser = argparse.ArgumentParser( + add_help=False, + prog="volume", + description="""Display volume graph for a date. [Source: Yahoo Finance].""", + ) + parser.add_argument( + "-e", + "--expiry", + type=valid_date, + dest="s_expiry_date", + help="The expiry date (format YYYY-MM-DD) for the option chain", + required=True, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + if not ns_parser: + return + + __get_volume_graph(s_ticker, ns_parser.s_expiry_date.strftime("%Y-%m-%d")) + + except SystemExit: + print("") + except Exception as e: + print(e) + + +def __get_open_interest_graph(ticker_name, exp_date): + df = __get_volume_data(ticker_name, exp_date) + __generate_graph_sns(df, ticker_name, exp_date, True) + # __generate_graph_plotly(df, ticker_name, exp_date) + + +def __get_volume_graph(ticker_name, exp_date): + df = __get_volume_data(ticker_name, exp_date) + __generate_graph_sns(df, ticker_name, exp_date) + # __generate_graph_plotly(df, ticker_name, exp_date) + + +def __pull_call_put_data(call_put, flag): + df = call_put.pivot_table( + index="strike", values=["volume", "openInterest"], aggfunc="sum" + ) + + df.reindex() + + df["strike"] = df.index + df["type"] = flag + + return df + + +def __get_volume_data(ticker_name, exp_date): + + option_chain = yf.Ticker(ticker_name).option_chain(exp_date) + + calls = __pull_call_put_data(option_chain.calls, "calls") + + puts = __pull_call_put_data(option_chain.puts, "puts") + + volume_data = pd.concat([calls, puts], axis=0) + # dataframe + return volume_data + + +def __generate_graph_plotly(df, ticker_name, exp_date, for_open_interest=False): + # version with plotly express + if for_open_interest: + op_type = "openInterest" + else: + op_type = "volume" + + fig = px.line( + df, + x="strike", + y=op_type, + title=f"{ticker_name} options {op_type} for {exp_date}", + color="type", + ) + fig.show() + + return + + +def __generate_graph_sns(df, ticker_name, exp_date, for_open_interest=False): + # version with seaborn express + if for_open_interest: + op_type = "openInterest" + else: + op_type = "volume" + + plt.figure(figsize=(12, 6)) + fig = sns.lineplot( + data=df, x="strike", y=op_type, hue="type", palette=["limegreen", "tomato"] + ) + + plt.title(f"{ticker_name} options {op_type} for {exp_date}") + + plt.show() + return fig diff --git a/gamestonk_terminal/prediction_techniques/arima.py b/gamestonk_terminal/prediction_techniques/arima.py index 5ed5b4e45b7..e68ac8aad8b 100644 --- a/gamestonk_terminal/prediction_techniques/arima.py +++ b/gamestonk_terminal/prediction_techniques/arima.py @@ -11,6 +11,7 @@ from gamestonk_terminal.helper_funcs import ( valid_date, patch_pandas_text_adjustment, get_next_stock_market_days, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( print_pretty_prediction, @@ -18,6 +19,7 @@ from gamestonk_terminal.prediction_techniques.pred_helper import ( print_prediction_kpis, ) +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() @@ -168,7 +170,7 @@ def arima(l_args, s_ticker, df_stock): print("") # Plotting - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) if ns_parser.s_order: # BACKTESTING @@ -241,7 +243,7 @@ def arima(l_args, s_ticker, df_stock): # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/prediction_techniques/ets.py b/gamestonk_terminal/prediction_techniques/ets.py index a802b0cc977..96e17306d78 100644 --- a/gamestonk_terminal/prediction_techniques/ets.py +++ b/gamestonk_terminal/prediction_techniques/ets.py @@ -11,6 +11,7 @@ from gamestonk_terminal.helper_funcs import ( valid_date, patch_pandas_text_adjustment, get_next_stock_market_days, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( print_pretty_prediction, @@ -18,6 +19,7 @@ from gamestonk_terminal.prediction_techniques.pred_helper import ( print_prediction_kpis, ) +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() @@ -179,7 +181,7 @@ def exponential_smoothing(l_args, s_ticker, df_stock): print(f"SSE: {round(model.sse, 2)}\n") # Plotting - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) # BACKTESTING if ns_parser.s_end_date: @@ -249,7 +251,7 @@ def exponential_smoothing(l_args, s_ticker, df_stock): # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/prediction_techniques/fbprophet.py b/gamestonk_terminal/prediction_techniques/fbprophet.py index 21447c7d1ca..e2294791b6c 100644 --- a/gamestonk_terminal/prediction_techniques/fbprophet.py +++ b/gamestonk_terminal/prediction_techniques/fbprophet.py @@ -11,12 +11,14 @@ from gamestonk_terminal.helper_funcs import ( parse_known_args_and_warn, valid_date, patch_pandas_text_adjustment, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( price_prediction_backtesting_color, print_prediction_kpis, ) +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() @@ -114,7 +116,7 @@ def fbprophet(l_args, s_ticker, df_stock): ] # .apply(lambda x: f"{x:.2f} $") df_pred.index = l_pred_days - _, ax = plt.subplots() + _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) model.plot( forecast[: -ns_parser.n_days], ax=ax, @@ -177,7 +179,7 @@ def fbprophet(l_args, s_ticker, df_stock): # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/prediction_techniques/knn.py b/gamestonk_terminal/prediction_techniques/knn.py index ba44c3dc887..01de4c62b84 100644 --- a/gamestonk_terminal/prediction_techniques/knn.py +++ b/gamestonk_terminal/prediction_techniques/knn.py @@ -11,6 +11,7 @@ from gamestonk_terminal.helper_funcs import ( valid_date, patch_pandas_text_adjustment, get_next_stock_market_days, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( print_pretty_prediction, @@ -18,7 +19,7 @@ from gamestonk_terminal.prediction_techniques.pred_helper import ( print_prediction_kpis, ) - +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() @@ -143,7 +144,7 @@ def k_nearest_neighbors(l_args, s_ticker, df_stock): df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) s_knn = f"{ns_parser.n_neighbors}-Nearest Neighbors on {s_ticker}" # BACKTESTING @@ -202,7 +203,7 @@ def k_nearest_neighbors(l_args, s_ticker, df_stock): # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/prediction_techniques/neural_networks.py b/gamestonk_terminal/prediction_techniques/neural_networks.py index ee652eaf361..6fd0a356abd 100644 --- a/gamestonk_terminal/prediction_techniques/neural_networks.py +++ b/gamestonk_terminal/prediction_techniques/neural_networks.py @@ -18,6 +18,7 @@ from gamestonk_terminal.helper_funcs import ( valid_date, patch_pandas_text_adjustment, get_next_stock_market_days, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( @@ -28,6 +29,7 @@ from gamestonk_terminal.prediction_techniques.pred_helper import ( from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import config_neural_network_models as cfg_nn_models @@ -348,7 +350,7 @@ def _plot_and_print_results( ): """Plot and print the results. """ # Plotting - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=3) # BACKTESTING @@ -413,7 +415,7 @@ def _plot_and_print_results( # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/prediction_techniques/regression.py b/gamestonk_terminal/prediction_techniques/regression.py index c454feededb..8e02f37b44b 100644 --- a/gamestonk_terminal/prediction_techniques/regression.py +++ b/gamestonk_terminal/prediction_techniques/regression.py @@ -14,6 +14,7 @@ from gamestonk_terminal.helper_funcs import ( valid_date, patch_pandas_text_adjustment, get_next_stock_market_days, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( @@ -22,7 +23,7 @@ from gamestonk_terminal.prediction_techniques.pred_helper import ( print_prediction_kpis, ) - +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() @@ -163,7 +164,7 @@ def regression(l_args, s_ticker, df_stock, polynomial): df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) # BACKTESTING if ns_parser.s_end_date: @@ -225,7 +226,7 @@ def regression(l_args, s_ticker, df_stock, polynomial): # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/prediction_techniques/sma.py b/gamestonk_terminal/prediction_techniques/sma.py index 6b0504c1794..b371553343c 100644 --- a/gamestonk_terminal/prediction_techniques/sma.py +++ b/gamestonk_terminal/prediction_techniques/sma.py @@ -11,6 +11,7 @@ from gamestonk_terminal.helper_funcs import ( valid_date, patch_pandas_text_adjustment, get_next_stock_market_days, + plot_autoscale, ) from gamestonk_terminal.prediction_techniques.pred_helper import ( @@ -19,7 +20,7 @@ from gamestonk_terminal.prediction_techniques.pred_helper import ( print_prediction_kpis, ) - +from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() @@ -125,7 +126,7 @@ def simple_moving_average(l_args, s_ticker, df_stock): df_pred = pd.Series(l_predictions, index=l_pred_days, name="Price") # Plotting - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.plot(df_stock.index, df_stock["5. adjusted close"], lw=2) # BACKTESTING if ns_parser.s_end_date: @@ -189,7 +190,7 @@ def simple_moving_average(l_args, s_ticker, df_stock): # BACKTESTING if ns_parser.s_end_date: - plt.figure() + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) plt.subplot(211) plt.plot( df_future.index, diff --git a/gamestonk_terminal/sentiment/sen_menu.py b/gamestonk_terminal/sentiment/sen_menu.py deleted file mode 100644 index c35cf5df95e..00000000000 --- a/gamestonk_terminal/sentiment/sen_menu.py +++ /dev/null @@ -1,192 +0,0 @@ -import argparse - -from gamestonk_terminal import feature_flags as gtff -from gamestonk_terminal.helper_funcs import get_flair -from gamestonk_terminal.menu import session -from gamestonk_terminal.sentiment import google_api, reddit_api, stocktwits_api -from prompt_toolkit.completion import NestedCompleter - - -def print_sentiment(): - """ Print help """ - - print("\nSentiment:") - print(" help show this sentiment menu again") - print(" q quit this menu, and shows back to main menu") - print(" quit quit to abandon program") - print("") - print("Reddit:") - print(" wsb show what WSB gang is up to in subreddit wallstreetbets") - print(" watchlist show other users watchlist") - print(" popular show popular tickers") - print( - " spac_c show other users spacs announcements from subreddit SPACs community" - ) - print(" spac show other users spacs announcements from other subs") - print("") - print("Stocktwits:") - print(" bullbear estimate quick sentiment from last 30 messages on board") - print(" messages output up to the 30 last messages on the board") - print(" trending trending stocks") - print(" stalker stalk stocktwits user's last messages") - print("") - print("Twitter:") - print(" infer infer about stock's sentiment from latest tweets") - print(" sentiment in-depth sentiment prediction from tweets over time") - print("") - print("Google:") - print(" mentions interest over time based on stock's mentions") - print(" regions regions that show highest interest in stock") - print(" queries top related queries with this stock") - print(" rise top rising related queries with stock") - print("") - - return - - -def sen_menu(s_ticker, s_start): - - # Add list of arguments that the discovery parser accepts - sen_parser = argparse.ArgumentParser(prog="sen", add_help=False) - choices = [ - "help", - "q", - "quit", - "watchlist", - "spac", - "spac_c", - "wsb", - "popular", - "bullbear", - "messages", - "trending", - "stalker", - "infer", - "sentiment", - "mentions", - "regions", - "queries", - "rise", - ] - sen_parser.add_argument("cmd", choices=choices) - completer = NestedCompleter.from_nested_dict({c: None for c in choices}) - - print_sentiment() - - # Loop forever and ever - while True: - # Get input command from user - if session and gtff.USE_PROMPT_TOOLKIT: - as_input = session.prompt( - f"{get_flair()} (sen)> ", - completer=completer, - ) - else: - as_input = input(f"{get_flair()} (sen)> ") - - # Parse sentiment command of the list of possible commands - try: - (ns_known_args, l_args) = sen_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_sentiment() - - elif ns_known_args.cmd == "q": - # Just leave the DISC menu - return False - - elif ns_known_args.cmd == "quit": - # Abandon the program - return True - - elif ns_known_args.cmd == "watchlist": - reddit_api.watchlist(l_args) - - elif ns_known_args.cmd == "spac": - reddit_api.spac(l_args) - - elif ns_known_args.cmd == "spac_c": - reddit_api.spac_community(l_args) - - elif ns_known_args.cmd == "wsb": - reddit_api.wsb_community(l_args) - - elif ns_known_args.cmd == "popular": - reddit_api.popular_tickers(l_args) - - elif ns_known_args.cmd == "bullbear": - stocktwits_api.bullbear(l_args, s_ticker) - - elif ns_known_args.cmd == "messages": - stocktwits_api.messages(l_args, s_ticker) - - elif ns_known_args.cmd == "trending": - stocktwits_api.trending(l_args) - - elif ns_known_args.cmd == "stalker": - stocktwits_api.stalker(l_args) - - elif ns_known_args.cmd == "infer": - if not gtff.ENABLE_PREDICT: - print("Predict is not enabled in feature_flags.py") - print("Twitter inference menu is disabled") - print("") - continue - - try: - # pylint: disable=import-outside-toplevel - from gamestonk_terminal.sentiment import twitter_api - except ModuleNotFoundError as e: - print("One of the optional packages seems to be missing") - print("Optional packages need to be installed") - print(e) - print("") - continue - except Exception as e: - print(e) - print("") - continue - - twitter_api.inference(l_args, s_ticker) - - elif ns_known_args.cmd == "sentiment": - if not gtff.ENABLE_PREDICT: - print("Predict is not enabled in config_terminal.py") - print("Twitter sentiment menu is disabled") - print("") - continue - - try: - # pylint: disable=import-outside-toplevel - from gamestonk_terminal.sentiment import twitter_api - except ModuleNotFoundError as e: - print("One of the optional packages seems to be missing") - print("Optional packages need to be installed") - print(e) - print("") - continue - except Exception as e: - print(e) - print("") - continue - - twitter_api.sentiment(l_args, s_ticker) - - elif ns_known_args.cmd == "mentions": - google_api.mentions(l_args, s_ticker, s_start) - - elif ns_known_args.cmd == "regions": - google_api.regions(l_args, s_ticker) - - elif ns_known_args.cmd == "queries": - google_api.queries(l_args, s_ticker) - - elif ns_known_args.cmd == "rise": - google_api.rise(l_args, s_ticker) - - else: - print("Command not recognized!") diff --git a/poetry.lock b/poetry.lock index 5b554d913be..45b449e6623 100644 --- a/poetry.lock +++ b/poetry.lock @@ -476,6 +476,17 @@ category = "main" optional = true python-versions = "*" +[[package]] +name = "fredapi" +version = "0.4.3" +description = "Python API for Federal Reserve Economic Data (FRED) from St. Louis Fed" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pandas = "*" + [[package]] name = "ftfy" version = "5.9" @@ -2506,7 +2517,8 @@ prediction = ["fbprophet", "tensorflow", "pmdarima", "transformers", "flair", "t [metadata] lock-version = "1.1" python-versions = "^3.6.8" -content-hash = "c4a363cd8824c8ccab409ccfc74956db82f9cf9800cd46539b14c7ea927f36de" +content-hash = "184502c6b8d4b7db5baa4323e7f70b2585c6140c304583f0678e24681b8f9c9b" + [metadata.files] absl-py = [ @@ -2810,6 +2822,10 @@ flatbuffers = [ {file = "flatbuffers-1.12-py2.py3-none-any.whl", hash = "sha256:9e9ef47fa92625c4721036e7c4124182668dc6021d9e7c73704edd395648deb9"}, {file = "flatbuffers-1.12.tar.gz", hash = "sha256:63bb9a722d5e373701913e226135b28a6f6ac200d5cc7b4d919fa38d73b44610"}, ] +fredapi = [ + {file = "fredapi-0.4.3-py3-none-any.whl", hash = "sha256:e06075592eabddadfe0635f3c59e9072c9f48647430328b4582171ea10f7df2f"}, + {file = "fredapi-0.4.3.tar.gz", hash = "sha256:d9b3194fb60541991bd33f019c710d4a9580ecfb5e47efbf2d2571888a2aac02"}, +] ftfy = [ {file = "ftfy-5.9.tar.gz", hash = "sha256:8c4fb2863c0b82eae2ab3cf353d9ade268dfbde863d322f78d6a9fd5cefb31e9"}, ] diff --git a/pyproject.toml b/pyproject.toml index e775e13f428..84c831a6e37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ jupyter = "^1.0.0" mplfinance = "^0.12.7-alpha.7" seaborn = "^0.11.0" scipy = "1.5.4" +fredapi = "^0.4.3" screeninfo = "^0.6.7" [tool.poetry.dev-dependencies] diff --git a/requirements.txt b/requirements.txt index 8c767a55b06..06971cc844c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,6 +25,7 @@ decorator==4.4.2; python_full_version >= "3.6.1" and python_version >= "3.6" and defusedxml==0.7.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" entrypoints==0.3; python_version >= "3.6" finviz==1.3.4 +fredapi==0.4.3 fundamentalanalysis==0.2.6 hijri-converter==2.1.1; python_version >= "3.6" holidays==0.10.5.2 diff --git a/terminal.py b/terminal.py index 4969ab67c9d..7dcf72edb9c 100644 --- a/terminal.py +++ b/terminal.py @@ -19,9 +19,11 @@ from gamestonk_terminal.helper_funcs import b_is_stock_market_open, get_flair from gamestonk_terminal.main_helper import clear, export, load, print_help, view, candle from gamestonk_terminal.menu import session from gamestonk_terminal.papermill import papermill_controller as mill -from gamestonk_terminal.sentiment import sen_menu as sm +from gamestonk_terminal.behavioural_analysis import ba_controller from gamestonk_terminal.technical_analysis import ta_menu as tam from gamestonk_terminal.comparison_analysis import ca_menu as cam +from gamestonk_terminal.options import op_menu as opm +from gamestonk_terminal.fred import fred_menu as fm # import warnings # warnings.simplefilter("always") @@ -64,13 +66,15 @@ def main(): "export", "disc", "mill", - "sen", + "ba", "res", "fa", "ta", "dd", "pred", "ca", + "op", + "fred", ] menu_parser.add_argument("opt", choices=choices) completer = NestedCompleter.from_nested_dict({c: None for c in choices}) @@ -160,8 +164,8 @@ def main(): elif ns_known_args.opt == "mill": b_quit = mill.papermill_menu() - elif ns_known_args.opt == "sen": - b_quit = sm.sen_menu(s_ticker, s_start) + elif ns_known_args.opt == "ba": + b_quit = ba_controller.menu(s_ticker, s_start) elif ns_known_args.opt == "res": b_quit = rm.res_menu(s_ticker, s_start, s_interval) @@ -178,6 +182,12 @@ def main(): elif ns_known_args.opt == "dd": b_quit = ddm.dd_menu(df_stock, s_ticker, s_start, s_interval) + elif ns_known_args.opt == "op": + b_quit = opm.opt_menu(s_ticker) + + elif ns_known_args.opt == "fred": + b_quit = fm.fred_menu() + elif ns_known_args.opt == "pred": if not gtff.ENABLE_PREDICT: @@ -224,7 +234,6 @@ def main(): except Exception as e: print(e) print("Either the ticker or the API_KEY are invalids. Try again!") - b_quit = False return else: diff --git a/tests/test_ba_finbrain_api.py b/tests/test_ba_finbrain_api.py new file mode 100644 index 00000000000..03893ac0166 --- /dev/null +++ b/tests/test_ba_finbrain_api.py @@ -0,0 +1,10 @@ +""" behavioural_analysis/finbrain_view.py tests """ +import unittest + +# from gamestonk_terminal.behavioural_analysis.finbrain_view import sentiment_analysis + + +class TestBaFinbrainApi(unittest.TestCase): + def test_sentiment_analysis(self): + # sentiment_analysis([], "TSLA") + print("") diff --git a/tests/test_sentiment_twitter_api.py b/tests/test_sentiment_twitter_api.py index fa536db0754..ffe00494486 100644 --- a/tests/test_sentiment_twitter_api.py +++ b/tests/test_sentiment_twitter_api.py @@ -4,7 +4,10 @@ import unittest # pylint: disable=unused-import try: - from gamestonk_terminal.sentiment.twitter_api import inference, sentiment + from gamestonk_terminal.behavioural_analysis.twitter_view import ( + inference, + sentiment, + ) except ModuleNotFoundError as e: print("One of the optional packages seems to be missing") print(e)