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')

VectorBT PRO

Pattern ranges locate windows that match a price pattern. Projections collect price paths after events and calculate their distributions.

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,
    engine=None
)

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

See range_coverage().


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,
    engine=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 0x7f64f8901260>",
        "agg_func": null,
        "tags": "wrapper"
    },
    "end": {
        "title": "End",
        "calc_func": "<function Ranges.<lambda> at 0x7f64f8901300>",
        "agg_func": null,
        "tags": "wrapper"
    },
    "period": {
        "title": "Period",
        "calc_func": "<function Ranges.<lambda> at 0x7f64f89013a0>",
        "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 0x7f64f8901440>",
        "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,
    engine=None
)

Convert ranges to a mask.

See ranges_to_mask().


ts property¶

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