Skip to main content

Forecast

The Forecast module provides programmatic access to the same commands found in the OpenBB Terminal Forecast menu. The extensive library of models, built on top of the u8darts library, are easily tuned with hyper-parameters.

How to Use

The Forecast menu was designed specifically for the CLI application, and consequently, the operation of these commands do not mirror the workflow of the OpenBB Terminal. This will be improved in the future to more closely resemble it, and this guide will highlight some notable differences.

Commands within the forecast module are representatives from three broad categories:

  • Exploration
  • Feature Engineering
  • Model

Each command is listed below with a short description. A majority of functions will also have an additional syntax, _chart, for displaying the generated charts inline. For ease of use, we recommend using the _chart version for Model functions.

PathTypeDescription
openbb.forecast.atrFeature EngineeringAdd a Column for the Average True Range
openbb.forecast.autocesModelAutomatic Complex Exponential Smoothing Model
openbb.forecast.autoetsModelAutomatic ETS (Error, Trend, Seasonality) Model
openbb.forecast.autoselectModelAutomatically Selects the Best Statistical Model From AutoARIMA, AutoETS, AutoCES, MSTL, etc.
openbb.forecast.brnnModelBlock Recurrent Neural Network (RNN, LSTM, GRU) (feat. Past covariates)
openbb.forecast.cleanExplorationFill or Drop NaN Values
openbb.forecast.combineExplorationCombine Columns From Different Datasets
openbb.forecast.corrExplorationCorrelation Coefficients Between Columns of a Dataset
openbb.forecast.deleteExplorationDelete Columns From a Dataset
openbb.forecast.deltaFeature EngineeringAdd a Column for % Change
openbb.forecast.descExplorationShow Descriptive Statistics for a Dataset
openbb.forecast.emaFeature EngineeringAdd a Column for Exponentially Weighted Moving Average
openbb.forecast.expoModelProbabilistic Exponential Smoothing
openbb.forecast.exportExportExport a Processed Dataset as a CSV or XLSX File
openbb.forecast.linregrModelProbabilistic Linear Regression (feat. Past covariates and Explainability)
openbb.forecast.loadImportImport a Local CSV or XLSX File
openbb.forecast.momFeature EngineeringAdd a Column for Momentum
openbb.forecast.nbeatsModelNeural Bayesian Estimation (feat. Past covariates)
openbb.forecast.nhitsModelNeural Hierarchical Interpolation (feat. Past covariates)
openbb.forecast.plotExplorationPlots Specific Columns From a Loaded Dataset
openbb.forecast.regrModelRegression (feat. Past covariates and Explainability)
openbb.forecast.renameExplorationRename Columns in a Dataset
openbb.forecast.rnnModelProbabilistic Recurrent Neural Network (RNN, LSTM, GRU)
openbb.forecast.rocFeature EngineeringAdd a Column for Rate of Change
openbb.forecast.rsiFeature EngineeringAdd a Column for Relative Strength Index
openbb.forecast.rwdModelRandom Walk with Drift Model
openbb.forecast.seasonExplorationPlot Seasonality of a Column in a Dataset
openbb.forecast.seasonalnaiveModelSeasonal Naive Model
openbb.forecast.signalFeature EngineeringAdd a Column for Price Signal (Short vs. Long Term)
openbb.forecast.stoFeature EngineeringAdd a Column for Stochastic Oscillator %K and %D
openbb.forecast.tcnModelTemporal Convolutional Neural Network (feat. Past covariates)
openbb.forecast.tftModelTemporal Fusion Transformer Network(feat. Past covariates)
openbb.forecast.thetaModelTheta Method
openbb.forecast.transModelTransformer Network (feat. Past covariates)

Alternatively, the contents of the menu is printed with:

help(openbb.forecast)

Type hints and code completion will be activated upon entering the ., after, openbb.forecast. The first step is always going to involve loading some data. Let's walk through a procedure for procuring a DataFrame with some examples below.

Examples

Import Statements

The examples provided below will assume that the following import block is included at the beginning of the Python script or Notebook file:

