quantlab.analysis.factor_report.FactorAnalysis#
- class quantlab.analysis.factor_report.FactorAnalysis(pairs, figures=<factory>, config=<factory>, correlation=None, correlation_figure=None)[source]#
Bases:
objectThe result of
Factor.analyze: onePairAnalysisper pair.- Attributes:
- pairsdict[str, PairAnalysis]
Keyed by
"<factor>__<fret>".- figuresdict[str, matplotlib.figure.Figure]
The composite figure of each pair, same keys. The figures are built without
pyplot, so they are not registered with any GUI and need no closing;fig.savefig(path)writes one.- configdict
{"factor": factor config, "frets": [fret configs]}, the dictsrebuildrebuilds each object from.- correlationFactorCorrelation or None
The correlation between the analyzed factor variables, when there are two or more;
Noneotherwise.- correlation_figurematplotlib.figure.Figure or None
The figure of
correlation, held when nooutput_dirwas given.
- decay_of(factor_name)[source]#
Return
factor_name’s rows ofic_decay_table(), or None with one fret.The pair figures draw these rows as their IC-decay panel.
Examples
>>> analysis.decay_of("signal") is None # one fret True
- has_decay()[source]#
Whether two or more frets were analyzed, so an IC decay is drawn.
Examples
>>> analysis.has_decay() # one fret False
- ic_decay_table()[source]#
Return every pair’s mean IC with its horizon, ordered by factor then horizon.
Columns are
factor,fret,horizon,ic_mean,ic_nw_t_statandci_low/ci_high, the 95% intervalic_mean ± 1.96 * sewith the Newey-West standard errorse = |ic_mean / ic_nw_t_stat|. Read down one factor’s rows to see how fast its signal decays as the forward return lengthens.Examples
>>> analysis.ic_decay_table()[["factor", "fret", "horizon"]] factor fret horizon 0 signal ret_1 1
- ic_table()[source]#
Return every pair’s IC series as one tidy table.
Columns are
timestamp,factor,fret,ic(rank) andpearson_ic.Examples
>>> analysis.ic_table().head(2).round({"ic": 4, "pearson_ic": 4}) timestamp factor fret ic pearson_ic 0 2024-01-01 signal ret_1 0.1308 0.1260 1 2024-01-02 signal ret_1 -0.1353 -0.0991
- monthly_ic_table()[source]#
Return every pair’s monthly mean IC, tidy.
Columns are
month(month end),factor,fretandic.Examples
>>> analysis.monthly_ic_table().round({"ic": 4}) month factor fret ic 0 2024-01-31 signal ret_1 0.2159 1 2024-02-29 signal ret_1 0.1772 2 2024-03-31 signal ret_1 0.3103 3 2024-04-30 signal ret_1 0.2655
- quantile_returns_table()[source]#
Return every pair’s mean return per bucket and period, tidy.
Columns are
timestamp,factor,fret,quantileandmean_return.Examples
>>> list(analysis.quantile_returns_table().columns) ['timestamp', 'factor', 'fret', 'quantile', 'mean_return']
- save(output_dir, workers=None, figures=True)[source]#
Write the analysis to
output_dir, creating it if needed.Files written:
summary.json(every scalar metric, per pair),summary.csv,ic.csv,monthly_ic.csv,quantile_returns.csv,turnover.csv, one<factor>__<fret>.pngper pair andconfig.json(seeconfig). With acorrelation, alsofactor_correlation.csv(the mean matrix in cluster order),factor_correlation_pairs.csv(pairs_table()),factor_clusters.csv(cluster_table()) andfactor_correlation.png, andsummary.jsonholds a"correlation"entry (FactorCorrelation.summary). With two or more frets, alsoic_decay.csv(ic_decay_table()), and every pair figure includes an IC-decay panel. Floats that are NaN or infinite are written to JSON asnull. Figures held infiguresare saved as they are; when none is held, every pair is drawn from its metrics and saved, onworkersprocesses, without being kept. Withfigures=Falseno PNG is written, neither a pair’s nor the correlation’s.- Parameters:
- output_dirstr or pathlib.Path
Directory to write into.
- workersint, optional
Processes that draw the figures;
Noneuses every CPU the process may run on (os.process_cpu_count).- figuresbool, default True
Write the figures; False writes the tables and JSON files only.
- Returns:
- pathlib.Path
output_dir.
Examples
>>> out = analysis.save("report") >>> sorted(p.name for p in out.iterdir()) ['config.json', 'ic.csv', 'monthly_ic.csv', 'quantile_returns.csv', 'signal__ret_1.png', 'summary.csv', 'summary.json', 'turnover.csv'] >>> sorted(p.name for p in analysis.save("tables", figures=False).iterdir()) ['config.json', 'ic.csv', 'monthly_ic.csv', 'quantile_returns.csv', 'summary.csv', 'summary.json', 'turnover.csv']
- summary()[source]#
Return the headline metrics, one row per pair, to sort and filter factors by.
Columns:
factor,fret: the pair;ic: mean per-period Pearson IC (pearson_ic_mean);rank_ic: mean per-period Spearman IC (ic_mean);icir,rank_icir: each mean over its standard deviation (pearson_ir,ir);long_short_return: mean per-period forward return of the top quantile minus the bottom one (mean_spread), over the fret’s horizon;turnover: mean per-period turnover of the top and bottom quantiles, averaged (mean_turnover_top,mean_turnover_bottom).
Every value is one of
summary_table()’s, which holds the full set of scalar metrics.- Returns:
- pandas.DataFrame
One row per pair, in the order of
pairs.
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=100), ... "symbol": [f"S{i}" for i in range(20)]} >>> raw = rng.normal(size=(100, 20)) >>> signal = xr.DataArray(raw, coords=coords, dims=("timestamp", "symbol")) >>> ret = xr.DataArray(0.01 * (0.3 * raw + rng.normal(size=(100, 20))), ... coords=coords, dims=("timestamp", "symbol")) >>> analysis = FactorAnalyzer(plot=False).analyze_panels( ... signal.to_dataset(name="signal"), [Fret(ret.to_dataset(name="ret_1"))] ... ) >>> analysis.summary()[["factor", "fret", "ic", "rank_ic", "turnover"]].round(4) factor fret ic rank_ic turnover 0 signal ret_1 0.26 0.2384 0.8068
- summary_table()[source]#
Return the scalar metrics, one row per pair.
Examples
>>> table = analysis.summary_table() >>> table[["factor", "fret", "ic_mean", "mean_spread"]].round(4) factor fret ic_mean mean_spread 0 signal ret_1 0.2384 0.0069
- turnover_table()[source]#
Return every pair’s bucket turnover and rank autocorrelation, tidy.
Columns are
timestamp,factor,fret,quantileandturnover; the factor’s lag-1 rank autocorrelation is repeated on each bucket row asrank_autocorrelation, and every further lagkasrank_autocorrelation_lag<k>.Examples
>>> list(analysis.turnover_table().columns) ['timestamp', 'factor', 'fret', 'quantile', 'turnover', 'rank_autocorrelation', 'rank_autocorrelation_lag5', 'rank_autocorrelation_lag10', 'rank_autocorrelation_lag20']