Beispiel #1
0
 def repeat(self, n, as_columns=None):
     repeated = reshape_fns.repeat(self._obj, n, along_axis=1)
     if as_columns is not None:
         new_columns = index_fns.combine(
             reshape_fns.to_2d(self._obj).columns, as_columns)
         return self.wrap_array(repeated.values, columns=new_columns)
     return repeated
Beispiel #2
0
    def concat(self_or_cls, *others, as_columns=None, broadcast_kwargs={}):
        """Concatenate with `others` along columns.

        All arguments will be broadcasted using `vectorbt.utils.reshape_fns.broadcast`
        with `broadcast_kwargs`. Use `as_columns` as a top-level column level.

        Example:
            ```python-repl
            >>> import pandas as pd
            >>> sr = pd.Series([1, 2], index=['x', 'y'])
            >>> df = pd.DataFrame([[3, 4], [5, 6]], index=['x', 'y'], columns=['a', 'b'])

            >>> print(sr.vbt.concat(df, as_columns=['c', 'd']))
                  c     d
               a  b  a  b
            x  1  1  3  4
            y  2  2  5  6
            ```"""
        others = tuple(
            map(lambda x: x._obj
                if isinstance(x, Base_Accessor) else x, others))
        if isinstance(self_or_cls, type):
            objs = others
        else:
            objs = (self_or_cls._obj, ) + others
        broadcasted = reshape_fns.broadcast(*objs, **broadcast_kwargs)
        broadcasted = tuple(map(reshape_fns.to_2d, broadcasted))
        if checks.is_pandas(broadcasted[0]):
            concated = pd.concat(broadcasted, axis=1)
            if as_columns is not None:
                concated.columns = index_fns.combine(as_columns,
                                                     broadcasted[0].columns)
        else:
            concated = np.hstack(broadcasted)
        return concated
Beispiel #3
0
 def apply_and_concat(self,
                      ntimes,
                      *args,
                      apply_func=None,
                      as_columns=None,
                      **kwargs):
     """Apply a function n times and concatenate results into a single dataframe."""
     checks.assert_not_none(apply_func)
     if checks.is_numba_func(apply_func):
         # NOTE: your apply_func must a numba-compiled function and arguments must be numba-compatible
         # Also NOTE: outputs of apply_func must always be 2-dimensional
         result = combine_fns.apply_and_concat_nb(np.asarray(self._obj),
                                                  ntimes, apply_func, *args,
                                                  **kwargs)
     else:
         result = combine_fns.apply_and_concat(np.asarray(self._obj),
                                               ntimes, apply_func, *args,
                                               **kwargs)
     # Build column hierarchy
     if as_columns is not None:
         new_columns = index_fns.combine(
             as_columns,
             reshape_fns.to_2d(self._obj).columns)
     else:
         new_columns = index_fns.tile(
             reshape_fns.to_2d(self._obj).columns, ntimes)
     return self.wrap_array(result, columns=new_columns)
Beispiel #4
0
 def tile(self, n, as_columns=None):
     tiled = reshape_fns.tile(self._obj, n, along_axis=1)
     if as_columns is not None:
         new_columns = index_fns.combine(
             as_columns,
             reshape_fns.to_2d(self._obj).columns)
         return self.wrap_array(tiled.values, columns=new_columns)
     return tiled
Beispiel #5
0
    def repeat(self, n, as_columns=None):
        """See `vectorbt.utils.reshape_fns.repeat`.

        Use `as_columns` as a top-level column level."""
        repeated = reshape_fns.repeat(self._obj, n, axis=1)
        if as_columns is not None:
            new_columns = index_fns.combine(self.columns, as_columns)
            return self.wrap_array(repeated.values, columns=new_columns)
        return repeated
Beispiel #6
0
 def rolling_window(self, window, n=None):
     cube = nb.rolling_window_nb(self.to_2d_array(), window)
     if n is not None:
         idxs = np.round(np.linspace(0, cube.shape[2]-1, n)).astype(int)
         cube = cube[:, :, idxs]
     else:
         idxs = np.arange(cube.shape[2])
     matrix = np.hstack(cube)
     range_columns = pd.Index(self._obj.index[idxs], name='start_date')
     new_columns = index_fns.combine(range_columns, reshape_fns.to_2d(self._obj).columns)
     return pd.DataFrame(matrix, columns=new_columns)