from openbb_terminal.sdk import openbb
import pandas as pd
# %matplotlib inline (uncomment if using a Jupyter Interactive Terminal or Notebook)

Loading Data

This library of models are specifically for time-series, and consequently, the data must follow some formatting guidelines:

  • If the index is not a date, it must be sequentially ordered and evenly spaced - i.e., it can't be indexed like: [1,2,5,11,50]
  • A datetime index must be spaced evenly - i.e., monthly data is better handled when the interval date is the first of the month.
  • If the datetime index is a weekly interval, use a Monday-Friday format.
  • Intraday data is not officially supported at this time.

The equities market revolves around the S&P 500, so let's take a look at the ETF, SPY, from inception:

spy = openbb.stocks.load('SPY', start_date = '1990-01-01')
Loading Daily data for SPY with starting period 1993-01-29.

The printed message indicates that the first day of available data is not the same as the requested start date. Wikipedia shows the fund was launched on January 22, 1993. The product was marketed and sold to liquidity providers prior to trading on a public exchange, so this DataFrame is pretty darn close to the inception date. We can confirm that this data arrived as expected by printing the created DataFrame.

spy.head(5)
dateOpenHighLowCloseAdj CloseVolume
1993-01-29 00:00:0043.968843.968843.7543.937525.3341.0032e+06
1993-02-01 00:00:0043.968844.2543.968844.2525.5142480500
1993-02-02 00:00:0044.218844.37544.12544.343825.5683201300
1993-02-03 00:00:0044.406244.843844.37544.812525.8385529400
1993-02-04 00:00:0044.968845.093844.46884525.9467531500

Plot

The data can also be inspected visually, openbb.forecast.plot:

openbb.forecast.plot(data=spy, columns = ['Adj Close'])

openbb.forecast.plot

Theta

Data consisting of a numeric value and a datetime index is sufficient enough for feeding the inputs to a forecast model. One important distinction between the Terminal and SDK is that the target_column must be explicitly declared when using the SDK, if it is not labeled as "close". It is case-sensitive.

To use a forecast model with default parameters, all that is required in the syntax is:

  • The name of the dataset.
  • The target column for the forecast.

A basic, default, syntax will look like:

openbb.forecast.theta_chart(data = spy, target_column = 'Adj Close')

The default number of days to predict for all models is five. If the interval of the time-series is not daily, days equates to the interval of the index.

Theta Model obtains MAPE: 1.91%

openbb.forecast.theta_chart

DatetimePrediction
2022-11-24402.62
2022-11-25402.92
2022-11-28403.14
2022-11-29403.38
2022-11-30403.59

Refer to the docstrings to learn about each model's unique set of arguments.

help(openbb.forecast.theta_chart)

Feature Engineering

This category of functions are for adding columns to a dataset that are the results of calculations, like technical and quantitative analysis. Individual parameters will vary slightly between functions, but syntax construction will be similar.

EMA

A moving average provides an indication of the trend of the price movement by cutting down the amount of "noise" in a price chart.

help(openbb.forecast.ema)

Parameters
----------
dataset : pd.DataFrame
The dataset you wish to clean
target_column : str
The column you wish to add the EMA to
period : int
Time Span

Returns
-------
pd.DataFrame
Dataframe with added EMA column

The example below adds a column to the spy dataset for the 150-day exponential moving average of the adjusted-close price.

spy = openbb.forecast.ema(spy, target_column = 'Adj Close', period = 150)

spy.tail(3)
dateOpenHighLowCloseAdj CloseVolumeEMA_150
75082022-11-21394.64395.82392.66394.59394.5951243200394.923
75092022-11-22396.63400.07395.15399.9399.960429000394.989
75102022-11-23399.55402.93399.31402.42402.4268161400395.087

Additional columns can be added for each desired period length of the calculation:

spy = openbb.forecast.ema(spy, target_column = 'Adj Close', period = 20)

spy.tail(3)
dateOpenHighLowCloseAdj CloseVolumeEMA_150EMA_20
75082022-11-21394.64395.82392.66394.59394.5951243200394.923387.237
75092022-11-22396.63400.07395.15399.9399.960429000394.989388.443
75102022-11-23399.55402.93399.31402.42402.4268161400395.087389.775

