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¶
Hint
See StatsBuilderMixin.stats() and Ranges.metrics.
>>> 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¶
Hint
See PlotsBuilderMixin.plots() and Ranges.subplots.
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
- AttrResolver
- Configured
- Documented
- IndexingBase
- PandasIndexer
- Pickleable
- PlotsBuilderMixin
- Records
- RecordsWithFields
- StatsBuilderMixin
- Wrapping
Inherited members
- AttrResolver.deep_getattr()
- AttrResolver.post_resolve_attr()
- AttrResolver.pre_resolve_attr()
- AttrResolver.resolve_attr()
- Configured.copy()
- Configured.dumps()
- Configured.loads()
- Configured.to_doc()
- Configured.update_config()
- PandasIndexer.xs()
- Pickleable.load()
- Pickleable.save()
- PlotsBuilderMixin.build_subplots_doc()
- PlotsBuilderMixin.override_subplots_doc()
- PlotsBuilderMixin.plots()
- Records.apply()
- Records.apply_mask()
- Records.build_field_config_doc()
- Records.col_arr
- Records.col_mapper
- Records.config
- Records.count()
- Records.get_apply_mapping_arr()
- Records.get_by_col_idxs()
- Records.get_field_arr()
- Records.get_field_mapping()
- Records.get_field_name()
- Records.get_field_setting()
- Records.get_field_title()
- Records.get_map_field()
- Records.get_map_field_to_index()
- Records.id_arr
- Records.idx_arr
- Records.iloc
- Records.indexing_func_meta()
- Records.indexing_kwargs
- Records.is_sorted()
- Records.loc
- Records.map()
- Records.map_array()
- Records.map_field()
- Records.override_field_config_doc()
- Records.records
- Records.records_arr
- Records.records_readable
- Records.replace()
- Records.self_aliases
- Records.sort()
- Records.values
- Records.wrapper
- Records.writeable_attrs
- StatsBuilderMixin.build_metrics_doc()
- StatsBuilderMixin.override_metrics_doc()
- StatsBuilderMixin.stats()
- Wrapping.regroup()
- Wrapping.resolve_self()
- Wrapping.select_one()
- Wrapping.select_one_from_obj()
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
orFigureWidget
- 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).