Skip to content

ranges module

Base class for working with range records.

Range records capture information on ranges. They are useful for analyzing duration of processes, such as drawdowns, trades, and positions. They also come in handy when analyzing distance between events, such as entry and exit signals.

Each range has a starting point and an ending point. For example, the points for range(20) are 0 and 20 (not 19!) respectively.

Note

Be aware that if a range hasn't ended in a column, its end_idx will point at the latest index. Make sure to account for this when computing custom metrics involving duration.

>>> import vectorbt as vbt
>>> import numpy as np
>>> import pandas as pd

>>> start = '2019-01-01 UTC'  # crypto is in UTC
>>> end = '2020-01-01 UTC'
>>> price = vbt.YFData.download('BTC-USD', start=start, end=end).get('Close')
>>> fast_ma = vbt.MA.run(price, 10)
>>> slow_ma = vbt.MA.run(price, 50)
>>> fast_below_slow = fast_ma.ma_above(slow_ma)

>>> ranges = vbt.Ranges.from_ts(fast_below_slow, wrapper_kwargs=dict(freq='d'))

>>> ranges.records_readable
   Range Id  Column           Start Timestamp             End Timestamp  \
0         0       0 2019-02-19 00:00:00+00:00 2019-07-25 00:00:00+00:00
1         1       0 2019-08-08 00:00:00+00:00 2019-08-19 00:00:00+00:00
2         2       0 2019-11-01 00:00:00+00:00 2019-11-20 00:00:00+00:00

   Status
0  Closed
1  Closed
2  Closed

>>> ranges.duration.max(wrap_kwargs=dict(to_timedelta=True))
Timedelta('74 days 00:00:00')

From accessors

Moreover, all generic accessors have a property ranges and a method get_ranges:

>>> # vectorbt.generic.accessors.GenericAccessor.ranges.coverage
>>> fast_below_slow.vbt.ranges.coverage()
0.35792349726775957

Stats

>>> df = pd.DataFrame({
...     'a': [1, 2, np.nan, np.nan, 5, 6],
...     'b': [np.nan, 2, np.nan, 4, np.nan, 6]
... })
>>> ranges = df.vbt(freq='d').ranges

>>> ranges['a'].stats()
Start                             0
End                               5
Period              6 days 00:00:00
Total Records                     2
Coverage            4 days 00:00:00
Overlap Coverage    0 days 00:00:00
Duration: Min       2 days 00:00:00
Duration: Median    2 days 00:00:00
Duration: Max       2 days 00:00:00
Duration: Mean      2 days 00:00:00
Duration: Std       0 days 00:00:00
Name: a, dtype: object

StatsBuilderMixin.stats() also supports (re-)grouping:

>>> ranges.stats(group_by=True)
Start                                       0
End                                         5
Period                        6 days 00:00:00
Total Records                               5
Coverage                      5 days 00:00:00
Overlap Coverage              2 days 00:00:00
Duration: Min                 1 days 00:00:00
Duration: Median              1 days 00:00:00
Duration: Max                 2 days 00:00:00
Duration: Mean                1 days 09:36:00
Duration: Std       0 days 13:08:43.228968446
Name: group, dtype: object

Plots

Ranges class has a single subplot based on Ranges.plot():

>>> ranges['a'].plots()


ranges_attach_field_config Config

Config of fields to be attached to Ranges.

Config({
    "status": {
        "attach_filters": true
    }
})

ranges_field_config Config

Field config for Ranges.

Config({
    "dtype": {
        "id": "int64",
        "col": "int64",
        "start_idx": "int64",
        "end_idx": "int64",
        "status": "int64"
    },
    "settings": {
        "id": {
            "title": "Range Id"
        },
        "idx": {
            "name": "end_idx"
        },
        "start_idx": {
            "title": "Start Timestamp",
            "mapping": "index"
        },
        "end_idx": {
            "title": "End Timestamp",
            "mapping": "index"
        },
        "status": {
            "title": "Status",
            "mapping": {
                "Open": 0,
                "Closed": 1
            }
        }
    }
})

Ranges class

Ranges(
    wrapper,
    records_arr,
    ts=None,
    **kwargs
)

Extends Records for working with range records.

Requires records_arr to have all fields defined in range_dt.

Superclasses

Inherited members

Subclasses


avg_duration method

Ranges.avg_duration(
    group_by=None,
    wrap_kwargs=None,
    **kwargs
)

Average range duration (as timedelta).


closed method

Records filtered by status == 1.


col method

Mapped array of the field col.


coverage method

Ranges.coverage(
    overlapping=False,
    normalize=True,
    group_by=None,
    wrap_kwargs=None
)

Coverage, that is, the number of steps that are covered by all ranges.

See range_coverage_nb().


duration method

Duration of each range (in raw format).


end_idx method

Mapped array of the field end_idx.


field_config class variable

Field config of Ranges.

Config({
    "dtype": {
        "id": "int64",
        "col": "int64",
        "start_idx": "int64",
        "end_idx": "int64",
        "status": "int64"
    },
    "settings": {
        "id": {
            "name": "id",
            "title": "Range Id"
        },
        "col": {
            "name": "col",
            "title": "Column",
            "mapping": "columns"
        },
        "idx": {
            "name": "end_idx",
            "title": "Timestamp",
            "mapping": "index"
        },
        "start_idx": {
            "title": "Start Timestamp",
            "mapping": "index"
        },
        "end_idx": {
            "title": "End Timestamp",
            "mapping": "index"
        },
        "status": {
            "title": "Status",
            "mapping": {
                "Open": 0,
                "Closed": 1
            }
        }
    }
})

