code: def _create_backtesting_folds(
      data: Union[pd.Series, pd.DataFrame],
      window_size: int,
      initial_train_size: Union[int, None],
      test_size: int,
      externally_fitted: bool = False,
      refit: Optional[Union[bool, int]] = False,
      fixed_train_size: bool = True,
      gap: int = 0,
      allow_incomplete_fold: bool = True,
      return_all_indexes: bool = False,
      differentiation: Optional[int] = None,
      verbose: bool = True,
  ) -> list:
      """
      This function is designed to work after passing the `check_backtesting_input`
      function from `skforecast.utils`.
  
      Provides train/test indices (position) to split time series data samples that
      are observed at fixed time intervals, in train/test sets. In each split, test
      indices must be higher than before.
  
      Four arrays are returned for each fold with the position of train, window size,
      test including the gap, and test excluding the gap. The gap is the number of
      samples to exclude from the end of each train set before the test set. The
      test excluding the gap is the one that must be used to make evaluate the
      model. The test including the gap is provided for convenience.
  
      Returned indexes are not the indexes of the original time series, but the
      positional indexes of the samples in the time series. For example, if the
      original time series is `y = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]`, the
      returned indexes for the first fold if  `test_size = 4`, `gap = 1` and
      `initial_train_size = 2` with `window_size = 2` are: `[[0, 1], [0, 1],
      [2, 3, 4, 5], [3, 4, 5]]]`. This means that the first fold is using the samples
      with positional indexes 0 and 1 in the time series as training set, the samples
      with positional indexes 0 and 1 as last window, and the samples with positional
      indexes 2, 3, 4 and 5 as test set, but only the samples with positional indexes
      3, 4 and 5 should be used to evaluate the model since `gap = 1`. The second fold
      would be `[[0, 1, 2, 3], [2, 3], [4, 5, 6, 7], [5, 6, 7]]`, and so on.
  
      Each fold also provides information on whether the Forecaster needs to be
      trained, `True` or `False`. The first fold flag will be always `False` since
      the first fit is done inside _backtesting_forecaster function.
  
      Parameters
      ----------
      data : pandas Series, pandas DataFrame
          Time series values.
      window_size : int
          Size of the window needed to create the predictors.
      initial_train_size : int, None
          Size of the training set in the first fold. If `None` or 0, the initial
          fold does not include a training set.
      test_size : int
          Size of the test set in each fold.
      externally_fitted : bool, default `False`
          Flag indicating whether the forecaster is already trained. Only used when
          `initial_train_size` is None and `refit` is False.
      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.
      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.
      return_all_indexes : bool, default `False`
          If `True`, return all the indexes included in each fold. If `False`, return
          only the first and last index of each partition in each fold.
      differentiation : int, default `None`
          Order of differencing applied to the time series before training the forecaster.
      verbose : bool, default `True`
          Print information if the folds created.
  
      Returns
      -------
      folds : list
          List containing the `y` indices (position) for training, last window, test
          including the gap and test excluding the gap for each fold, and whether to
          fit the Forecaster.
  
      """
  
      idx = range(len(data))
      folds = []
      i = 0
      last_fold_excluded = False
  
      while initial_train_size + (i * test_size) + gap < len(data):
          if refit:
              # If `fixed_train_size` the train size doesn't increase but moves by
              # `test_size` positions in each iteration. If `False`, the train size
              # increases by `test_size` in each iteration.
              train_idx_start = (
                  i * (test_size) if fixed_train_size else 0
              )
              train_idx_end = initial_train_size + i * (test_size)
              test_idx_start = train_idx_end
          else:
              # The train size doesn't increase and doesn't move.
              train_idx_start = 0
              train_idx_end = initial_train_size
              test_idx_start = initial_train_size + i * (test_size)
  
          last_window_start = test_idx_start - window_size
          test_idx_end = test_idx_start + gap + test_size
  
          partitions = [
              idx[train_idx_start:train_idx_end],
              idx[last_window_start:test_idx_start],
              idx[test_idx_start:test_idx_end],
              idx[test_idx_start + gap : test_idx_end],
          ]
          folds.append(partitions)
          i += 1
  
      if not allow_incomplete_fold:
          if len(folds[-1][3]) < test_size:
              folds = folds[:-1]
              last_fold_excluded = True
  
      # Replace partitions inside folds with length 0 with `None`
      folds = [
          [
              partition if len(partition) > 0 else None
              for partition in fold
          ]
          for fold in folds
      ]
  
      # Create a flag to know whether to train the forecaster
      if refit == 0:
          refit = False
  
      if isinstance(refit, bool):
          fit_forecaster = [refit] * len(folds)
          fit_forecaster[0] = True
      else:
          fit_forecaster = [False] * len(folds)
          for i in range(0, len(fit_forecaster), refit):
              fit_forecaster[i] = True
  
      for i in range(len(folds)):
          folds[i].append(fit_forecaster[i])
          if fit_forecaster[i] is False:
              folds[i][0] = folds[i - 1][0]
  
      # This is done to allow parallelization when `refit` is `False`. The initial
      # Forecaster fit is outside the auxiliary function.
      folds[0][4] = False
  
      if verbose:
          print("Information of backtesting process")
          print("----------------------------------")
          if externally_fitted:
              print(
                  f"An already trained forecaster is to be used. Window size: {window_size}"
              )
          else:
              if differentiation is None:
                  print(
                      f"Number of observations used for initial training: {initial_train_size}"
                  )
              else:
                  print(
                      f"Number of observations used for initial training: {initial_train_size - differentiation}"
                  )
                  print(
                      f"    First {differentiation} observation/s in training sets are used for differentiation"
                  )
          print(
              f"Number of observations used for backtesting: {len(data) - initial_train_size}"
          )
          print(f"    Number of folds: {len(folds)}")
          print(f"    Number of steps per fold: {test_size}")
          print(
              f"    Number of steps to exclude from the end of each train set before test (gap): {gap}"
          )
          if last_fold_excluded:
              print(
                  "    Last fold has been excluded because it was incomplete."
              )
          if len(folds[-1][3]) < test_size:
              print(
                  f"    Last fold only includes {len(folds[-1][3])} observations."
              )
          print("")
  
          if differentiation is None:
              differentiation = 0
          for i, fold in enumerate(folds):
              training_start = (
                  data.index[fold[0][0] + differentiation]
                  if fold[0] is not None
                  else None
              )
              training_end = (
                  data.index[fold[0][-1]]
                  if fold[0] is not None
                  else None
              )
              training_length = (
                  len(fold[0]) - differentiation
                  if fold[0] is not None
                  else 0
              )
              validation_start = data.index[fold[3][0]]
              validation_end = data.index[fold[3][-1]]
              validation_length = len(fold[3])
  
              print(f"Fold: {i}")
              if not externally_fitted:
                  print(
                      f"    Training:   {training_start} -- {training_end}  (n={training_length})"
                  )
              print(
                  f"    Validation: {validation_start} -- {validation_end}  (n={validation_length})"
              )
          print("")
  
      if not return_all_indexes:
          # +1 to prevent iloc pandas from deleting the last observation
          folds = [
              [
                  [fold[0][0], fold[0][-1] + 1],
                  [fold[1][0], fold[1][-1] + 1],
                  [fold[2][0], fold[2][-1] + 1],
                  [fold[3][0], fold[3][-1] + 1],
                  fold[4],
              ]
              for fold in folds
          ]
  
      return folds
  
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 1 for calling a global function with example usage: _create_backtesting_folds(data, window_size, initial_train_size, test_size, externally_fitted, refit, fixed_train_size, gap, allow_incomplete_fold, return_all_indexes, differentiation, verbose) and returns: folds