Beispiel #7
0
def build_column_hierarchy(param_list, level_names, ts_columns):
    """For each parameter in `param_list`, create a new column level with parameter values. 
    Combine this level with columns `ts_columns` using Cartesian product."""
    checks.assert_same_shape(param_list, level_names, axis=0)
    param_indexes = [index_fns.from_values(param_list[i], name=level_names[i]) for i in range(len(param_list))]
    param_columns = None
    for param_index in param_indexes:
        if param_columns is None:
            param_columns = param_index
        else:
            param_columns = index_fns.stack(param_columns, param_index)
    if param_columns is not None:
        return index_fns.combine(param_columns, ts_columns)
    return ts_columns
Beispiel #8
0
    def apply_and_concat(self,
                         ntimes,
                         *args,
                         apply_func=None,
                         pass_2d=False,
                         as_columns=None,
                         **kwargs):
        """Apply `apply_func` `ntimes` times and concatenate the results along columns.
        See `vectorbt.utils.combine_fns.apply_and_concat`.

        Arguments `*args` and `**kwargs` will be directly passed to `apply_func`.
        If `pass_2d` is `True`, 2-dimensional NumPy arrays will be passed, otherwise as is.
        Use `as_columns` as a top-level column level.

        Example:
            ```python-repl
            >>> import pandas as pd
            >>> df = pd.DataFrame([[3, 4], [5, 6]], index=['x', 'y'], columns=['a', 'b'])

            >>> print(df.vbt.apply_and_concat(3, [1, 2, 3], 
            ...     apply_func=lambda i, a, b: a * b[i], as_columns=['c', 'd', 'e']))
                  c       d       e    
               a  b   a   b   a   b
            x  3  4   6   8   9  12
            y  5  6  10  12  15  18
            ```"""
        checks.assert_not_none(apply_func)
        # Optionally cast to 2d array
        if pass_2d:
            obj_arr = reshape_fns.to_2d(np.asarray(self._obj))
        else:
            obj_arr = np.asarray(self._obj)
        if checks.is_numba_func(apply_func):
            result = combine_fns.apply_and_concat_nb(obj_arr, ntimes,
                                                     apply_func, *args,
                                                     **kwargs)
        else:
            result = combine_fns.apply_and_concat(obj_arr, ntimes, apply_func,
                                                  *args, **kwargs)
        # Build column hierarchy
        if as_columns is not None:
            new_columns = index_fns.combine(as_columns, self.columns)
        else:
            new_columns = index_fns.tile(self.columns, ntimes)
        return self.wrap_array(result, columns=new_columns)
Beispiel #9
0
 def concat(self_or_cls, *others, as_columns=None, broadcast_kwargs={}):
     others = tuple(
         map(lambda x: x._obj
             if isinstance(x, Base_Accessor) else x, others))
     if isinstance(self_or_cls, type):
         objs = others
     else:
         objs = (self_or_cls._obj, ) + others
     broadcasted = reshape_fns.broadcast(*objs, **broadcast_kwargs)
     broadcasted = tuple(map(reshape_fns.to_2d, broadcasted))
     if checks.is_pandas(broadcasted[0]):
         concated = pd.concat(broadcasted, axis=1)
         if as_columns is not None:
             concated.columns = index_fns.combine(as_columns,
                                                  broadcasted[0].columns)
     else:
         concated = np.hstack(broadcasted)
     return concated
Beispiel #10
0
    def generate_stop_loss(self, ts, stops, trailing=False, as_columns=None, broadcast_kwargs={}):
        """See `vectorbt.signals.nb.stop_loss_nb`.

        Arguments will be broadcasted using `vectorbt.utils.reshape_fns.broadcast`
        with `broadcast_kwargs`. Argument `stops` can be either a single number, an array of 
        numbers, or a 3D array, where each matrix corresponds to a single configuration. 
        Use `as_columns` as a top-level column level.

        Example:
            For each entry in `signals`, set stop-loss order for 10% and 20% below the price `ts`:

            ```python-repl
            >>> print(entries.vbt.signals.generate_stop_loss(ts, [0.1, 0.2]))
            stop_loss                   0.1                  0.2
                            a      b      c      a      b      c
            2018-01-01  False  False  False  False  False  False
            2018-01-02  False   True  False  False  False  False
            2018-01-03  False  False  False  False  False  False
            2018-01-04  False   True   True  False   True   True
            2018-01-05  False  False  False  False  False  False
            ```"""
        entries = self._obj
        checks.assert_type(ts, (pd.Series, pd.DataFrame))

        entries, ts = reshape_fns.broadcast(entries, ts, **broadcast_kwargs, writeable=True)
        stops = reshape_fns.broadcast_to_array_of(stops, entries.vbt.to_2d_array())
        exits = nb.generate_stop_loss_nb(entries.vbt.to_2d_array(), ts.vbt.to_2d_array(), stops, trailing)

        # Build column hierarchy
        if as_columns is not None:
            param_columns = as_columns
        else:
            name = 'trail_stop' if trailing else 'stop_loss'
            param_columns = index_fns.from_values(stops, name=name)
        columns = index_fns.combine(param_columns, entries.vbt.columns)
        return entries.vbt.wrap_array(exits, columns=columns)