The process can be repeated as required.

RSI

Similar to ema, rsi adds a column for the Relative Strength Index. The three variables are the same here as above. A period of ten equates to ten trading days, or two-weeks.

spy = openbb.forecast.rsi(spy, target_column = 'Adj Close', period = 10)

spy.tail(3)
dateOpenHighLowCloseAdj CloseVolumeEMA_150EMA_20RSI_10_Adj Close
75082022-11-21394.64395.82392.66394.59394.5951243200394.923387.23758.837
75092022-11-22396.63400.07395.15399.9399.960429000394.989388.44363.7145
75102022-11-23399.55402.93399.31402.42402.4268161400395.087389.77565.8484

Let's add another column for a twelve-week period:

spy = openbb.forecast.rsi(spy, target_column = 'Adj Close', period = 60)

spy.tail(3)
dateOpenHighLowCloseAdj CloseVolumeEMA_150EMA_20RSI_10_Adj CloseRSI_60_Adj Close
75082022-11-21394.64395.82392.66394.59394.5951243200394.923387.23758.83750.5453
75092022-11-22396.63400.07395.15399.9399.960429000394.989388.44363.714551.4456
75102022-11-23399.55402.93399.31402.42402.4268161400395.087389.77565.848451.8685

STO

Some of the Feature Engineering commands require multiple columns, openbb.forecast.sto is one of them.

help(openbb.forecast.sto)
Stochastic Oscillator %K and %D : A stochastic oscillator is a momentum indicator comparing a particular closing price of a security to a range of its prices over a certain period of time. %K and %D are slow and fast indicators.

Requires Low/High/Close columns.
Note: This will drop first rows equal to period due to how this metric is calculated.

Parameters
----------
close_column: str
Column name for closing price
high_column: str
Column name for high price
low_column: str
Column name for low price
dataset : pd.DataFrame
The dataset you wish to calculate for
period : int
Span

Returns
-------
pd.DataFrame
Dataframe with added STO K & D columns

The results of these calculations appends the dataset with two additional columns.

spy = openbb.forecast.sto(
dataset = spy,
high_column='High',
low_column = 'Low',
close_column = 'Adj Close',
period = 20
)

spy.tail(3)
dateOpenHighLowCloseAdj CloseVolumeEMA_150EMA_20RSI_10_Adj CloseRSI_60_Adj CloseSO%K_20SO%D_20
2022-11-21 00:00:00394.64395.82392.66394.59394.595.12432e+07394.923387.23758.83750.545376.96979.1396
2022-11-22 00:00:00396.63400.07395.15399.9399.96.0429e+07394.989388.44363.714551.445692.810283.6814
2022-11-23 00:00:00399.55402.93399.31402.42402.426.81614e+07395.087389.77565.848451.868598.506289.4285

Exploration

As made evident by the composite dataset created, the name of a column can be undesirable. The exploration functions provide some tools for managing and maintaining the dataset.

Rename

Column names can be altered with openbb.forecast.rename. One column can be changed:

spy = openbb.forecast.rename(spy, 'RSI_10_Adj Close', 'RSI_10')

spy.tail(1)
dateOpenHighLowCloseAdj CloseVolumeEMA_150EMA_20RSI_10RSI_60_Adj CloseSO%K_20SO%D_20
2022-11-23 00:00:00399.55402.93399.31402.42402.426.81614e+07395.087389.77565.848451.868598.506289.4285

Let's rename a few more to make working with them a little easier, this time using the Python-method:

spy.rename(columns = {
'RSI_60_Adj Close': 'RSI_60',
'SO%K_20': 'STO_Slow',
'SO%D_20': 'STO_Fast'}, inplace = True)

Verify the names were updated as intended with a console print:

spy.columns

