def historical_forecasts(
        self,
        series: Union[TimeSeries, Sequence[TimeSeries]],
        past_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
        future_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
        forecast_horizon: int = 1,
        num_samples: int = 1,
        train_length: Optional[int] = None,
        start: Optional[Union[pd.Timestamp, float, int]] = None,
        start_format: Literal["position", "value"] = "value",
        stride: int = 1,
        retrain: Union[bool, int, Callable[..., bool]] = True,
        overlap_end: bool = False,
        last_points_only: bool = True,
        verbose: bool = False,
        show_warnings: bool = True,
        predict_likelihood_parameters: bool = False,
        enable_optimization: bool = True,
        data_transformers: Optional[
            dict[str, Union[BaseDataTransformer, Pipeline]]
        ] = None,
        fit_kwargs: Optional[dict[str, Any]] = None,
        predict_kwargs: Optional[dict[str, Any]] = None,
        sample_weight: Optional[Union[TimeSeries, Sequence[TimeSeries], str]] = None,
        random_state: Optional[int] = None,
    ) -> Union[TimeSeries, list[TimeSeries], list[list[TimeSeries]]]:
        """Generates historical forecasts by simulating predictions at various points in time throughout the history of
        the provided (potentially multiple) `series`. This process involves retrospectively applying the model to
        different time steps, as if the forecasts were made in real-time at those specific moments. This allows for an
        evaluation of the model's performance over the entire duration of the series, providing insights into its
        predictive accuracy and robustness across different historical periods.

        There are two main modes for this method:

        - Re-training Mode (Default, `retrain=True`): The model is re-trained at each step of the simulation, and
          generates a forecast using the updated model. In case of multiple series, the model is re-trained on each
          series independently (global training is not yet supported).
        - Pre-trained Mode (`retrain=False`): The forecasts are generated at each step of the simulation without
          re-training. It is only supported for pre-trained global forecasting models. This mode is significantly
          faster as it skips the re-training step.

        By choosing the appropriate mode, you can balance between computational efficiency and the need for up-to-date
        model training.

        **Re-training Mode:** This mode repeatedly builds a training set by either expanding from the beginning of
        the `series` or by using a fixed-length `train_length` (the start point can also be configured with `start`
        and `start_format`). The model is then trained on this training set, and a forecast of length `forecast_horizon`
        is generated. Subsequently, the end of the training set is moved forward by `stride` time steps, and the process
        is repeated.

        **Pre-trained Mode:** This mode is only supported for pre-trained global forecasting models. It uses the same
        simulation steps as in the *Re-training Mode* (ignoring `train_length`), but generates the forecasts directly
        without re-training.

        By default, with `last_points_only=True`, this method returns a single time series (or a sequence of time
        series) composed of the last point from each historical forecast. This time series will thus have a frequency of
        `series.freq * stride`.
        If `last_points_only=False`, it will instead return a list (or a sequence of lists) of the full historical
        forecast series each with frequency `series.freq`.

        Parameters
        ----------
        series
            A (sequence of) target time series used to successively train (if `retrain` is not ``False``) and compute
            the historical forecasts.
        past_covariates
            Optionally, a (sequence of) past-observed covariate time series for every input time series in `series`.
            This applies only if the model supports past covariates.
        future_covariates
            Optionally, a (sequence of) future-known covariate time series for every input time series in `series`.
            This applies only if the model supports future covariates.
        forecast_horizon
            The forecast horizon for the predictions.
        num_samples
            Number of times a prediction is sampled from a probabilistic model. Use values ``>1`` only for probabilistic
            models.
        train_length
            Optionally, use a fixed length / number of time steps for every constructed training set (rolling window
            mode). Only effective when `retrain` is not ``False``. The default is ``None``, where it uses all time
            steps up until the prediction time (expanding window mode). If larger than the number of available time
            steps, uses the expanding mode. Needs to be at least `min_train_series_length`.
        start
            Optionally, the first point in time at which a prediction is computed. This parameter supports:
            ``float``, ``int``, ``pandas.Timestamp``, and ``None``.
            If a ``float``, it is the proportion of the time series that should lie before the first prediction point.
            If an ``int``, it is either the index position of the first prediction point for `series` with a
            `pd.DatetimeIndex`, or the index value for `series` with a `pd.RangeIndex`. The latter can be changed to
            the index position with `start_format="position"`.
            If a ``pandas.Timestamp``, it is the time stamp of the first prediction point.
            If ``None``, the first prediction point will automatically be set to:

            - the first predictable point if `retrain` is ``False``, or `retrain` is a Callable and the first
              predictable point is earlier than the first trainable point.
            - the first trainable point if `retrain` is ``True`` or ``int`` (given `train_length`),
              or `retrain` is a ``Callable`` and the first trainable point is earlier than the first predictable point.
            - the first trainable point (given `train_length`) otherwise

            Note: If `start` is not within the trainable / forecastable points, uses the closest valid start point that
              is a round multiple of `stride` ahead of `start`. Raises a `ValueError`, if no valid start point exists.
            Note: If the model uses a shifted output (`output_chunk_shift > 0`), then the first predicted point is also
              shifted by `output_chunk_shift` points into the future.
            Note: If `start` is outside the possible historical forecasting times, will ignore the parameter
              (default behavior with ``None``) and start at the first trainable/predictable point.
        start_format
            Defines the `start` format.
            If set to ``'position'``, `start` corresponds to the index position of the first predicted point and can
            range from `(-len(series), len(series) - 1)`.
            If set to ``'value'``, `start` corresponds to the index value/label of the first predicted point. Will raise
            an error if the value is not in `series`' index. Default: ``'value'``.
        stride
            The number of time steps between two consecutive predictions.
        retrain
            Whether and/or on which condition to retrain the model before predicting.
            This parameter supports 3 different types: ``bool``, (positive) ``int``, and ``Callable`` (returning a
            ``bool``).
            In the case of ``bool``: retrain the model at each step (`True`), or never retrain the model (`False`).
            In the case of ``int``: the model is retrained every `retrain` iterations.
            In the case of ``Callable``: the model is retrained whenever callable returns `True`.
            The callable must have the following positional arguments:

            - `counter` (int): current `retrain` iteration
            - `pred_time` (pd.Timestamp or int): timestamp of forecast time (end of the training series)
            - `train_series` (TimeSeries): train series up to `pred_time`
            - `past_covariates` (TimeSeries): past_covariates series up to `pred_time`
            - `future_covariates` (TimeSeries): future_covariates series up to `min(pred_time + series.freq *
              forecast_horizon, series.end_time())`

            Note: if any optional `*_covariates` are not passed to `historical_forecast`, ``None`` will be passed
            to the corresponding retrain function argument.
            Note: some models require being retrained every time and do not support anything other than
            `retrain=True`.
            Note: also controls the retraining of the `data_transformers`.
        overlap_end
            Whether the returned forecasts can go beyond the series' end or not.
        last_points_only
            Whether to return only the last point of each historical forecast. If set to ``True``, the method returns a
            single ``TimeSeries`` (for each time series in `series`) containing the successive point forecasts.
            Otherwise, returns a list of historical ``TimeSeries`` forecasts.
        verbose
            Whether to print the progress.
        show_warnings
            Whether to show warnings related to historical forecasts optimization, or parameters `start` and
            `train_length`.
        predict_likelihood_parameters
            If set to `True`, the model predicts the parameters of its `likelihood` instead of the target. Only
            supported for probabilistic models with a likelihood, `num_samples = 1` and `n<=output_chunk_length`.
            Default: ``False``.
        enable_optimization
            Whether to use the optimized version of `historical_forecasts` when supported and available.
            Default: ``True``.
        data_transformers
            Optionally, a dictionary of `BaseDataTransformer` or `Pipeline` to apply to the corresponding series
            (possibles keys; "series", "past_covariates", "future_covariates"). If provided, all input series must be
            in the un-transformed space. For fittable transformer / pipeline:

            - if `retrain=True`, the data transformer re-fit on the training data at each historical forecast step.
            - if `retrain=False`, the data transformer transforms the series once before all the forecasts.

            The fitted transformer is used to transform the input during both training and prediction.
            If the transformation is invertible, the forecasts will be inverse-transformed.
        fit_kwargs
            Optionally, some additional arguments passed to the model `fit()` method.
        predict_kwargs
            Optionally, some additional arguments passed to the model `predict()` method.
        sample_weight
            Optionally, some sample weights to apply to the target `series` labels for training. Only effective when
            `retrain` is not ``False``. They are applied per observation, per label (each step in
            `output_chunk_length`), and per component.
            If a series or sequence of series, then those weights are used. If the weight series only have a single
            component / column, then the weights are applied globally to all components in `series`. Otherwise, for
            component-specific weights, the number of components must match those of `series`.
            If a string, then the weights are generated using built-in weighting functions. The available options are
            `"linear"` or `"exponential"` decay - the further in the past, the lower the weight. The weights are
            computed per time `series`.
        random_state
            Controls the randomness of probabilistic predictions.

        Returns
        -------
        TimeSeries
            A single historical forecast for a single `series` and `last_points_only=True`: it contains only the
            predictions at step `forecast_horizon` from all historical forecasts.
        List[TimeSeries]
            A list of historical forecasts for:

            - a sequence (list) of `series` and `last_points_only=True`: for each series, it contains only the
              predictions at step `forecast_horizon` from all historical forecasts.
            - a single `series` and `last_points_only=False`: for each historical forecast, it contains the entire
              horizon `forecast_horizon`.
        List[List[TimeSeries]]
            A list of lists of historical forecasts for a sequence of `series` and `last_points_only=False`. For each
            series, and historical forecast, it contains the entire horizon `forecast_horizon`. The outer list
            is over the series provided in the input sequence, and the inner lists contain the historical forecasts for
            each series.
        """
        model: ForecastingModel = self
        # only GlobalForecastingModels support historical forecasting without retraining the model
        base_class_name = model.__class__.__base__.__name__

        # we can directly abort if retrain is False and fit hasn't been called before
        raise_if(
            not model._fit_called and retrain is False,
            "The model has not been fitted yet, and `retrain` is ``False``. "
            "Either call `fit()` before `historical_forecasts()`, or set `retrain` "
            "to something different than ``False``.",
            logger,
        )

        raise_if(
            (isinstance(retrain, Callable) or int(retrain) != 1)
            and (not model._supports_non_retrainable_historical_forecasts),
            f"{base_class_name} does not support historical forecasting with `retrain` set to `False`. "
            f"For now, this is only supported with GlobalForecastingModels such as TorchForecastingModels. "
            f"For more information, read the documentation for `retrain` in `historical_forecasts()`",
            logger,
        )

        if train_length and not isinstance(train_length, int):
            raise_log(
                TypeError("If not None, train_length needs to be an integer."),
                logger,
            )
        elif (train_length is not None) and train_length < 1:
            raise_log(
                ValueError("If not None, train_length needs to be positive."),
                logger,
            )
        elif (
            train_length is not None
        ) and train_length < model._training_sample_time_index_length + (
            model.min_train_samples - 1
        ):
            raise_log(
                ValueError(
                    "train_length is too small for the training requirements of this model. "
                    f"Must be `>={model._training_sample_time_index_length + (model.min_train_samples - 1)}`."
                ),
                logger,
            )
        if train_length is not None and retrain is False:
            raise_log(
                ValueError("cannot use `train_length` when `retrain=False`."),
                logger,
            )

        if isinstance(retrain, bool) or (isinstance(retrain, int) and retrain >= 0):

            def retrain_func(
                counter, pred_time, train_series, past_covariates, future_covariates
            ):
                return counter % int(retrain) == 0 if retrain else False

        elif isinstance(retrain, Callable):
            retrain_func = retrain

            # check that the signature matches the documentation
            expected_arguments = [
                "counter",
                "pred_time",
                "train_series",
                "past_covariates",
                "future_covariates",
            ]
            passed_arguments = list(inspect.signature(retrain_func).parameters.keys())
            raise_if(
                expected_arguments != passed_arguments,
                f"the Callable `retrain` must have a signature/arguments matching the following positional arguments: "
                f"{expected_arguments}.",
                logger,
            )

            # passing dummy values to check the type of the output
            result = retrain_func(
                counter=0,
                pred_time=get_single_series(series).time_index[-1],
                train_series=series,
                past_covariates=past_covariates,
                future_covariates=future_covariates,
            )
            raise_if_not(
                isinstance(result, bool),
                f"Return value of `retrain` must be bool, received {type(result)}",
                logger,
            )
        else:
            retrain_func = None
            raise_log(
                ValueError(
                    "`retrain` argument must be either `bool`, positive `int` or `Callable` (returning `bool`)"
                ),
                logger,
            )

        data_transformers = _convert_data_transformers(
            data_transformers=data_transformers, copy=True
        )

        using_prefitted_transformers = False
        # data transformer already fitted and can be directly applied to all the series
        if data_transformers and not retrain:
            using_prefitted_transformers = True
            series, past_covariates, future_covariates = _apply_data_transformers(
                series=series,
                past_covariates=past_covariates,
                future_covariates=future_covariates,
                data_transformers=data_transformers,
                max_future_cov_lag=model.extreme_lags[5],
                fit_transformers=False,
            )

        # remove unsupported arguments, raise exception if interference with historical forecasts logic
        fit_kwargs, predict_kwargs = _historical_forecasts_sanitize_kwargs(
            model=model,
            fit_kwargs=fit_kwargs,
            predict_kwargs=predict_kwargs,
            retrain=retrain is not False and retrain != 0,
            show_warnings=show_warnings,
        )

        if (
            enable_optimization
            and model.supports_optimized_historical_forecasts
            and model._check_optimizable_historical_forecasts(
                forecast_horizon=forecast_horizon,
                retrain=retrain,
                show_warnings=show_warnings,
            )
        ):
            forecasts = model._optimized_historical_forecasts(
                series=series,
                past_covariates=past_covariates,
                future_covariates=future_covariates,
                num_samples=num_samples,
                start=start,
                start_format=start_format,
                forecast_horizon=forecast_horizon,
                stride=stride,
                overlap_end=overlap_end,
                last_points_only=last_points_only,
                verbose=verbose,
                show_warnings=show_warnings,
                predict_likelihood_parameters=predict_likelihood_parameters,
                random_state=random_state,
                **predict_kwargs,
            )

            return _apply_inverse_data_transformers(
                series=series, forecasts=forecasts, data_transformers=data_transformers
            )

        sequence_type_in = get_series_seq_type(series)
        series = series2seq(series)
        past_covariates = series2seq(past_covariates)
        future_covariates = series2seq(future_covariates)
        sample_weight = (
            sample_weight
            if isinstance(sample_weight, str)
            else series2seq(sample_weight)
        )

        if len(series) == 1:
            # Use tqdm on the outer loop only if there's more than one series to iterate over
            # (otherwise use tqdm on the inner loop).
            outer_iterator = series
        else:
            outer_iterator = _build_tqdm_iterator(
                series, verbose, total=len(series), desc="historical forecasts"
            )

        # deactivate the warning after displaying it once if show_warnings is True
        show_predict_warnings = show_warnings

        forecasts_list = []
        for idx, series_ in enumerate(outer_iterator):
            past_covariates_ = past_covariates[idx] if past_covariates else None
            future_covariates_ = future_covariates[idx] if future_covariates else None
            if isinstance(sample_weight, str):
                sample_weight_ = sample_weight
            else:
                sample_weight_ = sample_weight[idx] if sample_weight else None

            # predictable time indexes (assuming model is already trained)
            historical_forecasts_time_index_predict = (
                _get_historical_forecast_predict_index(
                    model,
                    series_,
                    idx,
                    past_covariates_,
                    future_covariates_,
                    forecast_horizon,
                    overlap_end,
                )
            )

            if retrain:
                # trainable time indexes (considering lags and available covariates)
                historical_forecasts_time_index_train = (
                    _get_historical_forecast_train_index(
                        model,
                        series_,
                        idx,
                        past_covariates_,
                        future_covariates_,
                        forecast_horizon,
                        overlap_end,
                    )
                )

                # We need the first value timestamp to be used in order to properly shift the series
                # Look at both past and future, since the target lags must be taken in consideration
                min_timestamp_series = (
                    historical_forecasts_time_index_train[0]
                    - model._training_sample_time_index_length * series_.freq
                )

                # based on `retrain`, historical_forecasts_time_index is based either on train or predict
                (
                    historical_forecasts_time_index,
                    train_length_,
                ) = _reconciliate_historical_time_indices(
                    model=model,
                    historical_forecasts_time_index_predict=historical_forecasts_time_index_predict,
                    historical_forecasts_time_index_train=historical_forecasts_time_index_train,
                    series=series_,
                    series_idx=idx,
                    retrain=retrain,
                    train_length=train_length,
                    show_warnings=show_warnings,
                )
            else:
                # we are only predicting: start of the series does not have to change
                min_timestamp_series = series_.time_index[0]
                historical_forecasts_time_index = (
                    historical_forecasts_time_index_predict
                )
                train_length_ = None

            # based on `forecast_horizon` and `overlap_end`, historical_forecasts_time_index is shortened
            historical_forecasts_time_index = _adjust_historical_forecasts_time_index(
                series=series_,
                series_idx=idx,
                historical_forecasts_time_index=historical_forecasts_time_index,
                start=start,
                start_format=start_format,
                stride=stride,
                show_warnings=show_warnings,
            )

            # adjust the start of the series depending on whether we train (at some point), or predict only
            # must be performed after the operation on historical_foreacsts_time_index
            if min_timestamp_series > series_.time_index[0]:
                series_ = series_.drop_before(min_timestamp_series - 1 * series_.freq)

            # generate time index for the iteration
            historical_forecasts_time_index = generate_index(
                start=historical_forecasts_time_index[0],
                end=historical_forecasts_time_index[-1],
                freq=series_.freq,
            )

            if len(series) == 1:
                # Only use tqdm if there's no outer loop
                iterator = _build_tqdm_iterator(
                    historical_forecasts_time_index[::stride],
                    verbose,
                    total=(len(historical_forecasts_time_index) - 1) // stride + 1,
                    desc="historical forecasts",
                )
            else:
                iterator = historical_forecasts_time_index[::stride]

            # Either store the whole forecasts or only the last points of each forecast, depending on last_points_only
            forecasts = []
            last_points_times = []
            last_points_values = []
            _counter_train = 0
            forecast_components = None
            # iterate and forecast
            for _counter, pred_time in enumerate(iterator):
                # drop everything after `pred_time` to train on / predict with shifting input
                if pred_time <= series_.end_time():
                    train_series = series_.drop_after(pred_time)
                else:
                    train_series = series_

                # optionally, apply moving window (instead of expanding window)
                if train_length_ and len(train_series) > train_length_:
                    train_series = train_series[-train_length_:]

                # when `retrain=True`, data transformers are also retrained between iterations to avoid data-leakage
                # using a single series
                if data_transformers and retrain:
                    train_series, past_covariates_, future_covariates_ = (
                        _apply_data_transformers(
                            series=train_series,
                            past_covariates=past_covariates_,
                            future_covariates=future_covariates_,
                            data_transformers=data_transformers,
                            max_future_cov_lag=model.extreme_lags[5],
                            fit_transformers=True,
                        )
                    )

                # testing `retrain` to exclude `False` and `0`
                if (
                    retrain
                    and historical_forecasts_time_index_train is not None
                    and historical_forecasts_time_index_train[0]
                    <= pred_time
                    <= historical_forecasts_time_index_train[-1]
                ):
                    # retrain_func processes the series that would be used for training
                    if retrain_func(
                        counter=_counter_train,
                        pred_time=pred_time,
                        train_series=train_series,
                        past_covariates=past_covariates_,
                        future_covariates=future_covariates_,
                    ):
                        # avoid fitting the same model multiple times
                        model = model.untrained_model()
                        model._fit_wrapper(
                            series=train_series,
                            past_covariates=past_covariates_,
                            future_covariates=future_covariates_,
                            sample_weight=sample_weight_,
                            **fit_kwargs,
                        )
                    else:
                        # untrained model was not trained on the first trainable timestamp
                        if not _counter_train and not model._fit_called:
                            raise_log(
                                ValueError(
                                    f"`retrain` is `False` in the first train iteration at prediction point (in time) "
                                    f"`{pred_time}` and the model has not been fit before. Either call `fit()` before "
                                    f"`historical_forecasts()`, use a different `retrain` value or modify the function "
                                    f"to return `True` at or before this timestamp."
                                ),
                                logger,
                            )
                    _counter_train += 1
                elif not _counter and not model._fit_called:
                    # model must be fit before the first prediction
                    # `historical_forecasts_time_index_train` is known to be not None
                    raise_log(
                        ValueError(
                            f"Model has not been fit before the first predict iteration at prediction point "
                            f"(in time) `{pred_time}`. Either call `fit()` before `historical_forecasts()`, "
                            f"set `retrain=True`, modify the function to return `True` at least once before "
                            f"`{pred_time}`, or use a different `start` value. The first 'predictable' "
                            f"timestamp with re-training inside `historical_forecasts` is: "
                            f"{historical_forecasts_time_index_train[0]} (potential `start` value)."
                        ),
                        logger,
                    )

                # for regression models with lags=None, lags_past_covariates=None and min(lags_future_covariates)>=0,
                # the first predictable timestamp is the first timestamp of the series, a dummy ts must be created
                # to support `predict()`
                if len(train_series) == 0:
                    train_series = TimeSeries.from_times_and_values(
                        times=generate_index(
                            start=pred_time - 1 * series_.freq,
                            length=1,
                            freq=series_.freq,
                        ),
                        values=np.array([np.nan]),
                    )

                forecast = model._predict_wrapper(
                    n=forecast_horizon,
                    series=train_series,
                    past_covariates=past_covariates_,
                    future_covariates=future_covariates_,
                    num_samples=num_samples,
                    verbose=verbose,
                    predict_likelihood_parameters=predict_likelihood_parameters,
                    show_warnings=show_predict_warnings,
                    random_state=random_state,
                    **predict_kwargs,
                )

                forecast = _apply_inverse_data_transformers(
                    series=train_series,
                    forecasts=forecast,
                    data_transformers=data_transformers,
                    series_idx=idx if using_prefitted_transformers else None,
                )

                show_predict_warnings = False

                if forecast_components is None:
                    forecast_components = forecast.columns

                if last_points_only:
                    last_points_values.append(forecast.all_values(copy=False)[-1])
                    last_points_times.append(forecast.end_time())
                else:
                    forecasts.append(forecast)

            if last_points_only and last_points_values:
                forecasts_list.append(
                    TimeSeries.from_times_and_values(
                        generate_index(
                            start=last_points_times[0],
                            end=last_points_times[-1],
                            freq=series_.freq * stride,
                        ),
                        np.array(last_points_values),
                        columns=(
                            forecast_components
                            if forecast_components is not None
                            else series_.columns
                        ),
                        static_covariates=(
                            series_.static_covariates
                            if not predict_likelihood_parameters
                            else None
                        ),
                        hierarchy=(
                            series_.hierarchy
                            if not predict_likelihood_parameters
                            else None
                        ),
                        metadata=series_.metadata,
                    )
                )
            else:
                forecasts_list.append(forecasts)

        return series2seq(forecasts_list, seq_type_out=sequence_type_in)