Beispiel #11
0
    def rolling_window(self, window, n=None):
        """Split time series into `n` time ranges each `window` long.

        The result will be a new DataFrame with index of length `window` and columns of length
        `len(columns) * n`. If `n` is `None`, will return the maximum number of time ranges.

        Example:
            ```python-repl
            >>> print(df.vbt.timeseries.rolling_window(2, n=2))
                                a                     b                     c           
            start_date 2018-01-01 2018-01-04 2018-01-01 2018-01-04 2018-01-01 2018-01-04
            0                 1.0        4.0        5.0        2.0        1.0        2.0
            1                 2.0        5.0        4.0        1.0        2.0        1.0 
            ```"""
        cube = nb.rolling_window_nb(self.to_2d_array(), window)
        if n is not None:
            idxs = np.round(np.linspace(0, cube.shape[2]-1, n)).astype(int)
            cube = cube[:, :, idxs]
        else:
            idxs = np.arange(cube.shape[2])
        matrix = np.hstack(cube)
        range_columns = pd.Index(self.index[idxs], name='start_date')
        new_columns = index_fns.combine(self.columns, range_columns)
        return pd.DataFrame(matrix, columns=new_columns)
Beispiel #12
0
    def combine_with_multiple(self,
                              others,
                              *args,
                              combine_func=None,
                              concat=False,
                              broadcast_kwargs={},
                              as_columns=None,
                              **kwargs):
        """Broadcast with other objects to the same shape and combine them all pairwise.

        The returned shape is the same as broadcasted shape if concat is False.
        The returned shape is concatenation of broadcasted shapes if concat is True."""
        others = tuple(
            map(lambda x: x._obj
                if isinstance(x, Base_Accessor) else x, others))
        checks.assert_not_none(combine_func)
        checks.assert_type(others, Iterable)
        # Broadcast arguments
        if checks.is_numba_func(combine_func):
            # Numba requires writable arrays
            broadcast_kwargs = {**dict(writeable=True), **broadcast_kwargs}
            # Plus all of our arrays must be in the same order
            broadcast_kwargs['copy_kwargs'] = {
                **dict(order='C'),
                **broadcast_kwargs.get('copy_kwargs', {})
            }
        new_obj, *new_others = reshape_fns.broadcast(self._obj, *others,
                                                     **broadcast_kwargs)
        broadcasted = tuple(map(np.asarray, (new_obj, *new_others)))
        if concat:
            # Concat the results horizontally
            if checks.is_numba_func(combine_func):
                for i in range(1, len(broadcasted)):
                    # NOTE: all inputs must have the same dtype
                    checks.assert_same_meta(broadcasted[i - 1], broadcasted[i])
                result = combine_fns.combine_and_concat_nb(
                    broadcasted[0], broadcasted[1:], combine_func, *args,
                    **kwargs)
            else:
                result = combine_fns.combine_and_concat(
                    broadcasted[0], broadcasted[1:], combine_func, *args,
                    **kwargs)
            if as_columns is not None:
                new_columns = index_fns.combine(
                    as_columns,
                    reshape_fns.to_2d(new_obj).columns)
            else:
                new_columns = index_fns.tile(
                    reshape_fns.to_2d(new_obj).columns, len(others))
            return new_obj.vbt.wrap_array(result, columns=new_columns)
        else:
            # Combine arguments pairwise into one object
            if checks.is_numba_func(combine_func):
                for i in range(1, len(broadcasted)):
                    # NOTE: all inputs must have the same dtype
                    checks.assert_same_dtype(broadcasted[i - 1],
                                             broadcasted[i])
                result = combine_fns.combine_multiple_nb(
                    broadcasted, combine_func, *args, **kwargs)
            else:
                result = combine_fns.combine_multiple(broadcasted,
                                                      combine_func, *args,
                                                      **kwargs)
            return new_obj.vbt.wrap_array(result)