Index(['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume', 'EMA_150', 'EMA_20', 'RSI_10', 'RSI_60', STO_Slow', 'STO_Fast'], dtype='object')

Delete

Say, for example, that we would like to eliminate the Close column in favour of the adjusted-close values. First, delete the desired column:

openbb.forecast.delete(spy, 'Close')

Then, let's rename, 'Adj Close', as, 'Close', and verify the results:

spy = openbb.forecast.rename(spy, 'Adj Close', 'Close')

spy.tail(1)
dateOpenHighLowCloseVolumeEMA_150EMA_20RSI_10RSI_60STO_SlowSTO_Fast
2022-11-23 00:00:00399.55402.93399.31402.426.81614e+07395.087389.77565.848451.868598.506289.4285

Models

Some models are more taxing on system resources than others, and some take considerably longer to run. Changes to parameters can have dramatic effects on the forecast, be sure to make note of the changes while tuning the hyper-parameters. There are also two distinct types of models:

  • Those with the ability to target past-covariates.
  • Those without the ability to target past-covarites.

We currently recommend using the _chart version for every model.

Models of the former type are:

  • linregr
  • regr
  • brnn
  • nbeats
  • nhits
  • tcn
  • trans
  • tft

All models default to past-covariates = None, and targets for past covariates are selected with a comma-separated list of names, as demonstrated below.

regr_chart

openbb.forecast.regr_chart is a regression model which can forecast with, or without, past-covariates. The first example below is without.

openbb.forecast.regr_chart(spy, target_column = 'Close')
Predicting Regression for 5 days

Regression model obtains MAPE: 1.90%

openbb.forecast.regr_chart

DatetimePrediction
2022-11-24403.06
2022-11-25401.95
2022-11-28402.69
2022-11-29402.55
2022-11-30399.84

Then, targeting both EMA columns as past-covariates:

openbb.forecast.regr_chart(spy, target_column = 'Close', past_covariates= "EMA_150,EMA_20")
Warning: when using past covariates n_predict must equal output_chunk_length. We have changed your output_chunk_length to 5 to match your n_predict

Covariate #0: EMA_150
Covariate #1: EMA_20

Predicting Regression for 5 days

Regression model obtains MAPE: 1.85%

openbb.forecast.regr_chart

DatetimePrediction
2022-11-24403.20
2022-11-25401.95
2022-11-28402.15
2022-11-29400.99
2022-11-30398.01

Adding these past-covariates has improved the MAPE by 0.05%, which is a good thing; like golf, a lower score is better.

A second chart displayed by a regression model is for "explainability", SHAP values. It is an illustration of which past-covariates have the most impact on the model output.

Explainability

Targeting the Volume column as a past-covariate reveals it to be negatively impacting the forecast, in this particular instance and application.

openbb.forecast.regr_chart(spy, target_column = 'Close', past_covariates="Volume")

openbb.forecast.regr_chart

Combine

Let's add another potential past-covariate to the dataset by taking the adjusted-close value of XOM, and using combine to join the column with our existing DataFrame.

xom = openbb.stocks.load("XOM", start_date = '1993-01-29')
spy = openbb.forecast.combine(df1 = spy, df2 = xom, column = 'Adj Close', dataset = 'XOM' )
spy.rename(columns = {'XOM_Adj Close': 'XOM'}, inplace = True)

Corr

openbb.forecast.corr calculates the correlation between all columns in a dataset.

openbb.forecast.corr(spy)
OpenHighLowCloseVolumeEMA_150EMA_20RSI_10_Adj CloseRSI_60STO_SlowSTO_FastXOM
Open10.9999280.9999070.9962960.1026010.9908440.9956260.04858530.06854730.6314120.6358140.725111
High0.99992810.9998450.9963880.1053010.9913710.9958190.04681990.06480850.632980.6372210.724806
Low0.9999070.99984510.9963370.09889360.9903130.9953870.05483030.07407190.6301260.6344850.725668
Close0.9962960.9963880.99633710.1158540.9955060.999310.05443620.07084910.622150.6262350.725945
Volume0.1026010.1053010.09889360.11585410.1435540.125322-0.255959-0.33920.3875540.3845610.470041
EMA_1500.9908440.9913710.9903130.9955060.14355410.9971170.007950850.002949350.631390.6353930.737946
EMA_200.9956260.9958190.9953870.999310.1253220.99711710.02958480.05305820.6218290.6259250.726945
RSI_10_Adj Close0.04858530.04681990.05483030.0544362-0.2559590.007950850.029584810.7077230.005506610.004758050.0316687
RSI_600.06854730.06480850.07407190.0708491-0.33920.002949350.05305820.7077231-0.203022-0.2015850.00254247
STO_Slow0.6314120.632980.6301260.622150.3875540.631390.6218290.00550661-0.20302210.9912310.609652
STO_Fast0.6358140.6372210.6344850.6262350.3845610.6353930.6259250.00475805-0.2015850.99123110.613626
XOM0.7251110.7248060.7256680.7259450.4700410.7379460.7269450.03166870.002542470.6096520.6136261

Let's see how Exxon impacts our previous forecast.

openbb.forecast.regr_chart(data = spy, target_column = "Close", dataset_name = 'SPY', past_covariates = "EMA_20,EMA_150,XOM")
Warning: when using past covariates n_predict must equal output_chunk_length. We have changed your output_chunk_length to 5 to match your n_predict

Covariate #0: EMA_20
Covariate #1: EMA_150
Covariate #2: XOM

Predicting Regression for 5 days

Regression model obtains MAPE: 1.80%
DatetimePrediction
2022-11-24401.70
2022-11-25402.02
2022-11-26402.25
2022-11-27401.48
2022-11-28397.16

openbb.forecast.regr_chart

To include pan/zoom functionality for charts, substitute %matplotlib widget in the import statement block. The code block below will recreate the DataFrame as shown in the examples above:

from openbb_terminal.sdk import openbb
import pandas as pd
# %matplotlib widget (uncomment if using a Jupyter Interactive Terminal or Notebook)

spy:pd.DataFrame = []

spy = openbb.stocks.load('SPY', start_date = '1990-01-01')

spy = openbb.forecast.ema(spy, target_column = 'Adj Close', period = 150)

spy = openbb.forecast.ema(spy, target_column = 'Adj Close', period = 20)

spy = openbb.forecast.rsi(spy, target_column = 'Adj Close', period = 10)

spy = openbb.forecast.rsi(spy, target_column = 'Adj Close', period = 60)

spy = openbb.forecast.sto(
dataset = spy,
high_column='High',
low_column = 'Low',
close_column = 'Adj Close',
period = 20
)

openbb.forecast.delete(spy, 'Close')

spy.rename(columns = {
'Adj Close': 'Close',
'RSI_60_Adj Close': 'RSI_10',
'RSI_60_Adj Close': 'RSI_60',
'SO%K_20': 'STO_Slow',
'SO%D_20': 'STO_Fast'}, inplace = True)

xom = openbb.stocks.load("XOM", start_date = '1993-01-29')
openbb.forecast.combine(df1 = spy, df2 = xom, column = 'Adj Close', dataset = 'XOM' )
spy.rename(columns = {'XOM_Adj Close': 'XOM'}, inplace = True)

spy

Hyper-Parameters

Hyper-parameters are the fine-tune dials for each model. Refer to the docstrings for the extensive list. The parameters below are the ways in which the regression model can be altered. Each model will be different, and their responses will vary. The demonstrated workflow is a simple way to begin experimenting with the functions. The same general processes can be applied for all models. The purpose of this guide is to help users get going with using the Forecast module, some assembly required.

help(openbb.forecast.regr_chart)

Help on Operation in module openbb_terminal.core.library.operation:

<openbb_terminal.core.library.operation.Operation object>
Display Regression Forecasting

Parameters
----------
data: Union[pd.Series, pd.DataFrame]
Input Data
target_column: str
Target column to forecast. Defaults to "close".
dataset_name: str
The name of the ticker to be predicted
n_predict: int
Days to predict. Defaults to 5.
train_split: float
Train/val split. Defaults to 0.85.
past_covariates: str
Multiple secondary columns to factor in when forecasting. Defaults to None.
forecast_horizon: int
Forecast horizon when performing historical forecasting. Defaults to 5.
output_chunk_length: int
The length of the forecast of the model. Defaults to 1.
lags: Union[int, List[int]]
lagged target values to predict the next time step
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