Source code for macrosynergy.panel.cross_asset_effects

from typing import List, Optional, Dict

from pandas import DataFrame

from macrosynergy.management.types import QuantamentalDataFrame
from macrosynergy.panel import panel_calculator


[docs]def cross_asset_effects( df: QuantamentalDataFrame, cids: List[str], effect_name: str, signal_xcats: Dict[str, str], weights_xcats: Dict[str, str], signal_signs: Optional[Dict[str, int]] = None, ) -> DataFrame: """ Linear combination of a set of categories with corresponding weights and, optionally, signs. Corresponding assets' volatilities are generally used as weights. Parameters ---------- df : str QuantamentalDataFrame with time-series of categories for both values and weights for all cross-sections. cids : List[str] List of cross-sections to compute the new quantamental category for. effect_name : str Name of the new quantamental xcat. signal_xcats : Dict[str, str] Dictionary of asset class names and related signals' time-series specified as xcats, part of df. weights_xcats : Dict[str, str] Dictionary of asset class names and related weights' time-series specified as xcats, part of df. signal_signs : Dict[str, int], optional Dictionary of asset class names and related signs in form of +1 / -1. Default is None, hence we assume all components contribute positively and proportionately to the final average Returns ------- pd.DataFrame """ assert isinstance(signal_xcats, dict), "Please provide a dictionary for assets' xcats" assert isinstance(weights_xcats, dict), "Please provide a dictionary for assets' weights" assert signal_signs is None or isinstance(signal_signs, dict), "Please provide a dictionary for assets' signs if needed." assert set(signal_xcats.keys()) == set( weights_xcats.keys()), "The keys of provided dictionaries for xcats and weights do not match." assert len(signal_xcats) == len( weights_xcats), "The size of provided dictionaries for xcats and weights do not match." if signal_signs is not None: assert set(signal_xcats.keys()) == set( signal_signs.keys()), "The keys of provided dictionaries for xcats and signs do not match." assert len(signal_xcats) == len( signal_signs), "The size of provided dictionaries for xcats and signs do not match." else: signal_signs = { k: 1 for k, v in signal_xcats.items() } weighted_parts_calc = [ f"( {k.upper()}_SHARE ) * ( {str(signal_signs.get(k))} ) * {v}" for k, v in signal_xcats.items() ] calcs = [ # Computing the total weight assigned across xcat elements f"WSUM = {' + '.join(weights_xcats.values())}" ] + [ # Computing each category's share f"{k.upper()}_SHARE = {v} / WSUM" for k, v in weights_xcats.items() ] + [ # Computing the final indicator as weighted average f"{effect_name} = {' + '.join(weighted_parts_calc)}" ] return panel_calculator(df, calcs=calcs, cids=cids)