docs: def exp_cov(prices, span=180, frequency=252):
      """
      Estimate the exponentially-weighted covariance matrix, which gives
      greater weight to more recent data.
  
      :param prices: adjusted closing prices of the asset, each row is a date
                     and each column is a ticker/id.
      :type prices: pd.DataFrame
      :param span: the span of the exponential weighting function, defaults to 180
      :type span: int, optional
      :param frequency: number of time periods in a year, defaults to 252 (the number
                        of trading days in a year)
      :type frequency: int, optional
      :return: annualised estimate of exponential covariance matrix
      :rtype: pd.DataFrame
      """
      if not isinstance(prices, pd.DataFrame):
          warnings.warn("prices are not in a dataframe", RuntimeWarning)
          prices = pd.DataFrame(prices)
      assets = prices.columns
      daily_returns = daily_price_returns(prices)
      N = len(assets)
  
      # Loop over matrix, filling entries with the pairwise exp cov
      S = np.zeros((N, N))
      for i in range(N):
          for j in range(i, N):
              S[i, j] = S[j, i] = _pair_exp_cov(
                  daily_returns.iloc[:, i], daily_returns.iloc[:, j], span
              )
      return pd.DataFrame(S * frequency, columns=assets, index=assets)