quantlab.analysis.factor_report.FactorAnalyzer#
- class quantlab.analysis.factor_report.FactorAnalyzer(quantiles=5, rolling_window=22, plot=True, workers=None, chunk_size=32, correlation_threshold=0.7, autocorrelation_lags=(1, 5, 10, 20))[source]#
Bases:
objectCompute alphalens-style metrics of factor variables against frets.
The metrics are computed with polars: the aligned panels become one long
(timestamp, symbol)frame per chunk of factor variables, every per-period statistic of every variable in the chunk is one lazy plan, and the plan is collected once. Only the small per-period series are then finished in pandas.- Parameters:
- quantilesint, default 5
Number of equal-count buckets per timestamp. Timestamps with fewer usable symbols than buckets get no bucket returns.
- rolling_windowint, default 22
Window, in periods, of the rolling mean IC drawn in the figure.
- plotbool, default True
Draw figures. With an
output_dirthey are drawn onworkersprocesses straight to PNG files and not kept; without one they are held inFactorAnalysis.figures. False draws none: anoutput_dirthen gets the tables and JSON files only.- workersint, optional
Processes that draw the figures of a saved report;
Noneuses every CPU the process may run on (os.process_cpu_count, which followstasksetandnumactl).- chunk_sizeint, default 32
Factor variables per lazy plan. Each plan holds
chunk_size + 3float columns oftimestamps * symbolsrows in memory.- correlation_thresholdfloat, default 0.7
|correlation|at which the factor-correlation clusters are cut; seequantlab.analysis.factor_correlation.- autocorrelation_lagssequence of int, default (1, 5, 10, 20)
Lags, in periods, of the factor rank autocorrelation. Lag 1 is always included.
Examples
>>> analyzer = FactorAnalyzer(quantiles=5) >>> pair = analyzer.analyze_pair(signal, ret, "signal", "ret_1") >>> round(pair.summary["ic_mean"], 4), pair.mean_quantile_returns.round(4).tolist() (0.2384, [-0.0037, -0.0013, -0.0005, 0.0018, 0.0032])
- analyze_many(features, labels, horizon=1)[source]#
Compute every metric of every factor variable against every fret.
- Parameters:
- features, labelsxarray.Dataset
Aligned
(timestamp, symbol)panels: the factor variables and the forward-return variables. Only cells finite in both a factor and a fret are used for that pair.- horizonint, default 1
Bars the forward returns span.
- Returns:
- list of PairAnalysis
One per
(factor variable, fret variable), frets outermost.
Examples
>>> pairs = FactorAnalyzer().analyze_many(signals, rets, horizon=1) >>> [pair.key for pair in pairs] ['signal__ret_1', 'noise__ret_1']
- analyze_pair(factor, fret, factor_name, fret_name, horizon=1)[source]#
Compute every metric of one aligned factor/fret pair.
- Parameters:
- factor, fretxarray.DataArray
Aligned
(timestamp, symbol)panels. Only cells finite in both are used.- factor_name, fret_namestr
Names recorded in the result.
- horizonint, default 1
Bars the forward return spans.
- Returns:
- PairAnalysis
The metrics.
Examples
>>> pair = FactorAnalyzer().analyze_pair(signal, ret, "signal", "ret_1") >>> pair.key, pair.quantile_returns.shape ('signal__ret_1', (100, 5))
- analyze_panels(features, frets, *, config=None, output_dir=None, factor_label='factors')[source]#
Analyze every variable of
featuresagainst every fret panel.The panel-level core of
run, for panels that come from noFactorobject: each fret panel is checked for the features’ bar spacing, inner-joined withfeaturesand analyzed; the factor correlation, the figures andoutput_dirare handled as inrun.- Parameters:
- featuresxarray.Dataset
The factor variables on
(timestamp, symbol); every variable is analyzed.- fretssequence of Fret
The forward-return panels, each with its horizon and the name error messages give it.
- configdict, optional
Recorded as
FactorAnalysis.config; empty when None.- output_dirstr or pathlib.Path, optional
When given,
FactorAnalysis.savewrites the results there and the figures are not kept in memory.- factor_labelstr, default “factors”
Names the features in error messages (
runpasses the factor’s class name).
- Returns:
- FactorAnalysis
The metrics, figures and
config.
- Raises:
- ValueError
If no fret is given, a fret panel’s bar spacing differs from the features’, a fret panel shares no cell with the features, or two pairs share a name.
Examples
>>> import numpy as np >>> import pandas as pd >>> import xarray as xr >>> from quantlab.analysis.factor_report import FactorAnalyzer, Fret >>> rng = np.random.default_rng(0) >>> coords = {"timestamp": pd.date_range("2024-01-01", periods=50), ... "symbol": [f"S{i}" for i in range(10)]} >>> raw = rng.normal(size=(50, 10)) >>> features = xr.Dataset({"signal": (("timestamp", "symbol"), raw)}, coords=coords) >>> rets = xr.Dataset( ... {"ret_2": (("timestamp", "symbol"), 0.3 * raw + rng.normal(size=(50, 10)))}, ... coords=coords, ... ) >>> analysis = FactorAnalyzer(plot=False).analyze_panels( ... features, [Fret(rets, horizon=2)] ... ) >>> list(analysis.pairs), analysis.pairs["signal__ret_2"].horizon, analysis.config (['signal__ret_2'], 2, {})
- static check_frequency(features, labels, factor_label='factor', fret_label='fret')[source]#
Refuse panels whose most common bar spacing differs.
- Parameters:
- features, labelsxarray.Dataset
The factor and forward-return panels.
- factor_label, fret_labelstr
Names used in the error message.
- Returns:
- numpy.timedelta64
The shared spacing.
- Raises:
- ValueError
If the spacings differ.
Examples
>>> FactorAnalyzer.check_frequency(daily, weekly, "signal", "ret") Traceback (most recent call last): ... ValueError: bar spacing differs: signal has 1 days 00:00:00 bars, ret has 7 days 00:00:00 bars; resample one panel to the other's frequency first
- run(factor, frets, features, labels, factor_names=None, output_dir=None)[source]#
Analyze
featuresagainst every fret’s labels; seeFactor.analyze.- Parameters:
- factorFactor
The analyzed factor; its names, class and config are recorded.
- fretssequence of Forward
Forward-return labels, in the order of
labels; each one’sspan_bars()is its horizon.- featuresxr.Dataset
The factor’s panel from
computeorread.- labelssequence of xr.Dataset
Each fret’s panel from
computeorread.- factor_namessequence of str, optional
Factor variables to analyze; all of
get_factor_names()when None.- output_dirstr or pathlib.Path, optional
When given,
FactorAnalysis.savewrites the results there and the figures are not kept in memory.
- Returns:
- FactorAnalysis
The metrics, figures and configs.
- Raises:
- ValueError
If no fret is given, a factor name is unknown, a fret panel’s bar spacing differs from the factor’s, the aligned panel is empty, or two pairs share a name.
Examples
>>> window = ("2024-02-01", "2024-02-29") >>> analysis = FactorAnalyzer(quantiles=4).run( ... factor, [fwd], ... features=factor.compute(*window), ... labels=[fwd.compute(*window)], ... ) >>> list(analysis.pairs) ['momentum_5__ret_1']