From 06bde2e744ddff129db487833d0b29705a7686e9 Mon Sep 17 00:00:00 2001 From: FedericoGarza Date: Fri, 21 Oct 2022 17:15:00 -0500 Subject: [PATCH 1/6] feat: add autoets model --- openbb_terminal/forecast/autoets_model.py | 132 ++++++++++++++++++ openbb_terminal/forecast/autoets_view.py | 113 +++++++++++++++ .../forecast/forecast_controller.py | 58 ++++++++ openbb_terminal/forecast/helpers.py | 7 +- openbb_terminal/miscellaneous/i18n/en.yml | 1 + openbb_terminal/sdk.py | 4 + .../forecast/test_autoets_model.py | 11 ++ .../forecast/test_autoets_view.py | 18 +++ .../terminal/forecast/autoets/_index.md | 62 ++++++++ website/data/menu/main.yml | 2 + 10 files changed, 406 insertions(+), 2 deletions(-) create mode 100644 openbb_terminal/forecast/autoets_model.py create mode 100644 openbb_terminal/forecast/autoets_view.py create mode 100644 tests/openbb_terminal/forecast/test_autoets_model.py create mode 100644 tests/openbb_terminal/forecast/test_autoets_view.py create mode 100644 website/content/terminal/forecast/autoets/_index.md diff --git a/openbb_terminal/forecast/autoets_model.py b/openbb_terminal/forecast/autoets_model.py new file mode 100644 index 000000000000..bf42d5ba3e97 --- /dev/null +++ b/openbb_terminal/forecast/autoets_model.py @@ -0,0 +1,132 @@ +# pylint: disable=too-many-arguments +"""Automatic ETS (Error, Trend, and Seasonality) Model""" +__docformat__ = "numpy" + +import logging +from typing import Any, Union, Optional, List, Tuple + +import warnings +import numpy as np +import pandas as pd +from statsforecast.models import ETS +from statsforecast.core import StatsForecast + +from openbb_terminal.decorators import log_start_end +from openbb_terminal.rich_config import console +from openbb_terminal.forecast import helpers + + +warnings.simplefilter("ignore") + +logger = logging.getLogger(__name__) + + +@log_start_end(log=logger) +def get_autoets_data( + data: Union[pd.Series, pd.DataFrame], + target_column: str = "close", + seasonal_periods: int = 7, + n_predict: int = 30, + start_window: float = 0.85, + forecast_horizon: int = 5, +) -> Tuple[list[np.ndarray], List[np.ndarray], List[np.ndarray], Optional[float], Any]: + + """Performs Automatic ETS forecasting + This is a wrapper around StatsForecast ETS; + we refer to this link for the original and more complete documentation of the parameters. + + + https://nixtla.github.io/statsforecast/models.html#ets + + Parameters + ---------- + data : Union[pd.Series, np.ndarray] + Input data. + target_column (str, optional): + Target column to forecast. Defaults to "close". + seasonal_periods: int + Number of seasonal periods in a year (7 for daily data) + If not set, inferred from frequency of the series. + n_predict: int + Number of days to forecast + start_window: float + Size of sliding window from start of timeseries and onwards + forecast_horizon: int + Number of days to forecast when backtesting and retraining historical + + Returns + ------- + list[float] + Adjusted Data series + list[float] + List of historical fcast values + list[float] + List of predicted fcast values + Optional[float] + precision + Any + Fit ETS model object. + """ + + use_scalers = False + # statsforecast preprocessing + # when including more time series + # the preprocessing is similar + ticker_series = data[["date", target_column]] + ticker_series.columns = ["ds", "y"] + ticker_series.insert(0, "unique_id", target_column) + ticker_series["ds"] = pd.to_datetime(ticker_series["ds"]) + + # Model Init + model_ets = ETS( + season_length=int(seasonal_periods), + ) + fcst = StatsForecast(df=ticker_series, models=[model_ets], freq="B") + + # Historical backtesting + historical_fcast_ets = fcst.cross_validation( + h=int(forecast_horizon), + test_size=int((1 - start_window) * len(data)), + n_windows=None, + input_size=min(10 * forecast_horizon, len(data)), + ) + + # train new model on entire timeseries to provide best current forecast + # we have the historical fcast, now lets predict. + forecast = fcst.forecast(int(n_predict)) + y_true = historical_fcast_ets["y"].values + y_hat = historical_fcast_ets["ETS"].values + precision = helpers.mean_absolute_percentage_error(y_true, y_hat) + console.print(f"AutoETS obtains MAPE: {precision:.2f}% \n") + + # transform outputs to make them compatible with + # plots + use_scalers = False + _, ticker_series = helpers.get_series( + ticker_series.rename(columns={"y": target_column}), + target_column, + is_scaler=use_scalers, + time_col="ds", + ) + _, forecast = helpers.get_series( + forecast.rename(columns={"ETS": target_column}), + target_column, + is_scaler=use_scalers, + time_col="ds", + ) + _, historical_fcast_ets = helpers.get_series( + historical_fcast_ets.groupby("ds") + .head(1) + .rename(columns={"ETS": target_column}), + target_column, + is_scaler=use_scalers, + time_col="ds", + ) + + return ( + ticker_series, + historical_fcast_ets, + forecast, + precision, + fcst, + ) diff --git a/openbb_terminal/forecast/autoets_view.py b/openbb_terminal/forecast/autoets_view.py new file mode 100644 index 000000000000..c2eeb513247d --- /dev/null +++ b/openbb_terminal/forecast/autoets_view.py @@ -0,0 +1,113 @@ +"""Automatic ETS (Error, Trend, Sesonality) View""" +__docformat__ = "numpy" + +import logging +from typing import Union, Optional, List +from datetime import datetime + +import pandas as pd +import matplotlib.pyplot as plt + +from openbb_terminal.forecast import autoets_model +from openbb_terminal.decorators import log_start_end +from openbb_terminal.forecast import helpers + +logger = logging.getLogger(__name__) +# pylint: disable=too-many-arguments + + +@log_start_end(log=logger) +def display_autoets_forecast( + data: Union[pd.DataFrame, pd.Series], + target_column: str = "close", + dataset_name: str = "", + seasonal_periods: int = 7, + n_predict: int = 30, + start_window: float = 0.85, + forecast_horizon: int = 5, + export: str = "", + residuals: bool = False, + forecast_only: bool = False, + start_date: Optional[datetime] = None, + end_date: Optional[datetime] = None, + naive: bool = False, + export_pred_raw: bool = False, + external_axes: Optional[List[plt.axes]] = None, +): + """Display Automatic ETS (Error, Trend, Sesonality) Model + + Parameters + ---------- + data : Union[pd.Series, np.array] + Data to forecast + dataset_name str + The name of the ticker to be predicted + target_column (str, optional): + Target column to forecast. Defaults to "close". + seasonal_periods: int + Number of seasonal periods in a year + If not set, inferred from frequency of the series. + n_predict: int + Number of days to forecast + start_window: float + Size of sliding window from start of timeseries and onwards + forecast_horizon: int + Number of days to forecast when backtesting and retraining historical + export: str + Format to export data + residuals: bool + Whether to show residuals for the model. Defaults to False. + forecast_only: bool + Whether to only show dates in the forecasting range. Defaults to False. + start_date: Optional[datetime] + The starting date to perform analysis, data before this is trimmed. Defaults to None. + end_date: Optional[datetime] + The ending date to perform analysis, data after this is trimmed. Defaults to None. + naive: bool + Whether to show the naive baseline. This just assumes the closing price will be the same + as the previous day's closing price. Defaults to False. + external_axes:Optional[List[plt.axes]] + External axes to plot on + """ + data = helpers.clean_data(data, start_date, end_date, target_column, None) + if not helpers.check_data(data, target_column, None): + return + + ( + ticker_series, + historical_fcast, + predicted_values, + precision, + _model, + ) = autoets_model.get_autoets_data( + data=data, + target_column=target_column, + seasonal_periods=seasonal_periods, + n_predict=n_predict, + start_window=start_window, + forecast_horizon=forecast_horizon, + ) + probabilistic = False + helpers.plot_forecast( + name="AutoETS", + target_col=target_column, + historical_fcast=historical_fcast, + predicted_values=predicted_values, + ticker_series=ticker_series, + ticker_name=dataset_name, + data=data, + n_predict=n_predict, + forecast_horizon=forecast_horizon, + past_covariates=None, + precision=precision, + probabilistic=probabilistic, + export=export, + forecast_only=forecast_only, + naive=naive, + export_pred_raw=export_pred_raw, + external_axes=external_axes, + ) + if residuals: + helpers.plot_residuals( + _model, None, ticker_series, forecast_horizon=forecast_horizon + ) diff --git a/openbb_terminal/forecast/forecast_controller.py b/openbb_terminal/forecast/forecast_controller.py index 66a57c5cb1f8..200ebf55cb1a 100644 --- a/openbb_terminal/forecast/forecast_controller.py +++ b/openbb_terminal/forecast/forecast_controller.py @@ -55,6 +55,7 @@ from openbb_terminal.forecast import ( forecast_model, forecast_view, + autoets_view, expo_model, expo_view, linregr_view, @@ -108,6 +109,7 @@ class ForecastController(BaseController): "delta", "atr", "signal", + "autoets", "expo", "theta", "rnn", @@ -244,6 +246,7 @@ def update_runtime_choices(self): "signal", "combine", "rename", + "autoets", "expo", "theta", "rnn", @@ -320,6 +323,7 @@ def print_help(self): mt.add_cmd("signal", self.files) mt.add_raw("\n") mt.add_info("_tsforecasting_") + mt.add_cmd("autoets", self.files) mt.add_cmd("expo", self.files) mt.add_cmd("theta", self.files) mt.add_cmd("linregr", self.files) @@ -1608,6 +1612,60 @@ def call_export(self, other_args: List[str]): ) console.print() + # AutoETS Model + @log_start_end(log=logger) + def call_autoets(self, other_args: List[str]): + """Process autoets command""" + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + add_help=False, + prog="autoets", + description=""" + Perform Automatic ETS (Error, Trend, Seasonality) forecast + """, + ) + if other_args and "-" not in other_args[0][0]: + other_args.insert(0, "--target-dataset") + + ns_parser = self.parse_known_args_and_warn( + parser, + other_args, + export_allowed=EXPORT_ONLY_FIGURES_ALLOWED, + target_dataset=True, + target_column=True, + n_days=True, + seasonal="A", + periods=True, + window=True, + residuals=True, + forecast_only=True, + start=True, + end=True, + naive=True, + export_pred_raw=True, + ) + # TODO Convert this to multi series + if ns_parser: + if not helpers.check_parser_input(ns_parser, self.datasets): + return + + autoets_view.display_autoets_forecast( + data=self.datasets[ns_parser.target_dataset], + dataset_name=ns_parser.target_dataset, + n_predict=ns_parser.n_days, + target_column=ns_parser.target_column, + seasonal_periods=ns_parser.seasonal_periods, + start_window=ns_parser.start_window, + forecast_horizon=ns_parser.n_days, + export=ns_parser.export, + residuals=ns_parser.residuals, + forecast_only=ns_parser.forecast_only, + start_date=ns_parser.s_start_date, + end_date=ns_parser.s_end_date, + naive=ns_parser.naive, + export_pred_raw=ns_parser.export_pred_raw, + ) + # EXPO Model @log_start_end(log=logger) def call_expo(self, other_args: List[str]): diff --git a/openbb_terminal/forecast/helpers.py b/openbb_terminal/forecast/helpers.py index 30a71a56d9b7..9f9eafadfce3 100644 --- a/openbb_terminal/forecast/helpers.py +++ b/openbb_terminal/forecast/helpers.py @@ -613,12 +613,15 @@ def dt_format(x) -> str: def get_series( - data: pd.DataFrame, target_column: str = None, is_scaler: bool = True + data: pd.DataFrame, + target_column: str = None, + is_scaler: bool = True, + time_col: str = "date", ) -> tuple[Optional[Scaler], TimeSeries]: filler = MissingValuesFiller() filler_kwargs = dict( df=data, - time_col="date", + time_col=time_col, value_cols=[target_column], freq="B", fill_missing_dates=True, diff --git a/openbb_terminal/miscellaneous/i18n/en.yml b/openbb_terminal/miscellaneous/i18n/en.yml index 372887737fdb..70b31b1a10b4 100644 --- a/openbb_terminal/miscellaneous/i18n/en.yml +++ b/openbb_terminal/miscellaneous/i18n/en.yml @@ -1039,6 +1039,7 @@ en: forecast/atr: Add Average True Range forecast/signal: Add Price Signal (short vs. long term) forecast/_tsforecasting_: TimeSeries Forecasting + forecast/autoets: Automatic ETS (Error, Trend, Seasonality) Model forecast/arima: Arima (Non-darts) forecast/expo: Probabilistic Exponential Smoothing forecast/theta: Theta Method diff --git a/openbb_terminal/sdk.py b/openbb_terminal/sdk.py index 145211d4195a..eda671e8ce67 100644 --- a/openbb_terminal/sdk.py +++ b/openbb_terminal/sdk.py @@ -2002,6 +2002,10 @@ "forecast.roc": {"model": "openbb_terminal.forecast.forecast_model.add_roc"}, "forecast.mom": {"model": "openbb_terminal.forecast.forecast_model.add_momentum"}, "forecast.delta": {"model": "openbb_terminal.forecast.forecast_model.add_delta"}, + "forecast.autoets": { + "model": "openbb_terminal.forecast.autoets_model.get_autoets_data", + "view": "openbb_terminal.forecast.autoets_view.display_autoets_forecast", + }, "forecast.expo": { "model": "openbb_terminal.forecast.expo_model.get_expo_data", "view": "openbb_terminal.forecast.expo_view.display_expo_forecast", diff --git a/tests/openbb_terminal/forecast/test_autoets_model.py b/tests/openbb_terminal/forecast/test_autoets_model.py new file mode 100644 index 000000000000..d50a180d5c33 --- /dev/null +++ b/tests/openbb_terminal/forecast/test_autoets_model.py @@ -0,0 +1,11 @@ +import pytest +from tests.openbb_terminal.forecast import conftest + +try: + from openbb_terminal.forecast import autoets_model +except ImportError: + pytest.skip(allow_module_level=True) + + +def test_get_autoets_model(tsla_csv): + conftest.test_model(autoets_model.get_autoets_data, tsla_csv) diff --git a/tests/openbb_terminal/forecast/test_autoets_view.py b/tests/openbb_terminal/forecast/test_autoets_view.py new file mode 100644 index 000000000000..cb88356167af --- /dev/null +++ b/tests/openbb_terminal/forecast/test_autoets_view.py @@ -0,0 +1,18 @@ +import pytest + +try: + from openbb_terminal.forecast import autoets_view +except ImportError: + pytest.skip(allow_module_level=True) + + +def test_display_tft_forecast(tsla_csv): + with pytest.raises(AttributeError): + autoets_view.display_autoets_forecast( + tsla_csv, + target_column="close", + seasonal_periods=3, + n_predict=1, + start_window=0.5, + forecast_horizon=1, + ) diff --git a/website/content/terminal/forecast/autoets/_index.md b/website/content/terminal/forecast/autoets/_index.md new file mode 100644 index 000000000000..57f36b06f6e2 --- /dev/null +++ b/website/content/terminal/forecast/autoets/_index.md @@ -0,0 +1,62 @@ +``` +usage: expo [--trend {N,A,M}] [--dampen DAMPEN] [--naive] [-d {AAPL}] [-c TARGET_COLUMN] [-n N_DAYS] [-s {N,A,M}] [-p SEASONAL_PERIODS] + [-w START_WINDOW] [--end S_END_DATE] [--start S_START_DATE] [--residuals] [--forecast-only] [--export-pred-raw] [-h] + [--export EXPORT] +``` + +Perform Probabilistic Exponential Smoothing forecast Trend: N: None, A: Additive, M: Multiplicative Seasonality: N: None, A: Additive, M: Multiplicative Dampen: T: True, F: False + +``` +optional arguments: + --trend {N,A,M} Trend: N: None, A: Additive, M: Multiplicative. (default: A) + --dampen DAMPEN Dampening (default: F) + --naive Show the naive baseline for a model. (default: False) + -d {AAPL}, --target-dataset {AAPL} + The name of the dataset you want to select (default: None) + -c TARGET_COLUMN, --target-column TARGET_COLUMN + The name of the specific column you want to use (default: close) + -n N_DAYS, --n-days N_DAYS + prediction days. (default: 5) + -s {N,A,M}, --seasonal {N,A,M} + Seasonality: N: None, A: Additive, M: Multiplicative. (default: A) + -p SEASONAL_PERIODS, --periods SEASONAL_PERIODS + Seasonal periods: 4: Quarterly, 7: Daily (default: 7) + -w START_WINDOW, --window START_WINDOW + Start point for rolling training and forecast window. 0.0-1.0 (default: 0.85) + --end S_END_DATE The end date (format YYYY-MM-DD) to select for testing (default: None) + --start S_START_DATE The start date (format YYYY-MM-DD) to select for testing (default: None) + --residuals Show the residuals for the model. (default: False) + --forecast-only Do not plot the hisotorical data without forecasts. (default: False) + --export-pred-raw Export predictions to a csv file. (default: False) + -h, --help show this help message (default: False) + --export EXPORT Export figure into png, jpg, pdf, svg (default: ) + +For more information and examples, use 'about expo' to access the related guide. +``` + +Example: +``` +2022 Jul 23, 10:36 (๐Ÿฆ‹) /forecast/ $ load GME_20220719_123734.csv -a GME + +2022 Jul 23, 10:52 (๐Ÿฆ‹) /forecast/ $ expo GME +100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 115/115 [00:16<00:00, 6.80it/s] +Exponential smoothing obtains MAPE: 12.88% + + + + Actual price: $ 146.64 +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ +โ”ƒ Datetime โ”ƒ Prediction โ”ƒ +โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ +โ”‚ 2022-07-19 00:00:00 โ”‚ $ 146.35 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-07-20 00:00:00 โ”‚ $ 148.63 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-07-21 00:00:00 โ”‚ $ 148.86 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-07-22 00:00:00 โ”‚ $ 151.76 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-07-25 00:00:00 โ”‚ $ 149.74 โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` +![expo](https://user-images.githubusercontent.com/72827203/180615313-e45d6cb3-06a8-45aa-ae4e-505df07e7210.png) diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index 92e73e905cc6..64930f120665 100644 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -753,6 +753,8 @@ main: sub: - name: atr ref: terminal/forecast/atr + - name: autoets + ref: terminal/forecast/autoets - name: brnn ref: terminal/forecast/brnn - name: clean From 80e05e330c97fc8c82158c64205dd02043240c07 Mon Sep 17 00:00:00 2001 From: fede Date: Fri, 21 Oct 2022 17:23:18 -0500 Subject: [PATCH 2/6] feat: update autoets index --- .../terminal/forecast/autoets/_index.md | 56 +++++++++---------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/website/content/terminal/forecast/autoets/_index.md b/website/content/terminal/forecast/autoets/_index.md index 57f36b06f6e2..fd8c2c9eee0a 100644 --- a/website/content/terminal/forecast/autoets/_index.md +++ b/website/content/terminal/forecast/autoets/_index.md @@ -1,15 +1,13 @@ ``` -usage: expo [--trend {N,A,M}] [--dampen DAMPEN] [--naive] [-d {AAPL}] [-c TARGET_COLUMN] [-n N_DAYS] [-s {N,A,M}] [-p SEASONAL_PERIODS] - [-w START_WINDOW] [--end S_END_DATE] [--start S_START_DATE] [--residuals] [--forecast-only] [--export-pred-raw] [-h] - [--export EXPORT] +usage: autoets [--naive] [-d {AAPL}] [-c TARGET_COLUMN] [-n N_DAYS] [-s {N,A,M}] [-p SEASONAL_PERIODS] [-w START_WINDOW] [--end S_END_DATE] [--start S_START_DATE] [--residuals] [--forecast-only] + [--export-pred-raw] [-h] [--export EXPORT] + ``` -Perform Probabilistic Exponential Smoothing forecast Trend: N: None, A: Additive, M: Multiplicative Seasonality: N: None, A: Additive, M: Multiplicative Dampen: T: True, F: False +Perform Automatic ETS (Error, Trend, Seasonality) forecast ``` optional arguments: - --trend {N,A,M} Trend: N: None, A: Additive, M: Multiplicative. (default: A) - --dampen DAMPEN Dampening (default: F) --naive Show the naive baseline for a model. (default: False) -d {AAPL}, --target-dataset {AAPL} The name of the dataset you want to select (default: None) @@ -31,32 +29,30 @@ optional arguments: -h, --help show this help message (default: False) --export EXPORT Export figure into png, jpg, pdf, svg (default: ) -For more information and examples, use 'about expo' to access the related guide. +For more information and examples, use 'about autoets' to access the related guide. ``` Example: ``` -2022 Jul 23, 10:36 (๐Ÿฆ‹) /forecast/ $ load GME_20220719_123734.csv -a GME - -2022 Jul 23, 10:52 (๐Ÿฆ‹) /forecast/ $ expo GME -100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 115/115 [00:16<00:00, 6.80it/s] -Exponential smoothing obtains MAPE: 12.88% - - - - Actual price: $ 146.64 -โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ -โ”ƒ Datetime โ”ƒ Prediction โ”ƒ -โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ -โ”‚ 2022-07-19 00:00:00 โ”‚ $ 146.35 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ 2022-07-20 00:00:00 โ”‚ $ 148.63 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ 2022-07-21 00:00:00 โ”‚ $ 148.86 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ 2022-07-22 00:00:00 โ”‚ $ 151.76 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ 2022-07-25 00:00:00 โ”‚ $ 149.74 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +2022 Oct 21, 18:20 (๐Ÿฆ‹) /forecast/ $ load AAPL + +2022 Oct 21, 18:21 (๐Ÿฆ‹) /forecast/ $ autoets AAPL + + + + Actual price: 143.39 +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ +โ”ƒ Datetime โ”ƒ Prediction โ”ƒ +โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ +โ”‚ 2022-10-21 โ”‚ 143.42 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-10-24 โ”‚ 143.42 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-10-25 โ”‚ 143.42 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-10-26 โ”‚ 143.42 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 2022-10-27 โ”‚ 143.42 โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` -![expo](https://user-images.githubusercontent.com/72827203/180615313-e45d6cb3-06a8-45aa-ae4e-505df07e7210.png) +![autoets](https://user-images.githubusercontent.com/10517170/197297075-d141d735-0b35-43cc-bf4f-e746b6b1001e.png) From 5d1ea537d134ed52771cfd71903be33fbd63596f Mon Sep 17 00:00:00 2001 From: FedericoGarza Date: Tue, 25 Oct 2022 15:00:28 -0500 Subject: [PATCH 3/6] feat: add verbose option --- openbb_terminal/forecast/autoets_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbb_terminal/forecast/autoets_model.py b/openbb_terminal/forecast/autoets_model.py index bf42d5ba3e97..98b450af9088 100644 --- a/openbb_terminal/forecast/autoets_model.py +++ b/openbb_terminal/forecast/autoets_model.py @@ -81,7 +81,7 @@ def get_autoets_data( model_ets = ETS( season_length=int(seasonal_periods), ) - fcst = StatsForecast(df=ticker_series, models=[model_ets], freq="B") + fcst = StatsForecast(df=ticker_series, models=[model_ets], freq="B", verbose=True) # Historical backtesting historical_fcast_ets = fcst.cross_validation( From 7519b8064bb4f8382fd36384fde464d8df001fed Mon Sep 17 00:00:00 2001 From: FedericoGarza Date: Tue, 25 Oct 2022 20:20:06 -0500 Subject: [PATCH 4/6] feat: freq preprocessing --- openbb_terminal/forecast/autoets_model.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openbb_terminal/forecast/autoets_model.py b/openbb_terminal/forecast/autoets_model.py index 98b450af9088..4a42ae02e5ef 100644 --- a/openbb_terminal/forecast/autoets_model.py +++ b/openbb_terminal/forecast/autoets_model.py @@ -72,16 +72,17 @@ def get_autoets_data( # statsforecast preprocessing # when including more time series # the preprocessing is similar - ticker_series = data[["date", target_column]] + _, ticker_series = helpers.get_series(data, target_column, is_scaler=use_scalers) + freq = ticker_series.freq_str + ticker_series = ticker_series.pd_dataframe().reset_index() ticker_series.columns = ["ds", "y"] ticker_series.insert(0, "unique_id", target_column) - ticker_series["ds"] = pd.to_datetime(ticker_series["ds"]) # Model Init model_ets = ETS( season_length=int(seasonal_periods), ) - fcst = StatsForecast(df=ticker_series, models=[model_ets], freq="B", verbose=True) + fcst = StatsForecast(df=ticker_series, models=[model_ets], freq=freq, verbose=True) # Historical backtesting historical_fcast_ets = fcst.cross_validation( From 15af8689da66cff9cb762c0ee15962d01da9cacd Mon Sep 17 00:00:00 2001 From: FedericoGarza Date: Tue, 25 Oct 2022 20:34:14 -0500 Subject: [PATCH 5/6] feat: improve test size call --- openbb_terminal/forecast/autoets_model.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbb_terminal/forecast/autoets_model.py b/openbb_terminal/forecast/autoets_model.py index 4a42ae02e5ef..6ded5b69d8ef 100644 --- a/openbb_terminal/forecast/autoets_model.py +++ b/openbb_terminal/forecast/autoets_model.py @@ -85,11 +85,12 @@ def get_autoets_data( fcst = StatsForecast(df=ticker_series, models=[model_ets], freq=freq, verbose=True) # Historical backtesting + last_training_point = int((len(ticker_series) - 1) * start_window) historical_fcast_ets = fcst.cross_validation( h=int(forecast_horizon), - test_size=int((1 - start_window) * len(data)), + test_size=len(ticker_series) - last_training_point, n_windows=None, - input_size=min(10 * forecast_horizon, len(data)), + input_size=min(10 * forecast_horizon, len(ticker_series)), ) # train new model on entire timeseries to provide best current forecast From 76e25990dbfb9d03ebe7511405b92c4f5482a83b Mon Sep 17 00:00:00 2001 From: FedericoGarza Date: Wed, 26 Oct 2022 13:44:48 -0500 Subject: [PATCH 6/6] feat: add statsforecast dep to conda env full --- build/conda/conda-3-9-env-full.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/conda/conda-3-9-env-full.yaml b/build/conda/conda-3-9-env-full.yaml index 9289af688665..c3a57f53c413 100644 --- a/build/conda/conda-3-9-env-full.yaml +++ b/build/conda/conda-3-9-env-full.yaml @@ -8,3 +8,4 @@ dependencies: - u8darts[torch]=0.22.0 - poetry=1.1.13 - cvxpy=1.2.1 + - statsforecast==1.1.3