From bb9ab3a9d2f151f0e2569a285de0d3b3b802fb62 Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 17:22:39 +0000 Subject: [PATCH 01/14] add exploratory data analysis menu --- .../exploratory_data_analysis/eda_api.py | 619 ++++++++++++++++++ .../eda_controller.py | 172 +++++ gamestonk_terminal/main_helper.py | 3 + terminal.py | 23 + 4 files changed, 817 insertions(+) create mode 100644 gamestonk_terminal/exploratory_data_analysis/eda_api.py create mode 100644 gamestonk_terminal/exploratory_data_analysis/eda_controller.py diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_api.py b/gamestonk_terminal/exploratory_data_analysis/eda_api.py new file mode 100644 index 00000000000..11cf7b4263d --- /dev/null +++ b/gamestonk_terminal/exploratory_data_analysis/eda_api.py @@ -0,0 +1,619 @@ +""" Exploratory Data Analysis API """ +__docformat__ = "numpy" + +import argparse +from typing import List +from detecta import detect_cusum +from matplotlib import pyplot as plt +import pandas as pd +from pandas.plotting import register_matplotlib_converters +import numpy as np +import seaborn as sns +import statsmodels.api as sm +import matplotlib.gridspec as gridspec +from statsmodels.tsa.seasonal import seasonal_decompose +from gamestonk_terminal.helper_funcs import ( + parse_known_args_and_warn, + plot_autoscale, + check_positive, +) +from gamestonk_terminal.config_plot import PLOT_DPI +from gamestonk_terminal import feature_flags as gtff + + +register_matplotlib_converters() + + +def summary(other_args: List[str], stock: pd.DataFrame): + """Print summary statistics + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="summary", + description=""" + Summary statistics + """, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + df_stats = stock.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9]) + df_stats.loc["var"] = df_stats.loc["std"] ** 2 + print(df_stats.round(2).to_string()) + + print("") + + except Exception as e: + print(e, "\n") + return + + +def hist(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Plot histogram and density + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="hist", + description=""" + Histogram with depicted density and rug + """, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + + stock = stock["5. adjusted close"] + + sns.distplot( + stock, + bins=35, + color="blue", + hist=True, + hist_kws={"edgecolor": "black"}, + kde=True, + kde_kws={"color": "black", "lw": 3, "label": "KDE"}, + rug=True, + rug_kws={"edgecolor": "orange"}, + ) + plt.title(ticker + " (Histogram with Density)") + plt.ylabel("Density") + plt.xlabel("Share Price") + plt.grid(True) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return + + +def cdf(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Plot cumulative distribution function + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="cdf", + description=""" + Cumulative distribution function + """, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + + stock = stock["5. adjusted close"] + + cdf = stock.value_counts().sort_index().div(len(stock)).cumsum() + cdf.plot(lw=2) + plt.title(ticker + " (Cumulative Distribution Function)") + plt.ylabel("Probability") + plt.xlabel("Share Price") + minVal = stock.values.min() + q25 = np.quantile(stock.values, 0.25) + medianVal = np.quantile(stock.values, 0.5) + q75 = np.quantile(stock.values, 0.75) + data = [ + (minVal, q25), + (0.25, 0.25), + "r", + (q25, q25), + (0, 0.25), + "r", + (minVal, medianVal), + (0.5, 0.5), + "r", + (medianVal, medianVal), + (0, 0.5), + "r", + (minVal, q75), + (0.75, 0.75), + "r", + (q75, q75), + (0, 0.75), + "r", + ] + plt.plot(*data, ls="--") + plt.text(minVal + (q25 - minVal) / 2, 0.27, "Q1", color="r", fontweight="bold") + plt.text( + minVal + (medianVal - minVal) / 2, + 0.52, + "Median", + color="r", + fontweight="bold", + ) + plt.text(minVal + (q75 - minVal) / 2, 0.77, "Q3", color="r", fontweight="bold") + plt.xlim(cdf.index[0], cdf.index[-1]) + plt.grid(True) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return + + +def bwy(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Box and Whisker plot yearly + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="bwy", + description=""" + Box and Whisker plot yearly + """, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + + stock = stock["5. adjusted close"] + + sns.set(style="whitegrid") + box_plot = sns.boxplot(x=stock.index.year, y=stock) + box_plot.set( + xlabel="Year", ylabel="Share Price", title=ticker + " (Box-plot per Year)" + ) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return + + +def bwm(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Box and Whisker plot monthly + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="bwm", + description=""" + Box and Whisker plot monthly + """, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + + stock = stock["5. adjusted close"] + + sns.set(style="whitegrid") + box_plot = sns.boxplot(x=stock.index.month, y=stock) + box_plot.set( + xlabel="Month", + ylabel="Share Price", + title=ticker + " (Box-plot per Month)", + ) + l_months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ] + l_ticks = list() + for val in box_plot.get_xticklabels(): + l_ticks.append(l_months[int(val.get_text()) - 1]) + box_plot.set_xticklabels(l_ticks) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return + + +def rolling(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Rolling mean and std deviation + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="rolling", + description=""" + Rolling mean and std deviation + """, + ) + parser.add_argument( + "-w", + "--window", + dest="rolling_window", + type=check_positive, + default=100, + help="rolling window", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + stock = stock["5. adjusted close"] + + rolling_mean = stock.rolling( + ns_parser.rolling_window, center=True, min_periods=1 + ).mean() + rolling_std = stock.rolling( + ns_parser.rolling_window, center=True, min_periods=1 + ).std() + + fig, axMean = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + + axMean.plot(stock.index, stock.values, label=ticker, linewidth=2, color="black") + axMean.plot(rolling_mean, linestyle="--", linewidth=3, color="blue") + axMean.set_xlabel("Time") + axMean.set_ylabel("Share Price", color="blue") + axMean.legend(["Real values", "Rolling Mean"], loc=2) + axMean.tick_params(axis="y", labelcolor="blue") + axStd = axMean.twinx() + axStd.plot( + rolling_std, label="Rolling std", linestyle="--", color="green", linewidth=3 + ) + axStd.set_ylabel("Std Deviation") + axStd.legend(["Rolling std"], loc=1) + axStd.set_ylabel("Share Price standard deviation", color="green") + axStd.tick_params(axis="y", labelcolor="green") + axMean.set_title( + "Rolling mean and std with window " + + str(ns_parser.rolling_window) + + " applied to " + + ticker + ) + plt.xlim([stock.index[0], stock.index[-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) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return + + +def decompose(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Decompose time series as: + - Additive Time Series = Level + CyclicTrend + Residual + Seasonality + - Multiplicative Time Series = Level * CyclicTrend * Residual * Seasonality + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="decompose", + description=""" + Decompose time series as: + - Additive Time Series = Level + CyclicTrend + Residual + Seasonality + - Multiplicative Time Series = Level * CyclicTrend * Residual * Seasonality + """, + ) + parser.add_argument( + "-m", + "--multiplicative", + action="store_true", + default=False, + dest="multiplicative", + help="decompose using multiplicative model instead of additive", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + stock = stock["5. adjusted close"] + + seasonal_periods = 5 + # Hodrick-Prescott filter + # See Ravn and Uhlig: http://home.uchicago.edu/~huhlig/papers/uhlig.ravn.res.2002.pdf + lamb = 107360000000 + + fig = plt.figure( + figsize=plot_autoscale(), dpi=PLOT_DPI, constrained_layout=True + ) + spec = gridspec.GridSpec(ncols=4, nrows=5, figure=fig) + + fig.add_subplot(spec[0, :]) + plt.plot(stock) + + plt.title(ticker + " (Time-Series)") + + if ns_parser.multiplicative: + resultMul = seasonal_decompose( + stock, model="multiplicative", period=seasonal_periods + ) + cycleMul, trendMul = sm.tsa.filters.hpfilter( + resultMul.trend[resultMul.trend.notna().values], lamb=lamb + ) + + # Multiplicative model + fig.add_subplot(spec[1, :4]) + plt.plot(resultMul.trend, lw=2, c="purple") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Multiplicative Cyclic-Trend") + + fig.add_subplot(spec[2, 0:2]) + plt.plot(trendMul, lw=2, c="tab:blue") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Multiplicative Trend component") + + fig.add_subplot(spec[2, 2:]) + plt.plot(cycleMul, lw=2, c="green") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Multiplicative Cycle component") + + fig.add_subplot(spec[3, :]) + plt.plot(resultMul.seasonal, lw=2, c="orange") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Multiplicative Seasonal effect") + + fig.add_subplot(spec[4, :]) + plt.plot(resultMul.resid, lw=2, c="red") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Multiplicative Residuals") + + else: + resultAdd = seasonal_decompose( + stock, model="additive", period=seasonal_periods + ) + cycleAdd, trendAdd = sm.tsa.filters.hpfilter( + resultAdd.trend[resultAdd.trend.notna().values], lamb=lamb + ) + + # Additive model + fig.add_subplot(spec[1, :4]) + plt.plot(resultAdd.trend, lw=2, c="purple") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Additive Cyclic-Trend") + + fig.add_subplot(spec[2, 0:2]) + plt.plot(trendAdd, lw=2, c="tab:blue") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Additive Trend component") + + fig.add_subplot(spec[2, 2:]) + plt.plot(cycleAdd, lw=2, c="green") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Additive Cycle component") + + fig.add_subplot(spec[3, :]) + plt.plot(resultAdd.seasonal, lw=2, c="orange") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Additive Seasonal effect") + + fig.add_subplot(spec[4, :]) + plt.plot(resultAdd.resid, lw=2, c="red") + plt.xlim([stock.index[0], stock.index[-1]]) + plt.title("Additive Residuals") + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + # From # https://otexts.com/fpp2/seasonal-strength.html + + print("Time-Series Level is " + str(round(stock.mean(), 2))) + + if ns_parser.multiplicative: + FtMul = max(0, 1 - np.var(resultMul.resid)) / np.var( + resultMul.trend + resultMul.resid + ) + print("Strenght of Trend: %.4f" % FtMul) + FsMul = max( + 0, + 1 + - np.var(resultMul.resid) + / np.var(resultMul.seasonal + resultMul.resid), + ) + print("Strenght of Seasonality: %.4f" % FsMul) + + else: + FtAdd = max( + 0, + 1 - np.var(resultAdd.resid) / np.var(resultAdd.trend + resultAdd.resid), + ) + print("Strenght of Trend: %.4f" % FtAdd) + FsAdd = max( + 0, + 1 + - np.var(resultAdd.resid) + / np.var(resultAdd.seasonal + resultAdd.resid), + ) + print("Strenght of Seasonality: %.4f" % FsAdd) + print("") + + except Exception as e: + print(e, "\n") + return + + +def cusum(other_args: List[str], ticker: str, stock: pd.DataFrame): + """Cumulative sum algorithm (CUSUM) to detect abrupt changes in data + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="cusum", + description=""" + Cumulative sum algorithm (CUSUM) to detect abrupt changes in data + """, + ) + parser.add_argument( + "-t", + "--threshold", + dest="threshold", + type=float, + default=( + max(stock["5. adjusted close"].values) + - min(stock["5. adjusted close"].values) + ) + / 40, + help="threshold", + ) + parser.add_argument( + "-d", + "--drift", + dest="drift", + type=float, + default=( + max(stock["5. adjusted close"].values) + - min(stock["5. adjusted close"].values) + ) + / 80, + help="drift", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + stock = stock["5. adjusted close"] + + detect_cusum(stock.values, ns_parser.threshold, ns_parser.drift, True, True) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py new file mode 100644 index 00000000000..1ed8ea818a8 --- /dev/null +++ b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py @@ -0,0 +1,172 @@ +"""Exploratory Data Analysis Controller Module""" +__docformat__ = "numpy" + +import argparse +from typing import List +from datetime import datetime +import pandas as pd +from matplotlib import pyplot as plt +from gamestonk_terminal.exploratory_data_analysis import eda_api +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.menu import session +from prompt_toolkit.completion import NestedCompleter + + +class EdaController: + """EDA Controller class""" + + # Command choices + CHOICES = [ + "help", + "q", + "quit", + "summary", + "hist", + "cdf", + "bwy", + "bwm", + "rolling", + "decompose", + "cusum", + ] + + def __init__( + self, + stock: pd.DataFrame, + ticker: str, + start: datetime, + interval: str, + ): + """Constructor""" + self.stock = stock + self.ticker = ticker + self.start = start + self.interval = interval + self.stats_parser = argparse.ArgumentParser(add_help=False, prog="stats") + self.stats_parser.add_argument( + "cmd", + choices=self.CHOICES, + ) + + @staticmethod + def print_help(self): + """Print help""" + + s_intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"] + + if self.start: + print( + f"\n{s_intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})" + ) + else: + print(f"\n{s_intraday} Stock: {self.ticker}") + + print("\nExploratory Data Analysis:") + print(" help show this comparison analysis menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print("") + print(" summary brief summary statistics") + print(" hist histogram with density plot") + print(" cdf cumulative distribution function") + print(" bwy box and whisker yearly plot") + print(" bwm box and whisker monthly plot") + print(" rolling rolling mean and std deviation") + print(" decompose decomposition in cyclic-trend, season, and residuals") + print(" cusum detects abrupt changes using cumulative sum algorithm") + print("") + return + + 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.stats_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(self) + + 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_summary(self, other_args: List[str]): + """Process summary command""" + eda_api.summary(other_args, self.stock) + + def call_hist(self, other_args: List[str]): + """Process hist command""" + eda_api.hist(other_args, self.ticker, self.stock) + + def call_cdf(self, other_args: List[str]): + """Process cdf command""" + eda_api.cdf(other_args, self.ticker, self.stock) + + def call_bwy(self, other_args: List[str]): + """Process bwy command""" + eda_api.bwy(other_args, self.ticker, self.stock) + + def call_bwm(self, other_args: List[str]): + """Process bwm command""" + eda_api.bwm(other_args, self.ticker, self.stock) + + def call_rolling(self, other_args: List[str]): + """Process rolling command""" + eda_api.rolling(other_args, self.ticker, self.stock) + + def call_decompose(self, other_args: List[str]): + """Process decompose command""" + eda_api.decompose(other_args, self.ticker, self.stock) + + def call_cusum(self, other_args: List[str]): + """Process cusum command""" + eda_api.cusum(other_args, self.ticker, self.stock) + + +def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str): + """Statistics Menu""" + + eda_controller = EdaController(stock, ticker, start, interval) + eda_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 eda_controller.CHOICES} + ) + an_input = session.prompt( + f"{get_flair()} (eda)> ", + completer=completer, + ) + else: + an_input = input(f"{get_flair()} (eda)> ") + + try: + plt.close("all") + + process_input = eda_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/main_helper.py b/gamestonk_terminal/main_helper.py index c5d95f067f3..cabd406e89c 100644 --- a/gamestonk_terminal/main_helper.py +++ b/gamestonk_terminal/main_helper.py @@ -75,6 +75,9 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open): print( " dd in-depth due-diligence, \t e.g.: news, analyst, shorts, insider, sec" ) + print( + " eda exploratory data analysis,\t e.g.: decompose, cusum, residuals analysis" + ) print( " pred prediction techniques, \t e.g.: regression, arima, rnn, lstm, prophet" ) diff --git a/terminal.py b/terminal.py index e9e9665eabc..8baac4c4cff 100644 --- a/terminal.py +++ b/terminal.py @@ -23,6 +23,7 @@ from gamestonk_terminal.papermill import papermill_controller as mill 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_controller +from gamestonk_terminal.exploratory_data_analysis import eda_controller from gamestonk_terminal.options import op_controller from gamestonk_terminal.fred import fred_menu as fm from gamestonk_terminal.portfolio import port_controller @@ -75,6 +76,7 @@ def main(): "fa", "ta", "dd", + "eda", "pred", "ca", "op", @@ -202,6 +204,27 @@ 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 == "eda": + if s_interval == "1440min": + b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval) + else: + df_stock = yf.download( + ns_parser.s_ticker, start=ns_parser.s_start_date, progress=False + ) + df_stock = df_stock.rename( + columns={ + "Open": "1. open", + "High": "2. high", + "Low": "3. low", + "Close": "4. close", + "Adj Close": "5. adjusted close", + "Volume": "6. volume", + } + ) + df_stock.index.name = "date" + + b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval) + elif ns_known_args.opt == "op": b_quit = op_controller.menu(s_ticker) From f173a1b1f3ede3217ede844a362ee7b16e7de860 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Sat, 27 Mar 2021 17:46:40 +0000 Subject: [PATCH 02/14] EDA readme --- .../exploratory_data_analysis/README.md | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 gamestonk_terminal/exploratory_data_analysis/README.md diff --git a/gamestonk_terminal/exploratory_data_analysis/README.md b/gamestonk_terminal/exploratory_data_analysis/README.md new file mode 100644 index 00000000000..eb61a8faf3c --- /dev/null +++ b/gamestonk_terminal/exploratory_data_analysis/README.md @@ -0,0 +1,117 @@ +# EXPLORATORY DATA ANALYSIS + +This menu aims to perform exploratory data analysis on a pre-loaded stock, and the usage of the following commands along with an example will be exploited below. + +* [summary](#summary) + * brief summary statistics +* [hist](#hist) + * histogram with density plot +* [cdf](#cdf) + * cumulative distribution function +* [bwy](#bwy) + * box and whisker yearly plot +* [bwm](#bwm) + * box and whisker monthly plot +* [rolling](#rolling) + * rolling mean and std deviation +* [decompose](#decompose) + * decomposition in cyclic-trend, season, and residuald +* [cusum](#cusum) + * detects abrupt changes using cumulative sum algorithm + + +## summary + +```text +usage: summary +``` + +Summary statistics + + + +## hist + +```text +usage: hist +``` + +Plot histogram and density + + + +## cdf + +```text +usage: cdf +``` + +Plot cumulative distribution function + + + +## bwy + +```text +usage: bwy +``` + +Box and Whisker plot yearly + +![bwy](https://user-images.githubusercontent.com/25267873/112729437-ff03d280-8f23-11eb-87fb-a331747357f5.png) + + +## bwm + +```text +usage: bwm +``` + +Box and Whisker plot monthly + +![bwm](https://user-images.githubusercontent.com/25267873/112729439-ff9c6900-8f23-11eb-9a63-8d60f23f1435.png) + + +## rolling + +```text +usage: rolling [-w ROLLING_WINDOW] +``` + +Rolling mean and std deviation + +* -w : rolling window. Default 100. + +![rolling](https://user-images.githubusercontent.com/25267873/112729342-843ab780-8f23-11eb-93f2-11c7c516d224.png) + +Captura de ecrã 2021-03-27, às 17 32 05 + + +## decompose + +```text +usage: decompose [-m] +``` + +Decompose time series as: + - Additive Time Series = Level + CyclicTrend + Residual + Seasonality + - Multiplicative Time Series = Level * CyclicTrend * Residual * Seasonality + +* -m : multiplicative model. Default additive. + +![decompose](https://user-images.githubusercontent.com/25267873/112729282-4c337480-8f23-11eb-913c-f30e5c0ef459.png) + + +## cusum + +```text +usage: cusum [-t THRESHOLD] [-d DRIFT] +``` + +Cumulative sum algorithm (CUSUM) to detect abrupt changes in data + +* -t : threshold. Default (MAX-min)/40. +* -d : drift. Default (MAX-min)/80. + +![cusum](https://user-images.githubusercontent.com/25267873/112729206-ef37be80-8f22-11eb-9a53-8e8e55c4caf0.png) + From c68327ee32739baf4b933653e68760ee73d78f91 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Sat, 27 Mar 2021 18:02:48 +0000 Subject: [PATCH 03/14] Update README.md --- .../exploratory_data_analysis/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gamestonk_terminal/exploratory_data_analysis/README.md b/gamestonk_terminal/exploratory_data_analysis/README.md index eb61a8faf3c..ebc52f14df6 100644 --- a/gamestonk_terminal/exploratory_data_analysis/README.md +++ b/gamestonk_terminal/exploratory_data_analysis/README.md @@ -28,6 +28,7 @@ usage: summary Summary statistics +summary ## hist @@ -38,6 +39,7 @@ usage: hist Plot histogram and density +![hist](https://user-images.githubusercontent.com/25267873/112729911-75a1cf80-8f26-11eb-925c-252a90657128.png) ## cdf @@ -48,6 +50,7 @@ usage: cdf Plot cumulative distribution function +![cdf](https://user-images.githubusercontent.com/25267873/112729910-75a1cf80-8f26-11eb-801a-2b44b193022b.png) ## bwy @@ -58,7 +61,7 @@ usage: bwy Box and Whisker plot yearly -![bwy](https://user-images.githubusercontent.com/25267873/112729437-ff03d280-8f23-11eb-87fb-a331747357f5.png) +![bwy](https://user-images.githubusercontent.com/25267873/112729912-763a6600-8f26-11eb-81b6-3df0b632b3af.png) ## bwm @@ -69,7 +72,7 @@ usage: bwm Box and Whisker plot monthly -![bwm](https://user-images.githubusercontent.com/25267873/112729439-ff9c6900-8f23-11eb-9a63-8d60f23f1435.png) +![bwm](https://user-images.githubusercontent.com/25267873/112729913-76d2fc80-8f26-11eb-8338-448147ed5703.png) ## rolling @@ -82,9 +85,7 @@ Rolling mean and std deviation * -w : rolling window. Default 100. -![rolling](https://user-images.githubusercontent.com/25267873/112729342-843ab780-8f23-11eb-93f2-11c7c516d224.png) - -Captura de ecrã 2021-03-27, às 17 32 05 +![rolling](https://user-images.githubusercontent.com/25267873/112729908-75093900-8f26-11eb-9056-16bac2f54386.png) ## decompose @@ -101,6 +102,8 @@ Decompose time series as: ![decompose](https://user-images.githubusercontent.com/25267873/112729282-4c337480-8f23-11eb-913c-f30e5c0ef459.png) +Captura de ecrã 2021-03-27, às 17 32 05 + ## cusum From b64fcf835959990c27f43a9dd91a45df8cc2906a Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 18:03:28 +0000 Subject: [PATCH 04/14] add start time to stats plots --- .../exploratory_data_analysis/eda_api.py | 23 ++++++++++++------- .../eda_controller.py | 8 +++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_api.py b/gamestonk_terminal/exploratory_data_analysis/eda_api.py index 11cf7b4263d..a4e4535a537 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_api.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_api.py @@ -5,6 +5,7 @@ import argparse from typing import List from detecta import detect_cusum from matplotlib import pyplot as plt +from datetime import datetime import pandas as pd from pandas.plotting import register_matplotlib_converters import numpy as np @@ -60,7 +61,7 @@ def summary(other_args: List[str], stock: pd.DataFrame): return -def hist(other_args: List[str], ticker: str, stock: pd.DataFrame): +def hist(other_args: List[str], ticker: str, stock: pd.DataFrame, start: datetime): """Plot histogram and density Parameters @@ -100,7 +101,9 @@ def hist(other_args: List[str], ticker: str, stock: pd.DataFrame): rug=True, rug_kws={"edgecolor": "orange"}, ) - plt.title(ticker + " (Histogram with Density)") + plt.title( + f"Histogram with Density of {ticker} from {start.strftime('%Y-%m-%d')}" + ) plt.ylabel("Density") plt.xlabel("Share Price") plt.grid(True) @@ -116,7 +119,7 @@ def hist(other_args: List[str], ticker: str, stock: pd.DataFrame): return -def cdf(other_args: List[str], ticker: str, stock: pd.DataFrame): +def cdf(other_args: List[str], ticker: str, stock: pd.DataFrame, start: datetime): """Plot cumulative distribution function Parameters @@ -147,7 +150,9 @@ def cdf(other_args: List[str], ticker: str, stock: pd.DataFrame): cdf = stock.value_counts().sort_index().div(len(stock)).cumsum() cdf.plot(lw=2) - plt.title(ticker + " (Cumulative Distribution Function)") + plt.title( + f"Cumulative Distribution Function of {ticker} from {start.strftime('%Y-%m-%d')}" + ) plt.ylabel("Probability") plt.xlabel("Share Price") minVal = stock.values.min() @@ -198,7 +203,7 @@ def cdf(other_args: List[str], ticker: str, stock: pd.DataFrame): return -def bwy(other_args: List[str], ticker: str, stock: pd.DataFrame): +def bwy(other_args: List[str], ticker: str, stock: pd.DataFrame, start: datetime): """Box and Whisker plot yearly Parameters @@ -230,7 +235,9 @@ def bwy(other_args: List[str], ticker: str, stock: pd.DataFrame): sns.set(style="whitegrid") box_plot = sns.boxplot(x=stock.index.year, y=stock) box_plot.set( - xlabel="Year", ylabel="Share Price", title=ticker + " (Box-plot per Year)" + xlabel="Year", + ylabel="Share Price", + title=f"Box-plot per Year of {ticker} from {start.strftime('%Y-%m-%d')}", ) if gtff.USE_ION: @@ -244,7 +251,7 @@ def bwy(other_args: List[str], ticker: str, stock: pd.DataFrame): return -def bwm(other_args: List[str], ticker: str, stock: pd.DataFrame): +def bwm(other_args: List[str], ticker: str, stock: pd.DataFrame, start: datetime): """Box and Whisker plot monthly Parameters @@ -278,7 +285,7 @@ def bwm(other_args: List[str], ticker: str, stock: pd.DataFrame): box_plot.set( xlabel="Month", ylabel="Share Price", - title=ticker + " (Box-plot per Month)", + title=f"Box-plot per Month of {ticker} from {start.strftime('%Y-%m-%d')}", ) l_months = [ "Jan", diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py index 1ed8ea818a8..006ebdaa2d2 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py @@ -113,19 +113,19 @@ class EdaController: def call_hist(self, other_args: List[str]): """Process hist command""" - eda_api.hist(other_args, self.ticker, self.stock) + eda_api.hist(other_args, self.ticker, self.stock, self.start) def call_cdf(self, other_args: List[str]): """Process cdf command""" - eda_api.cdf(other_args, self.ticker, self.stock) + eda_api.cdf(other_args, self.ticker, self.stock, self.start) def call_bwy(self, other_args: List[str]): """Process bwy command""" - eda_api.bwy(other_args, self.ticker, self.stock) + eda_api.bwy(other_args, self.ticker, self.stock, self.start) def call_bwm(self, other_args: List[str]): """Process bwm command""" - eda_api.bwm(other_args, self.ticker, self.stock) + eda_api.bwm(other_args, self.ticker, self.stock, self.start) def call_rolling(self, other_args: List[str]): """Process rolling command""" From 88b624585ca447f2ecc2c40de41958ccba176d4d Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 18:06:07 +0000 Subject: [PATCH 05/14] fix strength word --- gamestonk_terminal/exploratory_data_analysis/eda_api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_api.py b/gamestonk_terminal/exploratory_data_analysis/eda_api.py index a4e4535a537..ebd4e7c436d 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_api.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_api.py @@ -533,28 +533,28 @@ def decompose(other_args: List[str], ticker: str, stock: pd.DataFrame): FtMul = max(0, 1 - np.var(resultMul.resid)) / np.var( resultMul.trend + resultMul.resid ) - print("Strenght of Trend: %.4f" % FtMul) + print("Strength of Trend: %.4f" % FtMul) FsMul = max( 0, 1 - np.var(resultMul.resid) / np.var(resultMul.seasonal + resultMul.resid), ) - print("Strenght of Seasonality: %.4f" % FsMul) + print("Strength of Seasonality: %.4f" % FsMul) else: FtAdd = max( 0, 1 - np.var(resultAdd.resid) / np.var(resultAdd.trend + resultAdd.resid), ) - print("Strenght of Trend: %.4f" % FtAdd) + print("Strength of Trend: %.4f" % FtAdd) FsAdd = max( 0, 1 - np.var(resultAdd.resid) / np.var(resultAdd.seasonal + resultAdd.resid), ) - print("Strenght of Seasonality: %.4f" % FsAdd) + print("Strength of Seasonality: %.4f" % FsAdd) print("") except Exception as e: From d0d4e4880e8e2b7ea718625706b196eb19567d50 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Sat, 27 Mar 2021 18:07:06 +0000 Subject: [PATCH 06/14] add hist to ignore words --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9a1a62fd675..17f52d31bea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,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","ba" --quiet-level=2 --skip=".git" --skip="*.yaml" --skip="*.json" + - run: codespell --ignore-words-list="mape","ba","hist" --quiet-level=2 --skip=".git" --skip="*.yaml" --skip="*.json" - 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 From f2a9470ab19fd5547786718ddb544bd0be0f3dd6 Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 18:12:09 +0000 Subject: [PATCH 07/14] fix entering EDA menu when intraday stock --- terminal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/terminal.py b/terminal.py index 8baac4c4cff..f4ae5fde0b2 100644 --- a/terminal.py +++ b/terminal.py @@ -6,6 +6,7 @@ import sys import os from datetime import datetime, timedelta import pandas as pd +import yfinance as yf from alpha_vantage.timeseries import TimeSeries from prompt_toolkit.completion import NestedCompleter @@ -208,9 +209,7 @@ def main(): if s_interval == "1440min": b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval) else: - df_stock = yf.download( - ns_parser.s_ticker, start=ns_parser.s_start_date, progress=False - ) + df_stock = yf.download(s_ticker, start=s_start, progress=False) df_stock = df_stock.rename( columns={ "Open": "1. open", @@ -222,6 +221,7 @@ def main(): } ) df_stock.index.name = "date" + s_interval = "1440min" b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval) From 0b85212935e69e39693eae4a641923bae2a55d46 Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 18:13:38 +0000 Subject: [PATCH 08/14] remove unused import --- gamestonk_terminal/exploratory_data_analysis/eda_controller.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py index 006ebdaa2d2..731937eb9fb 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py @@ -8,8 +8,7 @@ import pandas as pd from matplotlib import pyplot as plt from gamestonk_terminal.exploratory_data_analysis import eda_api 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.helper_funcs import get_flair from gamestonk_terminal.menu import session from prompt_toolkit.completion import NestedCompleter From 4bac4ac21ca554415d6180e8042bc1e174e64ff5 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Sat, 27 Mar 2021 18:18:04 +0000 Subject: [PATCH 09/14] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 2915a76f215..7cf2d4656f8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -139,7 +139,7 @@ ### Short term -* [ ] Statistical techniques applied to a stock share price (e.g. decompose seasonality, trend, level, auto-correlation, cusum, ...) (@didier) +* [x] Summary stats, CDF, Histogram, Box Whiskers, Decompose (in Trend, Cyclic Trend, Season), CUSUM (@didier) - [PR #289](https://github.com/DidierRLopes/GamestonkTerminal/pull/289) * [ ] Hypothesis tests (e.g. Kurtosis, Jarques-Bera, ARCH, ADF, ...) (@didier) ### Long term From 1c79319d9dfef701395854ae4c75b7d6bac8234c Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 19:59:48 +0000 Subject: [PATCH 10/14] Add (partial) auto-correlation function option --- .../exploratory_data_analysis/eda_api.py | 83 +++++++++++++++++++ .../eda_controller.py | 6 ++ 2 files changed, 89 insertions(+) diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_api.py b/gamestonk_terminal/exploratory_data_analysis/eda_api.py index ebd4e7c436d..190b46ccc6d 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_api.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_api.py @@ -624,3 +624,86 @@ def cusum(other_args: List[str], ticker: str, stock: pd.DataFrame): except Exception as e: print(e, "\n") return + + +def acf(other_args: List[str], ticker: str, stock: pd.DataFrame, start: datetime): + """Auto-Correlation and Partial Auto-Correlation Functions for diff and diff diff stock data + + Parameters + ---------- + other_args : str + Command line arguments to be processed with argparse + ticker : str + Ticker of the stock + stock : pd.DataFrame + Stock data + """ + parser = argparse.ArgumentParser( + add_help=False, + prog="acf", + description=""" + Auto-Correlation and Partial Auto-Correlation Functions for diff and diff diff stock data + """, + ) + parser.add_argument( + "-l", + "--lags", + dest="lags", + type=check_positive, + default=20, + help="maximum lags to display in plots", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + stock = stock["5. adjusted close"] + + fig = plt.figure( + figsize=plot_autoscale(), dpi=PLOT_DPI, constrained_layout=True + ) + spec = gridspec.GridSpec(ncols=2, nrows=2, figure=fig) + + # Diff Auto-correlation function for original time series + ax_acf = fig.add_subplot(spec[0, 0]) + sm.graphics.tsa.plot_acf( + np.diff(np.diff(stock.values)), lags=ns_parser.lags, ax=ax_acf + ) + plt.title(f"Diff({ticker}) Auto-Correlation from {start.strftime('%Y-%m-%d')}") + # Diff Partial auto-correlation function for original time series + ax_pacf = fig.add_subplot(spec[0, 1]) + sm.graphics.tsa.plot_pacf( + np.diff(np.diff(stock.values)), lags=ns_parser.lags, ax=ax_pacf + ) + plt.title( + f"Diff({ticker}) Partial Auto-Correlation from {start.strftime('%Y-%m-%d')}" + ) + + # Diff Diff Auto-correlation function for original time series + ax_acf = fig.add_subplot(spec[1, 0]) + sm.graphics.tsa.plot_acf( + np.diff(np.diff(stock.values)), lags=ns_parser.lags, ax=ax_acf + ) + plt.title( + f"Diff(Diff({ticker})) Auto-Correlation from {start.strftime('%Y-%m-%d')}" + ) + # Diff Diff Partial auto-correlation function for original time series + ax_pacf = fig.add_subplot(spec[1, 1]) + sm.graphics.tsa.plot_pacf( + np.diff(np.diff(stock.values)), lags=ns_parser.lags, ax=ax_pacf + ) + plt.title( + f"Diff(Diff({ticker})) Partial Auto-Correlation from {start.strftime('%Y-%m-%d')}" + ) + + if gtff.USE_ION: + plt.ion() + + plt.show() + print("") + + except Exception as e: + print(e, "\n") + return diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py index 731937eb9fb..7d3189d1fe6 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_controller.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_controller.py @@ -29,6 +29,7 @@ class EdaController: "rolling", "decompose", "cusum", + "acf", ] def __init__( @@ -75,6 +76,7 @@ class EdaController: print(" rolling rolling mean and std deviation") print(" decompose decomposition in cyclic-trend, season, and residuals") print(" cusum detects abrupt changes using cumulative sum algorithm") + print(" acf (partial) auto-correlation function differentials") print("") return @@ -138,6 +140,10 @@ class EdaController: """Process cusum command""" eda_api.cusum(other_args, self.ticker, self.stock) + def call_acf(self, other_args: List[str]): + """Process acf command""" + eda_api.acf(other_args, self.ticker, self.stock, self.start) + def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str): """Statistics Menu""" From 357efe9761724c9b123851cfcb6efa8770d7932f Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Sat, 27 Mar 2021 20:03:10 +0000 Subject: [PATCH 11/14] Update README.md --- .../exploratory_data_analysis/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gamestonk_terminal/exploratory_data_analysis/README.md b/gamestonk_terminal/exploratory_data_analysis/README.md index ebc52f14df6..7cc44c49b98 100644 --- a/gamestonk_terminal/exploratory_data_analysis/README.md +++ b/gamestonk_terminal/exploratory_data_analysis/README.md @@ -18,6 +18,8 @@ This menu aims to perform exploratory data analysis on a pre-loaded stock, and t * decomposition in cyclic-trend, season, and residuald * [cusum](#cusum) * detects abrupt changes using cumulative sum algorithm +* [acf](#acf) + * (partial) auto-correlation function differentials ## summary @@ -118,3 +120,17 @@ Cumulative sum algorithm (CUSUM) to detect abrupt changes in data ![cusum](https://user-images.githubusercontent.com/25267873/112729206-ef37be80-8f22-11eb-9a53-8e8e55c4caf0.png) + +## acf + +```text +usage: acf [-l LAGS] +``` + +Auto-Correlation and Partial Auto-Correlation Functions for diff and diff diff stock data + +* -l : maximum lags to display in plots. Default 20. + +![acf](https://user-images.githubusercontent.com/25267873/112733336-637c5d00-8f37-11eb-9aae-38e75dff9ad2.png) + + From 32891b0e318c10ec6927e2637cbbc9d46978792f Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 20:08:41 +0000 Subject: [PATCH 12/14] change acf lags default from 20 to 40 --- gamestonk_terminal/exploratory_data_analysis/README.md | 2 +- gamestonk_terminal/exploratory_data_analysis/eda_api.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gamestonk_terminal/exploratory_data_analysis/README.md b/gamestonk_terminal/exploratory_data_analysis/README.md index 7cc44c49b98..244d1079d4b 100644 --- a/gamestonk_terminal/exploratory_data_analysis/README.md +++ b/gamestonk_terminal/exploratory_data_analysis/README.md @@ -129,7 +129,7 @@ usage: acf [-l LAGS] Auto-Correlation and Partial Auto-Correlation Functions for diff and diff diff stock data -* -l : maximum lags to display in plots. Default 20. +* -l : maximum lags to display in plots. Default 40. ![acf](https://user-images.githubusercontent.com/25267873/112733336-637c5d00-8f37-11eb-9aae-38e75dff9ad2.png) diff --git a/gamestonk_terminal/exploratory_data_analysis/eda_api.py b/gamestonk_terminal/exploratory_data_analysis/eda_api.py index 190b46ccc6d..b00784c64af 100644 --- a/gamestonk_terminal/exploratory_data_analysis/eda_api.py +++ b/gamestonk_terminal/exploratory_data_analysis/eda_api.py @@ -650,7 +650,7 @@ def acf(other_args: List[str], ticker: str, stock: pd.DataFrame, start: datetime "--lags", dest="lags", type=check_positive, - default=20, + default=40, help="maximum lags to display in plots", ) From f4245f73463f3aa757d9a98dda06392f421f4332 Mon Sep 17 00:00:00 2001 From: didier Date: Sat, 27 Mar 2021 20:09:13 +0000 Subject: [PATCH 13/14] Add detecta lib to requirements --- requirements-full.txt | 1 + requirements-old.txt | 1 + requirements-win.txt | 1 + requirements.txt | 1 + 4 files changed, 4 insertions(+) diff --git a/requirements-full.txt b/requirements-full.txt index 24784254cfe..2ca49ab52d3 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -32,6 +32,7 @@ dataclasses==0.8; python_version >= "3.6" and python_version < "3.7" and python_ decorator==4.4.2; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.2.0" and python_version >= "3.6") 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" deprecated==1.2.11; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +detecta==0.0.5 entrypoints==0.3; python_version >= "3.6" ephem==3.7.7.1; python_version >= "2.7" and python_version < "4" fbprophet==0.6 diff --git a/requirements-old.txt b/requirements-old.txt index 6aaede2a75a..21a289ed40a 100644 --- a/requirements-old.txt +++ b/requirements-old.txt @@ -23,6 +23,7 @@ cython==0.29.17; python_version >= "3.6" and python_full_version < "3.0.0" or py dataclasses==0.8; python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.6.2" decorator==4.4.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.2.0" and python_version >= "3.6" deprecated==1.2.11; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +detecta==0.0.5 ephem==3.7.7.1; python_version >= "2.7" and python_version < "4" fbprophet==0.6 filelock==3.0.12; python_full_version >= "3.6.0" and python_version >= "3.6" diff --git a/requirements-win.txt b/requirements-win.txt index 7cebb528db2..0d6c1686522 100644 --- a/requirements-win.txt +++ b/requirements-win.txt @@ -23,6 +23,7 @@ cython==0.29.17; python_version >= "3.6" and python_full_version < "3.0.0" or py dataclasses==0.8; python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.6.2" decorator==4.4.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.2.0" and python_version >= "3.6" deprecated==1.2.11; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +detecta==0.0.5 ephem==3.7.7.1; python_version >= "2.7" and python_version < "4" fbprophet==0.7.1 filelock==3.0.12; python_full_version >= "3.6.0" and python_version >= "3.6" diff --git a/requirements.txt b/requirements.txt index 919b6242f57..67f988879b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,6 +24,7 @@ cycler==0.10.0; python_version >= "3.6" dataclasses==0.8; python_version >= "3.6" and python_version < "3.7" decorator==4.4.2; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.2.0" and python_version >= "3.6") 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" +detecta==0.0.5 entrypoints==0.3; python_version >= "3.6" finviz==1.3.4 fredapi==0.4.3 From 0408ef0a884133f220a06de7dca4797480aeb53f Mon Sep 17 00:00:00 2001 From: didier Date: Sun, 28 Mar 2021 14:19:19 +0100 Subject: [PATCH 14/14] update poetry dependencies --- poetry.lock | 18 +++++++++++++++++- pyproject.toml | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index cc79aeb62c3..98642b77bdf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -436,6 +436,14 @@ wrapt = ">=1.10,<2" [package.extras] dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] +[[package]] +name = "detecta" +version = "0.0.5" +description = "Detect events in data" +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "entrypoints" version = "0.3" @@ -2778,7 +2786,7 @@ prediction = ["fbprophet", "tensorflow", "pmdarima", "transformers", "flair", "t [metadata] lock-version = "1.1" python-versions = "^3.6.8" -content-hash = "b05035fef8aa3a5dacf6c4713579493f1104296ea25305049466fc47e0c35401" +content-hash = "d0abec748e4bb0fcc0bb22409e4bfdcb6802f2ca9b1849a77941d5a4a954ccc2" [metadata.files] absl-py = [ @@ -3059,6 +3067,10 @@ deprecated = [ {file = "Deprecated-1.2.12-py2.py3-none-any.whl", hash = "sha256:08452d69b6b5bc66e8330adde0a4f8642e969b9e1702904d137eeb29c8ffc771"}, {file = "Deprecated-1.2.12.tar.gz", hash = "sha256:6d2de2de7931a968874481ef30208fd4e08da39177d61d3d4ebdf4366e7dbca1"}, ] +detecta = [ + {file = "detecta-0.0.5-py3-none-any.whl", hash = "sha256:dbaf1938e5d785386c904034e2553824e2aa31793e967984ca65983aca06d23e"}, + {file = "detecta-0.0.5.tar.gz", hash = "sha256:d2ea7d13dfbbc994d6ce385a7f8dc0a85fe675a8a8e712a64ec56e54c40603ed"}, +] entrypoints = [ {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, @@ -4288,6 +4300,7 @@ scikit-learn = [ {file = "scikit_learn-0.24.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c658432d8a20e95398f6bb95ff9731ce9dfa343fdf21eea7ec6a7edfacd4b4d9"}, {file = "scikit_learn-0.24.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9dfa564ef27e8e674aa1cc74378416d580ac4ede1136c13dd555a87996e13422"}, {file = "scikit_learn-0.24.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:9c6097b6a9b2bafc5e0f31f659e6ab5e131383209c30c9e978c5b8abdac5ed2a"}, + {file = "scikit_learn-0.24.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5580eba7345a4d3b097be2f067cc71a306c44bab19e8717a30361f279c929bea"}, {file = "scikit_learn-0.24.1-cp36-cp36m-win32.whl", hash = "sha256:7b04691eb2f41d2c68dbda8d1bd3cb4ef421bdc43aaa56aeb6c762224552dfb6"}, {file = "scikit_learn-0.24.1-cp36-cp36m-win_amd64.whl", hash = "sha256:1adf483e91007a87171d7ce58c34b058eb5dab01b5fee6052f15841778a8ecd8"}, {file = "scikit_learn-0.24.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:ddb52d088889f5596bc4d1de981f2eca106b58243b6679e4782f3ba5096fd645"}, @@ -4295,6 +4308,7 @@ scikit-learn = [ {file = "scikit_learn-0.24.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0567a2d29ad08af98653300c623bd8477b448fe66ced7198bef4ed195925f082"}, {file = "scikit_learn-0.24.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:99349d77f54e11f962d608d94dfda08f0c9e5720d97132233ebdf35be2858b2d"}, {file = "scikit_learn-0.24.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:83b21ff053b1ff1c018a2d24db6dd3ea339b1acfbaa4d9c881731f43748d8b3b"}, + {file = "scikit_learn-0.24.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:abe835a851610f87201819cb315f8d554e1a3e8128912783a31e87264ba5ffb7"}, {file = "scikit_learn-0.24.1-cp37-cp37m-win32.whl", hash = "sha256:c3deb3b19dd9806acf00cf0d400e84562c227723013c33abefbbc3cf906596e9"}, {file = "scikit_learn-0.24.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d54dbaadeb1425b7d6a66bf44bee2bb2b899fe3e8850b8e94cfb9c904dcb46d0"}, {file = "scikit_learn-0.24.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:3c4f07f47c04e81b134424d53c3f5e16dfd7f494e44fd7584ba9ce9de2c5e6c1"}, @@ -4302,6 +4316,7 @@ scikit-learn = [ {file = "scikit_learn-0.24.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:4ddd2b6f7449a5d539ff754fa92d75da22de261fd8fdcfb3596799fadf255101"}, {file = "scikit_learn-0.24.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:826b92bf45b8ad80444814e5f4ac032156dd481e48d7da33d611f8fe96d5f08b"}, {file = "scikit_learn-0.24.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:259ec35201e82e2db1ae2496f229e63f46d7f1695ae68eef9350b00dc74ba52f"}, + {file = "scikit_learn-0.24.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:9599a3f3bf33f73fed0fe06d1dfa4e6081365a58c1c807acb07271be0dce9733"}, {file = "scikit_learn-0.24.1-cp38-cp38-win32.whl", hash = "sha256:8772b99d683be8f67fcc04789032f1b949022a0e6880ee7b75a7ec97dbbb5d0b"}, {file = "scikit_learn-0.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:ed9d65594948678827f4ff0e7ae23344e2f2b4cabbca057ccaed3118fdc392ca"}, {file = "scikit_learn-0.24.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:8aa1b3ac46b80eaa552b637eeadbbce3be5931e4b5002b964698e33a1b589e1e"}, @@ -4309,6 +4324,7 @@ scikit-learn = [ {file = "scikit_learn-0.24.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:087dfede39efb06ab30618f9ab55a0397f29c38d63cd0ab88d12b500b7d65fd7"}, {file = "scikit_learn-0.24.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:895dbf2030aa7337649e36a83a007df3c9811396b4e2fa672a851160f36ce90c"}, {file = "scikit_learn-0.24.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:9a24d1ccec2a34d4cd3f2a1f86409f3f5954cc23d4d2270ba0d03cf018aa4780"}, + {file = "scikit_learn-0.24.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:54be0a60a5a35005ad69c75902e0f5c9f699db4547ead427e97ef881c3242e6f"}, {file = "scikit_learn-0.24.1-cp39-cp39-win32.whl", hash = "sha256:fab31f48282ebf54dd69f6663cd2d9800096bad1bb67bbc9c9ac84eb77b41972"}, {file = "scikit_learn-0.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:4562dcf4793e61c5d0f89836d07bc37521c3a1889da8f651e2c326463c4bd697"}, ] diff --git a/pyproject.toml b/pyproject.toml index f4c3f068266..fb6675cf9a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ termcolor = "^1.1.0" alpaca-trade-api = "^1.0.1" pyally = "^1.1.2" pycoingecko = "^1.4.0" +detecta = "^0.0.5" [tool.poetry.dev-dependencies] pytest = "^6.2.2"