code: def forward_stability_curve_time_splitter(
      train_data: pd.DataFrame,
      training_time_start: DateType,
      training_time_end: DateType,
      time_column: str,
      holdout_gap: timedelta = timedelta(days=0),
      holdout_size: timedelta = timedelta(days=90),
      step: timedelta = timedelta(days=90),
      move_training_start_with_steps: bool = True,
  ) -> SplitterReturnType:
      """
      Splits the data into temporal buckets with both the training and testing folds both moving forward.
      The folds move forward by a fixed timedelta step.
      Optionally, there can be a gap between the end of the training period and the start of the holdout period.
  
      Similar to the stability curve time splitter, with the difference that the training period also
      moves forward with each fold.
  
      The clearest use case is to evaluate a periodic re-training framework.
  
      Parameters
      ----------
      train_data : pandas.DataFrame
          A Pandas' DataFrame that will be split for stability curve estimation.
  
      training_time_start: datetime.datetime or str
          Date for the start of the training period.
          If `move_training_start_with_steps` is `True`, each step will increase this date by `step`.
  
      training_time_end: datetime.datetime or str
          Date for the end of the training period.
          Each step increases this date by `step`.
  
      time_column : str
          The name of the Date column of `train_data`.
  
      holdout_gap: datetime.timedelta
          Timedelta of the gap between the end of the training period and the start of the validation period.
  
      holdout_size: datetime.timedelta
          Timedelta of the range between the start and the end of the holdout period.
  
      step: datetime.timedelta
          Timedelta that shifts both the training period and the holdout period by this value.
  
      move_training_start_with_steps: bool
          If True, the training start date will increase by `step` for each fold.
          If False, the training start date remains fixed at the `training_time_start` value.
      """
  
      if isinstance(training_time_start, str):
          training_time_start = datetime.strptime(
              training_time_start, "%Y-%m-%d"
          )
  
      if isinstance(training_time_end, str):
          training_time_end = datetime.strptime(
              training_time_end, "%Y-%m-%d"
          )
  
      train_data = train_data.reset_index()
  
      max_date = train_data[time_column].max()
  
      if not (
          train_data[time_column].min()
          <= training_time_start
          < training_time_end
          <= max_date
      ):
          raise ValueError(
              "Temporal training limits should be within datasets temporal bounds (min and max times)"
          )
      if timedelta(days=0) > holdout_gap:
          raise ValueError("Holdout gap cannot be negative")
      if timedelta(days=0) > holdout_size:
          raise ValueError("Holdout size cannot be negative")
  
      n_folds = int(
          np.ceil(
              (
                  max_date
                  - holdout_size
                  - holdout_gap
                  - training_time_end
              )
              / step
          )
      )
  
      if n_folds <= 0:
          raise ValueError(
              "After taking the gap and holdout into account, there should be enough time for the holdout set"
          )
  
      train_ranges = [
          (
              training_time_start
              + i * step * move_training_start_with_steps,
              training_time_end + i * step,
          )
          for i in range(n_folds)
      ]
  
      test_ranges = [
          (
              training_time_end + holdout_gap + i * step,
              training_time_end + holdout_gap + holdout_size + i * step,
          )
          for i in range(n_folds)
      ]
  
      train_idx = [
          train_data[
              (train_data[time_column] >= start)
              & (train_data[time_column] < end)
          ].index
          for start, end in train_ranges
      ]
      test_idx = [
          [
              train_data[
                  (train_data[time_column] >= start)
                  & (train_data[time_column] < end)
              ].index
          ]
          for start, end in test_ranges
      ]
  
      logs = [
          _log_time_fold(
              (
                  train_data.iloc[i][time_column],
                  train_data.iloc[j[0]][time_column],
              )
          )
          for i, j in zip(train_idx, test_idx)
      ]
  
      return list(zip(train_idx, test_idx)), logs
  
imports: import operator
  from datetime import datetime, timedelta
  from itertools import chain, repeat, starmap
  from typing import Callable, Iterable, List, Tuple, Union
  import numpy
  import pandas
  from sklearn.model_selection import GroupKFold, KFold, StratifiedKFold
  from sklearn.utils import check_random_state
  from toolz.curried import curry, partial, pipe, assoc, accumulate, map, filter
  from fklearn.common_docstrings import splitter_return_docstring
  from fklearn.types import DateType, LogType, SplitterReturnType
label_desc: Use image node_id 15 for calling a global function with example usage: forward_stability_curve_time_splitter(train_data, training_time_start, training_time_end, time_column, holdout_gap, holdout_size, step, move_training_start_with_steps) and returns: list,  logs