quantlab.runs.record.DataRecorder#
- class quantlab.runs.record.DataRecorder(keys=(), expected=None, owner='DataRecorder')[source]#
Bases:
objectRecord the data a run reads, hash it once per request, compare on close.
A run opens one around everything it reads: a trained unit, a backtest run, a
run_cvfold. While it is the innermost open recorder, every read throughBaseDataset.panel,Factor.readand a factor risk model’sRiskStore.readis logged as a request; nested recorders log to the innermost only. Only leaf datasets record (a store or a held panel): aMergedDatasetrecords nothing itself, its inputs do. A risk store is recorded under its model’s key and the store (risk_model.estimate), its reads merged into one request over the first to the last bar read (record_read’sreread_range).When the context closes, each distinct request is read once more and hashed with
_dataset_fingerprintover the requested variables (every variable of the panel when none were requested).recordsthen maps each key to its requests, in the order first read; an in-memory dataset hashes the panel it holds. Withexpectedgiven, the records are compared with it per key and request bydigestalone; a changed, missing or extra request or key logs a warning showing the ranges and sizes as explanation, and nothing is raised.If the body raises, what was read so far is hashed and compared partially: a request or key not read yet is not reported, every warning carries
_PARTIAL_NOTE, and the original error propagates. The diagnostic never raises and never replaces that error: a failure of the hashing or the comparison itself only logs a warning, andrecordskeeps what was hashed before it.- Parameters:
- keysiterable of (object, str) pairs, optional
The key each dataset, factor or risk model is recorded under, matched by identity; a source given twice takes its first key. An unmapped source is recorded under
"<ClassName>:<store path>", so two unmapped in-memory datasets share"FrameDataset:None"; map them.- expectedmapping, optional
A
recordsof an earlier run to compare with on close.- ownerstr
The name that opens every warning.
- Attributes:
- recordsdict
{key: [entry, ...]}, filled when the context closes. Each entry is a_dataset_fingerprintrecord plusrequest: the first and last bar read (start,end), the requestedsymbolsandvariables(Nonefor all); a source that reports its build settings addssettings, folded intodigest.
Examples
pricesis aStockDatasetover a business-day store from 2024-01-01:>>> with DataRecorder(keys=[(prices, "price_dataset")]) as recorder: ... _ = prices.panel("2024-01-02", "2024-01-31", variables=["adjClose"]) >>> entry = recorder.records["price_dataset"][0] >>> entry["request"]["variables"], entry["n_timestamps"] (['adjClose'], 22)
Comparing a rebuilt run whose store was restated (
restatedholds the same symbols and bars, other prices) logs, through loguru:with DataRecorder(keys=[(restated, "price_dataset")], expected=recorder.records): restated.panel("2024-01-02", "2024-01-31", variables=["adjClose"]) DataRecorder: data fingerprint mismatch for 'price_dataset', request 2024-01-02..2024-01-31, variables ['adjClose']: digest differs: values of ['adjClose'] changed (expected 2024-01-02T00:00:00 to 2024-01-31T00:00:00, 22 timestamps x 6 symbols, got ...). The data changed since the expected run; continuing