Exemplo n.º 1
0
    def _get_forecast_scalar_fixed(self, instrument_code, rule_variation_name):
        """
        Get the scalar to apply to raw forecasts

        In this simple version it's the same for all instruments, and fixed

        We get the scalars from: (a) configuration file in parent system
                                 (b) or if missing: uses the scalar from systems.defaults.py

        :param instrument_code:
        :type str:

        :param rule_variation_name:
        :type str: name of the trading rule variation

        :returns: float

        >>> from systems.tests.testdata import get_test_object_futures_with_rules
        >>> from systems.basesystem import System
        >>> (rules, rawdata, data, config)=get_test_object_futures_with_rules()
        >>> system1=System([rawdata, rules, ForecastScaleCapFixed()], data, config)
        >>>
        >>> ## From config
        >>> system1.forecastScaleCap.get_forecast_scalar("EDOLLAR", "ewmac8")
        5.3
        >>>
        >>> ## default
        >>> unused=config.trading_rules['ewmac8'].pop('forecast_scalar')
        >>> system3=System([rawdata, rules, ForecastScaleCapFixed()], data, config)
        >>> system3.forecastScaleCap.get_forecast_scalar("EDOLLAR", "ewmac8")
        1.0
        >>>
        >>> ## other config location
        >>> setattr(config, 'forecast_scalars', dict(ewmac8=11.0))
        >>> system4=System([rawdata, rules, ForecastScaleCapFixed()], data, config)
        >>> system4.forecastScaleCap.get_forecast_scalar("EDOLLAR", "ewmac8")
        11.0
        """

        system = self.parent
        try:
            scalar = system.config.trading_rules[rule_variation_name][
                'forecast_scalar']
        except:
            try:
                # can also put somewhere else ...
                scalar = system.config.forecast_scalars[rule_variation_name]
            except:
                # go with defaults
                scalar = get_default_config_key_value('forecast_scalar')

        return scalar
Exemplo n.º 2
0
def get_private_then_default_key_value(key_name,
                                       system_defaults_dict=arg_not_supplied,
                                       private_config_dict=arg_not_supplied,
                                       raise_error=True):

    key_value = get_private_config_key_value(
        key_name, private_config_dict=private_config_dict)
    if key_value is missing_data:
        key_value = get_default_config_key_value(
            key_name, system_defaults_dict=system_defaults_dict)

    if key_value is missing_data and raise_error:
        raise KeyError(
            "Can't find key %s in private %s or default %s config .yaml files"
            % (key_value, PRIVATE_CONFIG_FILE, DEFAULT_FILENAME))

    return key_value
Exemplo n.º 3
0
def forecast_scalar(cs_forecasts,
                    window=250000,
                    min_periods=500,
                    backfill=True):
    """
    Work out the scaling factor for xcross such that T*x has an abs value of 10 (or whatever the average absolute forecast is)

    :param cs_forecasts: forecasts, cross sectionally
    :type cs_forecasts: pd.DataFrame TxN

    :param span:
    :type span: int

    :param min_periods:


    :returns: pd.DataFrame
    """
    backfill = str2Bool(backfill)  # in yaml will come in as text
    # We don't allow this to be changed in config
    target_abs_forecast = get_default_config_key_value(
        "average_absolute_forecast")
    if target_abs_forecast is missing_data:
        raise Exception(
            "average_absolute_forecast not defined in system defaults file")

    # Remove zeros/nans
    copy_cs_forecasts = copy(cs_forecasts)
    copy_cs_forecasts[copy_cs_forecasts == 0.0] = np.nan

    # Take CS average first
    # we do this before we get the final TS average otherwise get jumps in
    # scalar when new markets introduced
    if copy_cs_forecasts.shape[1] == 1:
        x = copy_cs_forecasts.abs().iloc[:, 0]
    else:
        x = copy_cs_forecasts.ffill().abs().median(axis=1)

    # now the TS
    avg_abs_value = x.rolling(window=window, min_periods=min_periods).mean()
    scaling_factor = target_abs_forecast / avg_abs_value

    if backfill:
        scaling_factor = scaling_factor.fillna(method="bfill")

    return scaling_factor