from_ts class method

Ranges.from_ts(
    ts,
    gap_value=None,
    attach_ts=True,
    wrapper_kwargs=None,
    **kwargs
)

Build Ranges from time series ts.

Searches for sequences of

  • True values in boolean data (False acts as a gap),
  • positive values in integer data (-1 acts as a gap), and
  • non-NaN values in any other data (NaN acts as a gap).

**kwargs will be passed to Ranges.


id method

Mapped array of the field id.


indexing_func method

Ranges.indexing_func(
    pd_indexing_func,
    **kwargs
)

Perform indexing on Ranges.


max_duration method

Ranges.max_duration(
    group_by=None,
    wrap_kwargs=None,
    **kwargs
)

Maximum range duration (as timedelta).


metrics class variable

Metrics supported by Ranges.

Config({
    "start": {
        "title": "Start",
        "calc_func": "<function Ranges.<lambda> at 0x136191d00>",
        "agg_func": null,
        "tags": "wrapper"
    },
    "end": {
        "title": "End",
        "calc_func": "<function Ranges.<lambda> at 0x136191da0>",
        "agg_func": null,
        "tags": "wrapper"
    },
    "period": {
        "title": "Period",
        "calc_func": "<function Ranges.<lambda> at 0x136191e40>",
        "apply_to_timedelta": true,
        "agg_func": null,
        "tags": "wrapper"
    },
    "coverage": {
        "title": "Coverage",
        "calc_func": "coverage",
        "overlapping": false,
        "normalize": false,
        "apply_to_timedelta": true,
        "tags": [
            "ranges",
            "coverage"
        ]
    },
    "overlap_coverage": {
        "title": "Overlap Coverage",
        "calc_func": "coverage",
        "overlapping": true,
        "normalize": false,
        "apply_to_timedelta": true,
        "tags": [
            "ranges",
            "coverage"
        ]
    },
    "total_records": {
        "title": "Total Records",
        "calc_func": "count",
        "tags": "records"
    },
    "duration": {
        "title": "Duration",
        "calc_func": "duration.describe",
        "post_calc_func": "<function Ranges.<lambda> at 0x136191ee0>",
        "apply_to_timedelta": true,
        "tags": [
            "ranges",
            "duration"
        ]
    }
})

Returns Ranges._metrics, which gets (deep) copied upon creation of each instance. Thus, changing this config won't affect the class.

To change metrics, you can either change the config in-place, override this property, or overwrite the instance variable Ranges._metrics.


open method

Records filtered by status == 0.


plot method

Ranges.plot(
    column=None,
    top_n=5,
    plot_zones=True,
    ts_trace_kwargs=None,
    start_trace_kwargs=None,
    end_trace_kwargs=None,
    open_shape_kwargs=None,
    closed_shape_kwargs=None,
    add_trace_kwargs=None,
    xref='x',
    yref='y',
    fig=None,
    **layout_kwargs
)

Plot ranges.

Args

column : str
Name of the column to plot.
top_n : int
Filter top N range records by maximum duration.
plot_zones : bool
Whether to plot zones.
ts_trace_kwargs : dict
Keyword arguments passed to plotly.graph_objects.Scatter for Ranges.ts.
start_trace_kwargs : dict
Keyword arguments passed to plotly.graph_objects.Scatter for start values.
end_trace_kwargs : dict
Keyword arguments passed to plotly.graph_objects.Scatter for end values.
open_shape_kwargs : dict
Keyword arguments passed to plotly.graph_objects.Figure.add_shape for open zones.
closed_shape_kwargs : dict
Keyword arguments passed to plotly.graph_objects.Figure.add_shape for closed zones.
add_trace_kwargs : dict
Keyword arguments passed to add_trace.
xref : str
X coordinate axis.
yref : str
Y coordinate axis.
fig : Figure or FigureWidget
Figure to add traces to.
**layout_kwargs
Keyword arguments for layout.

Usage

>>> import vectorbt as vbt
>>> from datetime import datetime, timedelta
>>> import pandas as pd

>>> price = pd.Series([1, 2, 1, 2, 3, 2, 1, 2], name='Price')
>>> price.index = [datetime(2020, 1, 1) + timedelta(days=i) for i in range(len(price))]
>>> vbt.Ranges.from_ts(price >= 2, wrapper_kwargs=dict(freq='1 day')).plot()


plots_defaults property

Defaults for PlotsBuilderMixin.plots().

Merges Records.plots_defaults and ranges.plots from settings.


start_idx method

Mapped array of the field start_idx.


stats_defaults property

Defaults for StatsBuilderMixin.stats().

Merges Records.stats_defaults and ranges.stats from settings.


status method

Mapped array of the field status.


subplots class variable

Subplots supported by Ranges.

Config({
    "plot": {
        "title": "Ranges",
        "check_is_not_grouped": true,
        "plot_func": "plot",
        "tags": "ranges"
    }
})

Returns Ranges._subplots, which gets (deep) copied upon creation of each instance. Thus, changing this config won't affect the class.

To change subplots, you can either change the config in-place, override this property, or overwrite the instance variable Ranges._subplots.


to_mask method

Ranges.to_mask(
    group_by=None,
    wrap_kwargs=None
)

Convert ranges to a mask.

See ranges_to_mask_nb().


ts property

Original time series that records are built from (optional).