docs: def create_pyfolio_input(factor_data,
                           period,
                           capital=None,
                           long_short=True,
                           group_neutral=False,
                           equal_weight=False,
                           quantiles=None,
                           groups=None,
                           benchmark_period='1D'):
      """
      Simulate a portfolio using the input factor and returns the portfolio
      performance data properly formatted for Pyfolio analysis.
  
      For more details on how this portfolio is built see:
      - performance.cumulative_returns (how the portfolio returns are computed)
      - performance.factor_weights (how assets weights are computed)
  
      Parameters
      ----------
      factor_data : pd.DataFrame - MultiIndex
          A MultiIndex DataFrame indexed by date (level 0) and asset (level 1),
          containing the values for a single alpha factor, forward returns for
          each period, the factor quantile/bin that factor value belongs to,
          and (optionally) the group the asset belongs to.
          - See full explanation in utils.get_clean_factor_and_forward_returns
      period : string
          'factor_data' column name corresponding to the 'period' returns to be
          used in the computation of porfolio returns
      capital : float, optional
          If set, then compute 'positions' in dollar amount instead of percentage
      long_short : bool, optional
          if True enforce a dollar neutral long-short portfolio: asset weights
          will be computed by demeaning factor values and dividing by the sum of
          their absolute value (achieving gross leverage of 1) which will cause
          the portfolio to hold both long and short positions and the total
          weights of both long and short positions will be equal.
          If False the portfolio weights will be computed dividing the factor
          values and  by the sum of their absolute value (achieving gross
          leverage of 1). Positive factor values will generate long positions and
          negative factor values will produce short positions so that a factor
          with only posive values will result in a long only portfolio.
      group_neutral : bool, optional
          If True simulates a group neutral portfolio: the portfolio weights
          will be computed so that each group will weigh the same.
          if 'long_short' is enabled the factor values demeaning will occur on
          the group level resulting in a dollar neutral, group neutral,
          long-short portfolio.
          If False group information will not be used in weights computation.
      equal_weight : bool, optional
          if True the assets will be equal-weighted. If long_short is True then
          the factor universe will be split in two equal sized groups with the
          top assets in long positions and bottom assets in short positions.
          if False the assets will be factor-weighed, see 'long_short' argument
      quantiles: sequence[int], optional
          Use only specific quantiles in the computation. By default all
          quantiles are used
      groups: sequence[string], optional
          Use only specific groups in the computation. By default all groups
          are used
      benchmark_period : string, optional
          By default benchmark returns are computed as the factor universe mean
          daily returns but 'benchmark_period' allows to choose a 'factor_data'
          column corresponding to the returns to be used in the computation of
          benchmark returns. More generally benchmark returns are computed as the
          factor universe returns traded at 'benchmark_period' frequency, equal
          weighting and long only
  
  
      Returns
      -------
       returns : pd.Series
          Daily returns of the strategy, noncumulative.
           - Time series with decimal returns.
           - Example:
              2015-07-16    -0.012143
              2015-07-17    0.045350
              2015-07-20    0.030957
              2015-07-21    0.004902
  
       positions : pd.DataFrame
          Time series of dollar amount (or percentage when 'capital' is not
          provided) invested in each position and cash.
           - Days where stocks are not held can be represented by 0.
           - Non-working capital is labelled 'cash'
           - Example:
              index         'AAPL'         'MSFT'          cash
              2004-01-09    13939.3800     -14012.9930     711.5585
              2004-01-12    14492.6300     -14624.8700     27.1821
              2004-01-13    -13853.2800    13653.6400      -43.6375
  
  
       benchmark : pd.Series
          Benchmark returns computed as the factor universe mean daily returns.
  
      """
  
      #
      # Build returns:
      # we don't know the frequency at which the factor returns are computed but
      # pyfolio wants daily returns. So we compute the cumulative returns of the
      # factor, then resample it at 1 day frequency and finally compute daily
      # returns
      #
      cumrets = factor_cumulative_returns(factor_data,
                                          period,
                                          long_short,
                                          group_neutral,
                                          equal_weight,
                                          quantiles,
                                          groups)
      cumrets = cumrets.resample('1D').last().fillna(method='ffill')
      returns = cumrets.pct_change().fillna(0)
  
      #
      # Build positions. As pyfolio asks for daily position we have to resample
      # the positions returned by 'factor_positions' at 1 day frequency and
      # recompute the weights so that the sum of daily weights is 1.0
      #
      positions = factor_positions(factor_data,
                                   period,
                                   long_short,
                                   group_neutral,
                                   equal_weight,
                                   quantiles,
                                   groups)
      positions = positions.resample('1D').sum().fillna(method='ffill')
      positions = positions.div(positions.abs().sum(axis=1), axis=0).fillna(0)
      positions['cash'] = 1. - positions.sum(axis=1)
  
      # transform percentage positions to dollar positions
      if capital is not None:
          positions = positions.mul(
              cumrets.reindex(positions.index) * capital, axis=0)
  
      #
      #
      #
      # Build benchmark returns as the factor universe mean returns traded at
      # 'benchmark_period' frequency
      #
      fwd_ret_cols = utils.get_forward_returns_columns(factor_data.columns)
      if benchmark_period in fwd_ret_cols:
          benchmark_data = factor_data.copy()
          # make sure no negative positions
          benchmark_data['factor'] = benchmark_data['factor'].abs()
          benchmark_rets = factor_cumulative_returns(benchmark_data,
                                                     benchmark_period,
                                                     long_short=False,
                                                     group_neutral=False,
                                                     equal_weight=True)
          benchmark_rets = benchmark_rets.resample(
              '1D').last().fillna(method='ffill')
          benchmark_rets = benchmark_rets.pct_change().fillna(0)
          benchmark_rets.name = 'benchmark'
      else:
          benchmark_rets = None
  
      return returns, positions, benchmark_rets