Exemplo n.º 4
0
    def get_subsystem_position(self, instrument_code):
        """
        Get scaled position (assuming for now we trade our entire capital for one instrument)

        KEY OUTPUT

        :param instrument_code: instrument to get values for
        :type instrument_code: str

        :returns: Tx1 pd.DataFrame

        >>> from systems.tests.testdata import get_test_object_futures_with_comb_forecasts
        >>> from systems.basesystem import System
        >>> (comb, fcs, rules, rawdata, data, config)=get_test_object_futures_with_comb_forecasts()
        >>> system=System([rawdata, rules, fcs, comb, PositionSizing()], data, config)
        >>>
        >>> system.positionSize.get_subsystem_position("EDOLLAR").tail(2)
                    ss_position
        2015-12-10     1.811465
        2015-12-11     2.544598
        >>>
        >>> system2=System([rawdata, rules, fcs, comb, PositionSizing()], data, config)
        >>> system2.positionSize.get_subsystem_position("EDOLLAR").tail(2)
                    ss_position
        2015-12-10     1.811465
        2015-12-11     2.544598

        """
        self.log.msg(
            "Calculating subsystem position for %s" % instrument_code,
            instrument_code=instrument_code,
        )
        """
        We don't allow this to be changed in config
        """
        avg_abs_forecast = get_default_config_key_value(
            "average_absolute_forecast")

        vol_scalar = self.get_volatility_scalar(instrument_code)
        forecast = self.get_combined_forecast(instrument_code)

        vol_scalar = vol_scalar.reindex(forecast.index).ffill()

        subsystem_position = vol_scalar * forecast / avg_abs_forecast

        return subsystem_position
Exemplo n.º 5
0
    def forecast_turnover_for_list(self, instrument_code_list,
                                   rule_variation_name):
        """
        Get the average turnover for a rule, over instrument_code_list

        :param instrument_code_list: instruments to get values for
        :type instrument_code_list: list of str

        :param rule_variation_name: rule to get values for
        :type rule_variation_name: str

        :returns: float

        """

        average_forecast_for_turnover = get_default_config_key_value(
            'average_absolute_forecast')

        forecast_list = [
            self.get_capped_forecast(instrument_code, rule_variation_name)
            for instrument_code in instrument_code_list
        ]

        turnovers = [
            turnover(forecast, average_forecast_for_turnover)
            for forecast in forecast_list
        ]

        if len(instrument_code_list) == 1:
            return turnovers[0]

        # weight by length
        forecast_lengths = [len(forecast.index) for forecast in forecast_list]
        total_length = sum(forecast_lengths)
        weighted_turnovers = [
            tover * fc_length / total_length
            for (tover, fc_length) in zip(turnovers, forecast_lengths)
        ]

        avg_turnover = sum(weighted_turnovers)

        return avg_turnover
Exemplo n.º 6
0
    def get_forecast_diversification_multiplier_fixed(self, instrument_code):
        """

        Get the diversification multiplier for this instrument

        From: system.config.instrument_weights

        :param instrument_code: instrument to get multiplier for
        :type instrument_code: str

        :returns: Tx1 pd.DataFrame


        >>> from systems.tests.testdata import get_test_object_futures_with_rules_and_capping
        >>> from systems.basesystem import System
        >>> (fcs, rules, rawdata, data, config)=get_test_object_futures_with_rules_and_capping()
        >>> system=System([rawdata, rules, fcs, ForecastCombineFixed()], data, config)
        >>>
        >>> ## from config
        >>> system.combForecast.get_forecast_diversification_multiplier("EDOLLAR").tail(2)
                    fdm
        2015-12-10  1.1
        2015-12-11  1.1
        >>>
        >>> config.forecast_div_multiplier=dict(EDOLLAR=2.0)
        >>> system2=System([rawdata, rules, fcs, ForecastCombineFixed()], data, config)
        >>> system2.combForecast.get_forecast_diversification_multiplier("EDOLLAR").tail(2)
                    fdm
        2015-12-10    2
        2015-12-11    2
        >>>
        >>> ## defaults
        >>> del(config.forecast_div_multiplier)
        >>> system3=System([rawdata, rules, fcs, ForecastCombineFixed()], data, config)
        >>> system3.combForecast.get_forecast_diversification_multiplier("EDOLLAR").tail(2)
                    fdm
        2015-12-10    1
        2015-12-11    1
        """
        system = self.parent
        self.log.msg("Calculating diversification multiplier for %s" %
                     (instrument_code),
                     instrument_code=instrument_code)

        # Let's try the config
        if hasattr(system.config, "forecast_div_multiplier"):
            if isinstance(system.config.forecast_div_multiplier, float):
                fixed_div_mult = system.config.forecast_div_multiplier

            elif instrument_code in system.config.forecast_div_multiplier.keys(
            ):
                # dict
                fixed_div_mult = system.config.forecast_div_multiplier[
                    instrument_code]
            else:
                error_msg = "FDM in config needs to be either float, or dict with instrument_code keys"
                self.log.critical(error_msg, instrument_code=instrument_code)

        else:
            # try defaults
            fixed_div_mult = get_default_config_key_value(
                "forecast_div_multiplier")
            if fixed_div_mult is missing_data:
                error_msg = "Need to specify FDM in config or system_defaults"
                self.log.critical(error_msg, instrument_code=instrument_code)

        # Now we have a dict, fixed_weights.
        # Need to turn into a timeseries covering the range of forecast dates
        # get forecast weights first
        forecast_weights = self.get_forecast_weights(instrument_code)
        weight_ts = forecast_weights.index

        ts_fdm = pd.Series([fixed_div_mult] * len(weight_ts), index=weight_ts)

        return ts_fdm