Source code for finstmt.forecast.models.trend

from typing import Optional

import numpy as np
import pandas as pd
import statsmodels.api as sm
from statsmodels.regression.linear_model import RegressionResults

from finstmt.exc import ForecastNotFitException
from finstmt.forecast.models.base import ForecastModel


[docs]class LinearTrendModel(ForecastModel): model: Optional[sm.OLS] = None model_result: Optional[RegressionResults] = None
[docs] def fit(self, series: pd.Series): X = sm.add_constant(np.arange(len(series))) self.model = sm.OLS(series, X) self.model_result = self.model.fit() super().fit(series)
[docs] def predict(self) -> pd.Series: if self.model is None or self.model_result is None or self.orig_series is None: raise ForecastNotFitException("call .fit before .predict") last_t = len(self.model.exog) - 1 step = self.desired_freq_t_multiplier future_X = sm.add_constant( np.arange( last_t + step, last_t + (self.config.periods * step) + step * 0.9, step ) ) future_dates = self._future_date_range all_X = np.concatenate((self.model.exog, future_X)) all_dates = np.concatenate((self.orig_series.index, future_dates)) predicted = self.model_result.get_prediction(all_X) predict_df = predicted.summary_frame().set_index(all_dates) self.result_df = predict_df[["mean", "mean_ci_lower", "mean_ci_upper"]].rename( columns={"mean_ci_lower": "lower", "mean_ci_upper": "upper"} ) self.result = self.result_df["mean"].loc[future_dates] super().predict() return self.result