quantlab.factor.kunquant_cs.CrossSectionalNeutralize#
- class quantlab.factor.kunquant_cs.CrossSectionalNeutralize(y, size, industry, w=None, universe=None, use_industry=True, use_size=True)[source]#
Bases:
_IndustrySizeRegressionNeutralize
yagainst industry, size or both: its residual from a per-bar regression.The regression is
CrossSectionalIndustrySizeFill’s: on each bar, over the symbols whereuniverse > 0,yis finite,wis finite and positive and the regressors used are present (industryan integer code from 0 to 4096; any other code counts as missing), one intercept per industry plus a common slope onsize, by weighted least squares. Every symbol with a finitey, inside the universe or not, gets:out = y - intercept[industry] - b * size
The residual has zero weighted sum within each industry and zero weighted covariance with
sizeover the fit sample. It is NaN whereyis missing or infinite, where a regressor used is missing, and where the symbol’s industry has no fit member: a neutralized panel has no value that was left as it was.use_size=Falseneutralizes against industry alone (the weighted industry mean is subtracted);use_industry=Falseagainst size alone, with one common intercept.Unlike
CrossSectionalWLSResidual, a bar wheresizedoes not vary (within the industries, below 1e-10 of its spread) is not NaN: the residual of a least-squares fit is unique even then, and the slope is taken as 0. A symbol alone in its industry in the fit sample is left with a residual of 0. The output is not re-standardized; follow it withCrossSectionalZScorefor that.wanduniverseare optional: withoutwthe fit is ordinary least squares, withoutuniverseit uses every symbol. Leave them out rather than passing a constant: KunQuant merges equal expressions, so the same node passed twice to one cross-sectional op (a constant 1 as bothwanduniverse) reaches the C++ as one input and the op does not compile. Each set of flags and optional inputs gets a class of its own (CrossSectionalNeutralize_industry_size,CrossSectionalNeutralize_industry_size_w_universe);isinstancestill holds. The batch-start and SIMD-width notes ofCrossSectionalZScoreapply.- Parameters:
- yOpBase
The values to neutralize, such as an alpha factor.
- sizeOpBase
The size regressor, such as the log of market cap. Ignored, but still required, with
use_size=False.- industryOpBase
The industry code, a non-negative integer stored as a float. Ignored, but still required, with
use_industry=False.- wOpBase, optional
The regression weights, such as the square root of market cap as a Barra-style model weighs. Without it, every symbol weighs 1.
- universeOpBase, optional
A mask, positive for the symbols the fit uses. Without it, the fit uses every symbol.
- use_industry, use_sizebool, default True
Which regressors the model has; at least one.
- Raises:
- ValueError
If both flags are false.
Examples
Industry and size neutral by ordinary least squares over every symbol, then size neutral alone:
>>> cap = Input("marketcap") >>> Output(CrossSectionalNeutralize(alpha, Log(cap), Input("industry")), "alpha_neutral") >>> Output(CrossSectionalNeutralize(alpha, Log(cap), ConstantOp(0.0), use_industry=False), ... "alpha_size_neutral")
Weighted by the square root of market cap and fitted on an estimation universe, as Barra does:
>>> Output(CrossSectionalNeutralize(alpha, Log(cap), Input("industry"), Sqrt(cap), estu), "alpha_barra_neutral")