Beispiel #13
0
    def combine_with_multiple(self,
                              others,
                              *args,
                              combine_func=None,
                              pass_2d=False,
                              concat=False,
                              broadcast_kwargs={},
                              as_columns=None,
                              **kwargs):
        """Combine with `others` using `combine_func`.

        All arguments will be broadcasted using `vectorbt.utils.reshape_fns.broadcast`
        with `broadcast_kwargs`.

        If `concat` is `True`, concatenate the results along columns, 
        see `vectorbt.utils.combine_fns.combine_and_concat`.
        Otherwise, pairwise combine into a Series/DataFrame of the same shape, 
        see `vectorbt.utils.combine_fns.combine_multiple`.

        Arguments `*args` and `**kwargs` will be directly passed to `combine_func`. 
        If `pass_2d` is `True`, 2-dimensional NumPy arrays will be passed, otherwise as is.
        Use `as_columns` as a top-level column level.

        !!! note
            If `combine_func` is Numba-compiled, will broadcast using `writeable=True` and
            copy using `order='C'` flags, which can lead to an expensive computation overhead if
            passed objects are large and have different shape/memory order. You also must ensure 
            that all objects have the same data type.

            Also remember to bring each in `*args` to a Numba-compatible format.

        Example:
            ```python-repl
            >>> import pandas as pd
            >>> sr = pd.Series([1, 2], index=['x', 'y'])
            >>> df = pd.DataFrame([[3, 4], [5, 6]], index=['x', 'y'], columns=['a', 'b'])

            >>> print(sr.vbt.combine_with_multiple([df, df*2], 
            ...     combine_func=lambda x, y: x + y))
                a   b
            x  10  13
            y  17  20

            >>> print(sr.vbt.combine_with_multiple([df, df*2], 
            ...     combine_func=lambda x, y: x + y, concat=True, as_columns=['c', 'd']))
                  c       d    
               a  b   a   b
            x  4  5   7   9
            y  7  8  12  14
            ```"""
        others = tuple(
            map(lambda x: x._obj
                if isinstance(x, Base_Accessor) else x, others))
        checks.assert_not_none(combine_func)
        checks.assert_type(others, Iterable)
        # Broadcast arguments
        if checks.is_numba_func(combine_func):
            # Numba requires writable arrays
            broadcast_kwargs = {**dict(writeable=True), **broadcast_kwargs}
            # Plus all of our arrays must be in the same order
            broadcast_kwargs['copy_kwargs'] = {
                **dict(order='C'),
                **broadcast_kwargs.get('copy_kwargs', {})
            }
        new_obj, *new_others = reshape_fns.broadcast(self._obj, *others,
                                                     **broadcast_kwargs)
        # Optionally cast to 2d array
        if pass_2d:
            bc_arrays = tuple(
                map(lambda x: reshape_fns.to_2d(np.asarray(x)),
                    (new_obj, *new_others)))
        else:
            bc_arrays = tuple(
                map(lambda x: np.asarray(x), (new_obj, *new_others)))
        if concat:
            # Concat the results horizontally
            if checks.is_numba_func(combine_func):
                for i in range(1, len(bc_arrays)):
                    checks.assert_same_meta(bc_arrays[i - 1], bc_arrays[i])
                result = combine_fns.combine_and_concat_nb(
                    bc_arrays[0], bc_arrays[1:], combine_func, *args, **kwargs)
            else:
                result = combine_fns.combine_and_concat(
                    bc_arrays[0], bc_arrays[1:], combine_func, *args, **kwargs)
            columns = new_obj.vbt.columns
            if as_columns is not None:
                new_columns = index_fns.combine(as_columns, columns)
            else:
                new_columns = index_fns.tile(columns, len(others))
            return new_obj.vbt.wrap_array(result, columns=new_columns)
        else:
            # Combine arguments pairwise into one object
            if checks.is_numba_func(combine_func):
                for i in range(1, len(bc_arrays)):
                    checks.assert_same_dtype(bc_arrays[i - 1], bc_arrays[i])
                result = combine_fns.combine_multiple_nb(
                    bc_arrays, combine_func, *args, **kwargs)
            else:
                result = combine_fns.combine_multiple(bc_arrays, combine_func,
                                                      *args, **kwargs)
            return new_obj.vbt.wrap_array(result)