code: def backtesting_forecaster(
      forecaster,
      y: pd.Series,
      steps: int,
      metric: Union[str, Callable, list],
      initial_train_size: Optional[int] = None,
      fixed_train_size: bool = True,
      gap: int = 0,
      allow_incomplete_fold: bool = True,
      exog: Optional[Union[pd.Series, pd.DataFrame]] = None,
      refit: Optional[Union[bool, int]] = False,
      interval: Optional[list] = None,
      n_boot: int = 500,
      random_state: int = 123,
      in_sample_residuals: bool = True,
      n_jobs: Optional[Union[int, str]] = "auto",
      verbose: bool = False,
      show_progress: bool = True,
  ) -> Tuple[Union[float, list], pd.DataFrame]:
      """
      Backtesting of forecaster model.
  
      - If `refit` is `False`, the model will be trained only once using the
      `initial_train_size` first observations.
      - If `refit` is `True`, the model is trained on each iteration, increasing
      the training set.
      - If `refit` is an `integer`, the model will be trained every that number
      of iterations.
      - If `forecaster` is already trained and `initial_train_size` is `None`,
      no initial train will be done and all data will be used to evaluate the model.
      However, the first `len(forecaster.last_window)` observations are needed
      to create the initial predictors, so no predictions are calculated for them.
  
      A copy of the original forecaster is created so that it is not modified during
      the process.
  
      Parameters
      ----------
      forecaster : ForecasterAutoreg, ForecasterAutoregCustom, ForecasterAutoregDirect
          Forecaster model.
      y : pandas Series
          Training time series.
      steps : int
          Number of steps to predict.
      metric : str, Callable, list
          Metric used to quantify the goodness of fit of the model.
  
          - If `string`: {'mean_squared_error', 'mean_absolute_error',
          'mean_absolute_percentage_error', 'mean_squared_log_error'}
          - If `Callable`: Function with arguments y_true, y_pred that returns
          a float.
          - If `list`: List containing multiple strings and/or Callables.
      initial_train_size : int, default `None`
          Number of samples in the initial train split. If `None` and `forecaster` is
          already trained, no initial train is done and all data is used to evaluate the
          model. However, the first `len(forecaster.last_window)` observations are needed
          to create the initial predictors, so no predictions are calculated for them.
          This useful to backtest the model on the same data used to train it.
          `None` is only allowed when `refit` is `False` and `forecaster` is already
          trained.
      fixed_train_size : bool, default `True`
          If True, train size doesn't increase but moves by `steps` in each iteration.
      gap : int, default `0`
          Number of samples to be excluded after the end of each training set and
          before the test set.
      allow_incomplete_fold : bool, default `True`
          Last fold is allowed to have a smaller number of samples than the
          `test_size`. If `False`, the last fold is excluded.
      exog : pandas Series, pandas DataFrame, default `None`
          Exogenous variable/s included as predictor/s. Must have the same
          number of observations as `y` and should be aligned so that y[i] is
          regressed on exog[i].
      refit : bool, int, default `False`
          Whether to re-fit the forecaster in each iteration. If `refit` is an integer,
          the Forecaster will be trained every that number of iterations.
      interval : list, default `None`
          Confidence of the prediction interval estimated. Sequence of percentiles
          to compute, which must be between 0 and 100 inclusive. For example,
          interval of 95% should be as `interval = [2.5, 97.5]`. If `None`, no
          intervals are estimated.
      n_boot : int, default `500`
          Number of bootstrapping iterations used to estimate prediction
          intervals.
      random_state : int, default `123`
          Sets a seed to the random generator, so that boot intervals are always
          deterministic.
      in_sample_residuals : bool, default `True`
          If `True`, residuals from the training data are used as proxy of prediction
          error to create prediction intervals.  If `False`, out_sample_residuals
          are used if they are already stored inside the forecaster.
      n_jobs : int, 'auto', default `'auto'`
          The number of jobs to run in parallel. If `-1`, then the number of jobs is
          set to the number of cores. If 'auto', `n_jobs` is set using the function
          skforecast.utils.select_n_jobs_backtesting.
          **New in version 0.9.0**
      verbose : bool, default `False`
          Print number of folds and index of training and validation sets used
          for backtesting.
      show_progress: bool, default `True`
          Whether to show a progress bar.
  
      Returns
      -------
      metrics_value : float, list
          Value(s) of the metric(s).
      backtest_predictions : pandas DataFrame
          Value of predictions and their estimated interval if `interval` is not `None`.
  
          - column pred: predictions.
          - column lower_bound: lower bound of the interval.
          - column upper_bound: upper bound of the interval.
  
      """
  
      forecaters_allowed = [
          "ForecasterAutoreg",
          "ForecasterAutoregCustom",
          "ForecasterAutoregDirect",
          "ForecasterEquivalentDate",
      ]
  
      if type(forecaster).__name__ not in forecaters_allowed:
          raise TypeError(
              (
                  f"`forecaster` must be of type {forecaters_allowed}, for all other types of "
                  f" forecasters use the functions available in the other `model_selection` "
                  f"modules."
              )
          )
  
      check_backtesting_input(
          forecaster=forecaster,
          steps=steps,
          metric=metric,
          y=y,
          initial_train_size=initial_train_size,
          fixed_train_size=fixed_train_size,
          gap=gap,
          allow_incomplete_fold=allow_incomplete_fold,
          refit=refit,
          interval=interval,
          n_boot=n_boot,
          random_state=random_state,
          in_sample_residuals=in_sample_residuals,
          n_jobs=n_jobs,
          verbose=verbose,
          show_progress=show_progress,
      )
  
      if (
          type(forecaster).__name__ == "ForecasterAutoregDirect"
          and forecaster.steps < steps + gap
      ):
          raise ValueError(
              (
                  "When using a ForecasterAutoregDirect, the combination of steps "
                  f"+ gap ({steps+gap}) cannot be greater than the `steps` parameter "
                  f"declared when the forecaster is initialized ({forecaster.steps})."
              )
          )
  
      metrics_values, backtest_predictions = _backtesting_forecaster(
          forecaster=forecaster,
          y=y,
          steps=steps,
          metric=metric,
          initial_train_size=initial_train_size,
          fixed_train_size=fixed_train_size,
          gap=gap,
          allow_incomplete_fold=allow_incomplete_fold,
          exog=exog,
          refit=refit,
          interval=interval,
          n_boot=n_boot,
          random_state=random_state,
          in_sample_residuals=in_sample_residuals,
          n_jobs=n_jobs,
          verbose=verbose,
          show_progress=show_progress,
      )
  
      return metrics_values, backtest_predictions
  
imports: from typing import Union, Tuple, Optional, Callable
  import numpy
  import pandas
  import warnings
  import logging
  from copy import deepcopy
  from joblib import Parallel, delayed, cpu_count
  from tqdm.auto import tqdm
  from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_absolute_percentage_error, mean_squared_log_error
  from sklearn.model_selection import ParameterGrid
  from sklearn.model_selection import ParameterSampler
  import optuna
  from optuna.samplers import TPESampler, RandomSampler
  from ..exceptions import LongTrainingWarning
  from ..utils import check_backtesting_input
  from ..utils import initialize_lags_grid
  from ..utils import select_n_jobs_backtesting
label_desc: Use image node_id 4 for calling a global function with example usage: backtesting_forecaster(forecaster, y, steps, metric, initial_train_size, fixed_train_size, gap, allow_incomplete_fold, exog, refit, interval, n_boot, random_state, in_sample_residuals, n_jobs, verbose, show_progress) and returns: metrics_values,  backtest_predictions