docs: def calc_trades(current_contracts, desired_holdings, trade_weights, prices,
                  multipliers, **kwargs):
      """
      Calculate the number of tradeable contracts for rebalancing from a set
      of current contract holdings to a set of desired generic notional holdings
      based on prevailing prices and mapping from generics to tradeable
      instruments. Differences between current holdings and desired holdings
      are treated as 0. Zero trades are dropped.
  
      Parameters
      ----------
      current_contracts: pandas.Series
          Series of current number of contracts held for tradeable instruments.
          Can pass 0 if all holdings are 0.
      desired_holdings: pandas.Series
          Series of desired holdings in base notional currency of generics. Index
          is generic contracts, these should be the same generics as in
          trade_weights.
      trade_weights: pandas.DataFrame or dict
          A pandas.DataFrame of loadings of generic contracts on tradeable
          instruments **for a given date**. The columns refer to generic
          contracts and the index is strings representing instrument names.
          If dict is given keys should be root generic names, e.g. 'CL', and
          values should be pandas.DataFrames of loadings. The union of all
          columns should be a superset of the desired_holdings.index
      prices: pandas.Series
          Series of instrument prices. Index is instrument name and values are
          number of contracts. Extra instrument prices will be ignored.
      multipliers: pandas.Series
          Series of instrument multipliers. Index is instrument name and
          values are the multiplier associated with the contract.
          multipliers.index should be a superset of mapped desired_holdings
          intruments.
      kwargs: key word arguments
          Key word arguments to be passed to to_contracts()
  
      Returns
      -------
      A pandas.Series of instrument contract trades, lexigraphically sorted.
  
      Example
      -------
      >>> import pandas as pd
      >>> import mapping.util as util
      >>> wts = pd.DataFrame([[0.5, 0], [0.5, 0.5], [0, 0.5]],
      ...                    index=["CLX16", "CLZ16", "CLF17"],
      ...                    columns=["CL1", "CL2"])
      >>> desired_holdings = pd.Series([200000, -50000], index=["CL1", "CL2"])
      >>> current_contracts = pd.Series([0, 1, 0],
      ...                               index=['CLX16', 'CLZ16', 'CLF17'])
      >>> prices = pd.Series([50.32, 50.41, 50.48],
      ...                    index=['CLX16', 'CLZ16', 'CLF17'])
      >>> multipliers = pd.Series([100, 100, 100],
      ...                        index=['CLX16', 'CLZ16', 'CLF17'])
      >>> trades = util.calc_trades(current_contracts, desired_holdings, wts,
      ...                           prices, multipliers)
      """
      if not isinstance(trade_weights, dict):
          trade_weights = {"": trade_weights}
  
      generics = []
      for key in trade_weights:
          generics.extend(trade_weights[key].columns)
  
      if not set(desired_holdings.index).issubset(set(generics)):
          raise ValueError("'desired_holdings.index' contains values which "
                           "cannot be mapped to tradeables.\n"
                           "Received: 'desired_holdings.index'\n {0}\n"
                           "Expected in 'trade_weights' set of columns:\n {1}\n"
                           .format(sorted(desired_holdings.index),
                                   sorted(generics)))
  
      desired_contracts = []
      for root_key in trade_weights:
          gnrc_weights = trade_weights[root_key]
  
          subset = gnrc_weights.columns.intersection(desired_holdings.index)
          gnrc_des_hlds = desired_holdings.loc[subset]
          gnrc_weights = gnrc_weights.loc[:, subset]
          # drop indexes where all non zero weights were in columns dropped above
          gnrc_weights = gnrc_weights.loc[~(gnrc_weights == 0).all(axis=1)]
  
          instr_des_hlds = gnrc_des_hlds * gnrc_weights
          instr_des_hlds = instr_des_hlds.sum(axis=1)
          wprices = prices.loc[instr_des_hlds.index]
          desired_contracts.append(to_contracts(instr_des_hlds, wprices,
                                                multipliers, **kwargs))
  
      desired_contracts = pd.concat(desired_contracts, axis=0)
  
      trades = desired_contracts.subtract(current_contracts, fill_value=0)
      trades = trades.loc[trades != 0]
      trades = trades.sort_index()
      return trades