quantlab.risk.base.RiskStore#

class quantlab.risk.base.RiskStore(model, part, path, compute, warmup_bars)[source]#

Bases: object

One store of a factor risk model: rows per bar, written and read by date range.

Built by the risk model that owns it, from a function computing the rows of a date range (its warm-up included). A row may carry a symbol axis; it is written sorted (numerically for integer symbols), and only symbols with a value somewhere in the rows are kept, so the axis does not depend on how a range was split between build and extend.

The store is written through quantlab.backend.ranged.RangedStore, as a factor’s store is: the range recorded in <store_path>.range.json, the order of build and extend and their refusals are that module’s. The model writes its own stores, so owns_store() is true; a factor risk model declares its two stores to the live day and the data update (FactorRiskModel.store_uses).

A read inside an open quantlab.runs.record.DataRecorder is recorded under the model’s key and the store’s part (risk_model.estimate); one store’s reads are merged into one request over the first to the last bar read, so a reader taking a row per bar costs one record. Every read opens the store: a reader wanting rows in memory reads its range once and keeps them (the decision inputs read the estimate rows of a panel or a replay window this way).

Parameters:
modelFactorRiskModel

The risk model owning the store: the source of its recorded reads.

partstr

The store’s name in the model, "regression" or "estimate".

pathstr or None

The Zarr store; the date range is recorded in <path>.range.json.

computecallable

compute(start, end) returning the rows of the range as an xr.Dataset on timestamp (and its own other axes).

warmup_barsint

Bars before the requested start compute reads.

Attributes:
store_pathstr or None

As path.

ownerstr

Class.part, named in log and error messages.

Examples

>>> store = model.regression
>>> store.build("2024-01-01", "2024-03-31").store_range()
('2024-01-01', '2024-03-31')
>>> store.extend("2024-04-30").store_range()
('2024-01-01', '2024-04-30')
>>> dict(store.read("2024-04-01", "2024-04-30").sizes)["timestamp"]
22
build(start, end)[source]#

Compute start to end and write it as the store.

The store at store_path is replaced and the range recorded beside it (RangedStore.build).

Parameters:
start, endstr, datetime.date or pd.Timestamp

The range the store covers.

Returns:
RiskStore

self, for chaining.

Raises:
ValueError

If the store has no path.

Examples

>>> model.regression.build("2024-01-01", "2024-03-31").store_range()
('2024-01-01', '2024-03-31')
compute(start, end)[source]#

Compute the rows from start to end, both inclusive.

The compute function reads warmup_bars bars before start and returns only the requested bars. Nothing is written.

Parameters:
start, endstr, datetime.date or pd.Timestamp

The range. A date-only end includes every bar of that day.

Returns:
xr.Dataset

The rows, in memory, symbols sorted and the empty ones dropped.

Raises:
ValueError

If start is after end.

Examples

>>> rows = model.regression.compute("2024-02-01", "2024-02-29")
>>> rows["factor_return"].dims
('timestamp', 'factor')
extend(end)[source]#

Append the bars after the recorded range, up to end.

The bars are computed with compute, so they are warmed from the inputs’ history; a symbol axis widens to fit (RangedStore.extend).

Parameters:
endstr, datetime.date or pd.Timestamp

The new end of the store’s range.

Returns:
RiskStore

self, for chaining.

Raises:
ValueError

If the store has no path or no recorded range, or the recorded range already reaches end.

Examples

>>> model.regression.extend("2024-04-30").store_range()
('2024-01-01', '2024-04-30')
owns_store()[source]#

Return True: the risk model writes its own stores; nothing else does.

Examples

>>> model.regression.owns_store()
True
read(start, end)[source]#

Return the store from start to end, both inclusive.

The store is opened lazily. The range must lie inside the one recorded beside it (store_range). The read is recorded by an open DataRecorder (see the class docstring).

Parameters:
start, endstr, datetime.date or pd.Timestamp

The range. A date-only end includes every bar of that day.

Returns:
xr.Dataset

The rows of the range.

Raises:
ValueError

If start is after end, the store has no path or no recorded range, or the recorded range does not contain the requested one.

Examples

>>> model.regression.read("2024-03-20", "2024-04-10")
Traceback (most recent call last):
ValueError: Use4RiskModel.regression.read(): the store at ... covers 2024-01-01 to 2024-03-31, ...
rewind(end)[source]#

Drop the bars after end and end the recorded range there (RangedStore.rewind).

The next extend computes the dropped bars again.

Parameters:
endstr, datetime.date or pd.Timestamp

The new end of the store’s range, inside it and before its end.

Returns:
RiskStore

self, for chaining.

Raises:
ValueError

If the store has no path or no recorded range, or end is not inside the recorded range and before its end.

Examples

>>> model.regression.rewind("2024-04-15").store_range()
('2024-01-01', '2024-04-15')
store_range()[source]#

Return the (start, end) the store was built for, or None.

Examples

>>> model.regression.build("2024-01-01", "2024-03-31").store_range()
('2024-01-01', '2024-03-31')