Generates historical forecasts by simulating predictions at various points in time throughout the history of
        the provided (potentially multiple) `series`. This process involves retrospectively applying the model to
        different time steps, as if the forecasts were made in real-time at those specific moments. This allows for an
        evaluation of the model's performance over the entire duration of the series, providing insights into its
        predictive accuracy and robustness across different historical periods.

        There are two main modes for this method:

        - Re-training Mode (Default, `retrain=True`): The model is re-trained at each step of the simulation, and
          generates a forecast using the updated model. In case of multiple series, the model is re-trained on each
          series independently (global training is not yet supported).
        - Pre-trained Mode (`retrain=False`): The forecasts are generated at each step of the simulation without
          re-training. It is only supported for pre-trained global forecasting models. This mode is significantly
          faster as it skips the re-training step.

        By choosing the appropriate mode, you can balance between computational efficiency and the need for up-to-date
        model training.

        **Re-training Mode:** This mode repeatedly builds a training set by either expanding from the beginning of
        the `series` or by using a fixed-length `train_length` (the start point can also be configured with `start`
        and `start_format`). The model is then trained on this training set, and a forecast of length `forecast_horizon`
        is generated. Subsequently, the end of the training set is moved forward by `stride` time steps, and the process
        is repeated.

        **Pre-trained Mode:** This mode is only supported for pre-trained global forecasting models. It uses the same
        simulation steps as in the *Re-training Mode* (ignoring `train_length`), but generates the forecasts directly
        without re-training.

        By default, with `last_points_only=True`, this method returns a single time series (or a sequence of time
        series) composed of the last point from each historical forecast. This time series will thus have a frequency of
        `series.freq * stride`.
        If `last_points_only=False`, it will instead return a list (or a sequence of lists) of the full historical
        forecast series each with frequency `series.freq`.

        Parameters
        ----------
        series
            A (sequence of) target time series used to successively train (if `retrain` is not ``False``) and compute
            the historical forecasts.
        past_covariates
            Optionally, a (sequence of) past-observed covariate time series for every input time series in `series`.
            This applies only if the model supports past covariates.
        future_covariates
            Optionally, a (sequence of) future-known covariate time series for every input time series in `series`.
            This applies only if the model supports future covariates.
        forecast_horizon
            The forecast horizon for the predictions.
        num_samples
            Number of times a prediction is sampled from a probabilistic model. Use values ``>1`` only for probabilistic
            models.
        train_length
            Optionally, use a fixed length / number of time steps for every constructed training set (rolling window
            mode). Only effective when `retrain` is not ``False``. The default is ``None``, where it uses all time
            steps up until the prediction time (expanding window mode). If larger than the number of available time
            steps, uses the expanding mode. Needs to be at least `min_train_series_length`.
        start
            Optionally, the first point in time at which a prediction is computed. This parameter supports:
            ``float``, ``int``, ``pandas.Timestamp``, and ``None``.
            If a ``float``, it is the proportion of the time series that should lie before the first prediction point.
            If an ``int``, it is either the index position of the first prediction point for `series` with a
            `pd.DatetimeIndex`, or the index value for `series` with a `pd.RangeIndex`. The latter can be changed to
            the index position with `start_format="position"`.
            If a ``pandas.Timestamp``, it is the time stamp of the first prediction point.
            If ``None``, the first prediction point will automatically be set to:

            - the first predictable point if `retrain` is ``False``, or `retrain` is a Callable and the first
              predictable point is earlier than the first trainable point.
            - the first trainable point if `retrain` is ``True`` or ``int`` (given `train_length`),
              or `retrain` is a ``Callable`` and the first trainable point is earlier than the first predictable point.
            - the first trainable point (given `train_length`) otherwise

            Note: If `start` is not within the trainable / forecastable points, uses the closest valid start point that
              is a round multiple of `stride` ahead of `start`. Raises a `ValueError`, if no valid start point exists.
            Note: If the model uses a shifted output (`output_chunk_shift > 0`), then the first predicted point is also
              shifted by `output_chunk_shift` points into the future.
            Note: If `start` is outside the possible historical forecasting times, will ignore the parameter
              (default behavior with ``None``) and start at the first trainable/predictable point.
        start_format
            Defines the `start` format.
            If set to ``'position'``, `start` corresponds to the index position of the first predicted point and can
            range from `(-len(series), len(series) - 1)`.
            If set to ``'value'``, `start` corresponds to the index value/label of the first predicted point. Will raise
            an error if the value is not in `series`' index. Default: ``'value'``.
        stride
            The number of time steps between two consecutive predictions.
        retrain
            Whether and/or on which condition to retrain the model before predicting.
            This parameter supports 3 different types: ``bool``, (positive) ``int``, and ``Callable`` (returning a
            ``bool``).
            In the case of ``bool``: retrain the model at each step (`True`), or never retrain the model (`False`).
            In the case of ``int``: the model is retrained every `retrain` iterations.
            In the case of ``Callable``: the model is retrained whenever callable returns `True`.
            The callable must have the following positional arguments:

            - `counter` (int): current `retrain` iteration
            - `pred_time` (pd.Timestamp or int): timestamp of forecast time (end of the training series)
            - `train_series` (TimeSeries): train series up to `pred_time`
            - `past_covariates` (TimeSeries): past_covariates series up to `pred_time`
            - `future_covariates` (TimeSeries): future_covariates series up to `min(pred_time + series.freq *
              forecast_horizon, series.end_time())`

            Note: if any optional `*_covariates` are not passed to `historical_forecast`, ``None`` will be passed
            to the corresponding retrain function argument.
            Note: some models require being retrained every time and do not support anything other than
            `retrain=True`.
            Note: also controls the retraining of the `data_transformers`.
        overlap_end
            Whether the returned forecasts can go beyond the series' end or not.
        last_points_only
            Whether to return only the last point of each historical forecast. If set to ``True``, the method returns a
            single ``TimeSeries`` (for each time series in `series`) containing the successive point forecasts.
            Otherwise, returns a list of historical ``TimeSeries`` forecasts.
        verbose
            Whether to print the progress.
        show_warnings
            Whether to show warnings related to historical forecasts optimization, or parameters `start` and
            `train_length`.
        predict_likelihood_parameters
            If set to `True`, the model predicts the parameters of its `likelihood` instead of the target. Only
            supported for probabilistic models with a likelihood, `num_samples = 1` and `n<=output_chunk_length`.
            Default: ``False``.
        enable_optimization
            Whether to use the optimized version of `historical_forecasts` when supported and available.
            Default: ``True``.
        data_transformers
            Optionally, a dictionary of `BaseDataTransformer` or `Pipeline` to apply to the corresponding series
            (possibles keys; "series", "past_covariates", "future_covariates"). If provided, all input series must be
            in the un-transformed space. For fittable transformer / pipeline:

            - if `retrain=True`, the data transformer re-fit on the training data at each historical forecast step.
            - if `retrain=False`, the data transformer transforms the series once before all the forecasts.

            The fitted transformer is used to transform the input during both training and prediction.
            If the transformation is invertible, the forecasts will be inverse-transformed.
        fit_kwargs
            Optionally, some additional arguments passed to the model `fit()` method.
        predict_kwargs
            Optionally, some additional arguments passed to the model `predict()` method.
        sample_weight
            Optionally, some sample weights to apply to the target `series` labels for training. Only effective when
            `retrain` is not ``False``. They are applied per observation, per label (each step in
            `output_chunk_length`), and per component.
            If a series or sequence of series, then those weights are used. If the weight series only have a single
            component / column, then the weights are applied globally to all components in `series`. Otherwise, for
            component-specific weights, the number of components must match those of `series`.
            If a string, then the weights are generated using built-in weighting functions. The available options are
            `"linear"` or `"exponential"` decay - the further in the past, the lower the weight. The weights are
            computed per time `series`.
        random_state
            Controls the randomness of probabilistic predictions.

        Returns
        -------
        TimeSeries
            A single historical forecast for a single `series` and `last_points_only=True`: it contains only the
            predictions at step `forecast_horizon` from all historical forecasts.
        List[TimeSeries]
            A list of historical forecasts for:

            - a sequence (list) of `series` and `last_points_only=True`: for each series, it contains only the
              predictions at step `forecast_horizon` from all historical forecasts.
            - a single `series` and `last_points_only=False`: for each historical forecast, it contains the entire
              horizon `forecast_horizon`.
        List[List[TimeSeries]]
            A list of lists of historical forecasts for a sequence of `series` and `last_points_only=False`. For each
            series, and historical forecast, it contains the entire horizon `forecast_horizon`. The outer list
            is over the series provided in the input sequence, and the inner lists contain the historical forecasts for
            each series.
        
darts/models/forecasting/forecasting_model.py