quantlab.risk.base.FactorRiskModel#
- class quantlab.risk.base.FactorRiskModel(config)[source]#
-
A factor risk model: the stores estimated ahead of a backtest.
The interface every factor risk model presents, whatever its method:
factor_names: the factor axis, andfactor_groups: each factor’s group (country, industry or style; style by default);exposure_namesandexposure_matrix(exposures): the outputs of the exposures factor (config.exposures) it reads, and each symbol’s exposures tofactor_namesat a bar, with whether it has them all;the regression store (
regression), one row per bart:factor_returnon(timestamp, factor), the factor returns over the bar ending att, andspecific_returnon(timestamp, symbol), each symbol’s return over that bar less its factor part, the exposures being those of the bar before;the estimate store (
estimate), one row per bart:factor_covarianceon(timestamp, factor_i, factor_j)andspecific_riskon(timestamp, symbol), forecasts made attof the next bar’s factor covariance and specific volatilities;pricesandexposures: its inputs over a date range.
Every quantity is of one-bar returns, a row uses nothing later than its bar, and a store may add its own diagnostics. The
factoraxes arefactor_names. A missing value is NaN: a factor without a return on a bar, a forecast without enough history.A subclass implements the method:
factor_names,exposure_names,exposure_matrix,_compute_regressionand_compute_estimate(the rows of a date range, its warm-up read before it), and the warm-upsregression_warmup_barsandestimate_warmup_bars; it setsconfig_clsto its config, aFactorRiskConfig, and checks its parameters in_validate(calling this class’s). The rows it computes are checked against the stores’ variables before they are returned or written.- Parameters:
- configFactorRiskConfig
The exposures factor, the price dataset and the method’s parameters; an instance of the class’s
config_cls.
- Raises:
- TypeError
If
configis not an instance ofconfig_cls.- ValueError
If a parameter is invalid.
Examples
With
modelaUse4RiskModel:>>> isinstance(model, FactorRiskModel) True >>> model.regression.build("2012-01-01", "2024-12-31") >>> model.regression.read("2020-01-01", "2020-12-31")["factor_return"].dims ('timestamp', 'factor') >>> model.estimate.build("2018-01-01", "2024-12-31") >>> model.estimate.read("2024-12-31", "2024-12-31")["factor_covariance"].dims ('timestamp', 'factor_i', 'factor_j')
- property class_name#
Bare class name, used in log and error messages.
Examples
>>> model.class_name 'Use4RiskModel'
- property config#
The model’s normalised config:
namefilled, datasets merged.Examples
>>> model.config is config False >>> model.config.name 'quantlab.risk.predefined.use4.Use4RiskModel'
- config_cls#
The config class
from_configrebuilds this model with.alias of
FactorRiskConfig
- property estimate#
The estimate store: forecast factor covariance and specific risk (see the class docstring).
Examples
>>> model.estimate.build("2018-01-01", "2024-12-31") >>> rows = model.estimate.read("2024-12-31", "2024-12-31") >>> rows["factor_covariance"].dims ('timestamp', 'factor_i', 'factor_j')
- abstract property estimate_warmup_bars#
Regression-store bars before a range
_compute_estimatereads.Examples
>>> model.estimate_warmup_bars # Use4RiskModel's default 1637
- abstractmethod exposure_matrix(exposures)[source]#
Return each symbol’s exposures to
factor_namesand whether it has them all.- Parameters:
- exposuresxr.Dataset
The exposures factor’s values at one bar, on
symbol.
- Returns:
- matrixnp.ndarray
[n_symbols, n_factors].- coverednp.ndarray
Booleans: the symbol has an exposure to every factor it needs; its row is not meaningful otherwise.
Examples
>>> matrix, covered = model.exposure_matrix(style.compute(day, day).isel(timestamp=0)) >>> matrix.shape[1] == len(model.factor_names) True
- abstract property exposure_names#
The outputs of the exposures factor the model reads (the estimation universe aside).
Examples
>>> model.exposure_names[-1] 'industry'
- exposures(start, end)[source]#
Return the exposure variables from
starttoend, read or computed.- Parameters:
- start, endstr, datetime.date or pd.Timestamp
The range, both inclusive.
- Returns:
- xr.Dataset
The exposures factor’s
exposure_namesand, when the config names one, its estimation-universe flag, read from its store or computed perexposure_data_strategy.
Examples
>>> list(model.exposures("2024-01-02", "2024-01-31").data_vars)[-2:] ['industry', 'estu']
- factor_groups()[source]#
Return each factor’s group, one of
FACTOR_GROUPS, keyed by factor name.The factor attribution of a backtest (
quantlab.risk.attribution) sums its factors’ contributions and risk by group. By default every factor is a"style"; a model with a country (market) factor or industry factors says so by overriding this method.- Returns:
- dict
{factor: group}infactor_namesorder.
Examples
>>> set(model.factor_groups().values()) <= set(FACTOR_GROUPS) True >>> model.factor_groups()["country"] # a Use4RiskModel 'country'
- factor_labels()[source]#
Return each factor’s display name, keyed by factor name.
The backtest report names factors by these labels (stored as the
labelcoordinate of a backtest’s factor attribution). By default a factor is labelled by its name; a model with coded factor names (industry_34) overrides this method.- Returns:
- dict
{factor: label}infactor_namesorder.
Examples
>>> list(model.factor_labels()) == list(model.factor_names) True >>> model.factor_labels()["industry_34"] # a Use4RiskModel 'Business Services'
- abstract property factor_names#
The
factoraxis of both stores.Examples
>>> model.factor_names[:2] ('country', 'industry_1')
- forecast(estimate, exposures)[source]#
Return the forecast at one bar from its estimate row and the exposures at the bar.
The one coverage rule of the model’s forecasts. A symbol of
exposuresis covered whenexposure_matrixgives it every exposure, finite on the kept factors, and the row a specific risk. A factor without a covariance at the bar (covered_factors: no variance, or too few common bars with another) is left out of the forecast, and so is every symbol exposed to it.- Parameters:
- estimatexr.Dataset
The estimate store’s row at the bar (
factor_covarianceon(factor_i, factor_j),specific_riskonsymbol), asestimate.read(t, t).isel(timestamp=0)gives it and a decision’s context carries it (PortfolioContext.risk_estimate).- exposuresxr.Dataset
The exposures at the bar on
symbol(exposure_names), asexposures(t, t)gives them: the symbols the forecast may cover, in its order. The caller chooses them, so a decision can be handed exposures an executor injects.
- Returns:
- FactorRiskForecast
Examples
>>> row = model.estimate.read(day, day).isel(timestamp=0) >>> forecast = model.forecast(row, model.exposures(day, day).isel(timestamp=0)) >>> set(forecast.factor_names) <= set(model.factor_names) True
- forecast_window(timestamps, forecasts_through=None)[source]#
Return each bar’s outcome beside the forecast inputs of the bar before it.
Row
iholds the regression store’sfactor_returnandspecific_returnoftimestamps[i], and, oftimestamps[i - 1]: the estimate store’sfactor_covarianceandspecific_risk, the exposures (exposures), the risk-free rate (risk_free) and market cap (market_cap) fromprices, andestimation_universe(the estimation-universe flag, every symbol withoutestu_name). That is the forecast made at the bar before and what the bar then did. Row 0 has no forecast inputs (NaN). A row is whatforecastreads, as both its arguments.- Parameters:
- timestampsarray-like of datetime64
Consecutive bars, in order: a backtest’s, or the regression store’s.
- forecasts_throughdatetime-like, optional
The last bar whose forecast is needed: the estimate rows after it are not read (NaN), so the estimate store need not reach the outcomes of a multi-bar horizon. Every bar before the last by default.
- Returns:
- xr.Dataset
On
timestamps,symbol,factorandfactor_i/factor_j.
- Raises:
- ValueError
As
require_window, or if the exposures or prices do not cover the bars before the last.
Examples
>>> window = model.forecast_window(bars) >>> forecast = model.forecast(window.isel(timestamp=5), window.isel(timestamp=5))
- prices(start, end)[source]#
Return price, market cap and risk-free rate on the bars with a price.
With
risk_free_symbolthe rate is that symbol’s, forward-filled and broadcast across the others, and the symbol is dropped.- Parameters:
- start, endstr, datetime.date or pd.Timestamp
The range, both inclusive.
- Returns:
- xr.Dataset
price_column,market_cap_columnandrisk_free_columnon(timestamp, symbol), only the bars where some symbol has a price.
Examples
>>> model.prices("2024-01-02", "2024-01-31")[model.config.market_cap_column].dims ('timestamp', 'symbol')
- property regression#
The regression store: realized factor and specific returns (see the class docstring).
Examples
>>> model.regression.build("2024-01-01", "2024-03-31").store_range() ('2024-01-01', '2024-03-31')
- abstract property regression_warmup_bars#
Bars before a range
_compute_regressionreads.Examples
>>> model.regression_warmup_bars 1
- require_window(timestamps, forecasts_through=None)[source]#
Refuse bars the stores cannot serve: the outcome and forecast rows of
forecast_window.Reads lazily, so it is cheap enough to call before a backtest simulates.
- Parameters:
- timestampsarray-like of datetime64
The bars, in order.
- forecasts_throughdatetime-like, optional
The last bar whose forecast is needed; every bar before the last by default.
- Raises:
- ValueError
If the regression store does not cover the bars, or the estimate store the forecast bars (
RiskStore.read).
Examples
>>> model.require_window(bars) # stores built over the bars
- store_uses()[source]#
Return the model’s own stores, owned and written by date range: regression, then estimate.
Each is declared
"owns"with itsRiskStoreas the handle. The order is the order they are extended in, the estimate being computed from the regression store; the exposures factor and the datasets declare their own stores (seeComponent.store_uses). A store whose path the config leaves unset is left out.Examples
>>> [(use.relation, use.handle.part) for use in model.store_uses()] [('owns', 'regression'), ('owns', 'estimate')]