Ejemplo n.º 1
0
def cumulative_returns(returns: pd.DataFrame, period, freq=None):
    if not isinstance(period, pd.Timedelta):
        period = pd.Timedelta(period)

    if freq is None:
        freq = returns.index.freq

    if freq is None:
        freq = pd.tseries.offsets.BDay()
        warnings.warn(
            "'freq' not set, using business day calendar",
            UserWarning
        )

    trades_idx = returns.index.copy()
    returns_idx = utils.add_custom_calendar_timedelta(trades_idx, period)
    full_idx = trades_idx.union(returns_idx)

    sub_returns = []
    while len(trades_idx) > 0:
        sub_idx = []
        next = trades_idx.min()
        while next <= trades_idx.max():
            sub_idx.append(next)
            next = utils.add_custom_calendar_timedelta(
                input=next,
                timedelta=period,
            )
            try:
                i = trades_idx.get_loc(next, method="bfill")
                next = trades_idx[i]
            except KeyError:
                break

        sub_idx = pd.DatetimeIndex(sub_idx, tz=full_idx.tz)
        subret = returns[sub_idx]

        subret = subret.reindex(full_idx)

        for pret_idx in reversed(sub_idx):
            pret = subret[pret_idx]
            pret_end_idx = utils.add_custom_calendar_timedelta(pret_idx, period)
            slice = subret[(subret.index > pret_idx)
                           & (subret.index <= pret_end_idx)].index

            if pd.isnull(pret):
                continue

            def rate_of_returns(ret, period):
                return ((np.nansum(ret) + 1)**(1.0 / period)) - 1

            for slice_idx in slice:
                sub_period = utils.diff_custom_calendar_timedeltas(
                    pret_idx,
                    slice_idx,
                    freq
                )
Ejemplo n.º 2
0
def factor_rank_autocorrelation(
        factor_data: pd.DataFrame,
        period: Union[int,
                      str] = 1
):
    grouper = ["datetime"]

    ranks = factor_data.groupby(grouper)["factor"].rank()

    asset_factor_rank = ranks.reset_index().pivot(
        index="datetime",
        columns="code",
        values="factor"
    )

    if isinstance(period, int):
        asset_shifted = asset_factor_rank.shift(period)
    else:
        shifted_idx = utils.add_custom_calendar_timedelta(
            asset_factor_rank.index,
            -pd.Timedelta(period),
        )
        asset_shifted = asset_factor_rank.reindex(shifted_idx)
        asset_shifted.index = asset_factor_rank.index

    autocorr = asset_factor_rank.corrwith(asset_shifted, axis=1)
    autocorr.name = period
    return autocorr
Ejemplo n.º 3
0
def quantile_turnover(
        quantile_factor: pd.DataFrame,
        quantile: int,
        period: Union[int,
                      str] = 1
):
    """
    Computes the proportion of names in a factor quantile that were
    not in that quantile in the previous period.

    Parameters
    ----------
    quantile_factor : pd.Series
        DataFrame with date, asset and factor quantile.
    quantile : int
        Quantile on which to perform turnover analysis.
    period: string or int, optional
        Period over which to calculate the turnover. If it is a string it must
        follow pandas.Timedelta constructor format (e.g. '1 days', '1D', '30m',
        '3h', '1D1h', etc).
    Returns
    -------
    quant_turnover : pd.Series
        Period by period turnover for that quantile.
    """
    quant_names = quantile_factor[quantile_factor == quantile]
    quant_name_sets = quant_names.groupby(
        level=["datetime"]
    ).apply(lambda x: set(x.index.get_level_values("code")))

    if isinstance(period, int):
        name_shifted = quant_name_sets.shift(period)
    else:
        period = utils.get_period(period)
        shifted_idx = utils.add_custom_calendar_timedelta(
            quant_name_sets.index,
            -pd.Timedelta(period)
        )
        name_shifted = quant_name_sets.reindex(shifted_idx)
        name_shifted.index = quant_name_sets.index

    new_names = (quant_name_sets - name_shifted).dropna()
    quant_turnover = new_names.apply(lambda x: len(x)
                                    ) / quant_name_sets.apply(lambda x: len(x))
    quant_turnover.name = quantile
    return quant_turnover