Cross-Sectional Regression: private API
Types
PortfolioOptimisers.AbstractCrossSectionalSolveAlgorithm — Type
abstract type AbstractCrossSectionalSolveAlgorithm <: AbstractRegressionAlgorithmAbstract supertype for all cross-sectional solve algorithm types.
A member decides what CrossSectionalLinearRegression does when the weighted design of an observation is rank deficient, and the members differ on two axes: whether a rank test runs at all, and what happens when it fails. The decision is a real one, because Julia's \ answers a deficient design in three different ways. A square design goes to an LU factorisation that throws LinearAlgebra.SingularException on an exactly zero pivot. A non-square one goes to a column-pivoted QR whose solve completes the orthogonal factorisation, so it returns the minimum-norm solution and agrees with a pseudo-inverse. A design that is only nearly dependent passes the rank test of every member and returns a badly conditioned answer that a pseudo-inverse would truncate.
Related
Functions
PortfolioOptimisers.cross_sectional_design_mask — Function
cross_sectional_design_mask(
Z::AbstractArray{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}, 3},
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
W::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}
) -> BitMatrix
Return the eligibility mask of a cross-sectional design, after checking its three arrays.
An (observation, asset) pair is eligible when its cross-sectional weight is positive. The weight is the one contract: a pair excluded by a zero weight may carry a missing return or a missing exposure, and a pair with a positive weight may not.
Arguments
Z::Arr3Num: Exposure tensorobservations × assets × factors.X::MatNum: Asset returns matrixobservations × assets.W::MatNum: Cross-sectional weights matrixobservations × assets.
Validation
!isempty(Z),!isempty(X)and!isempty(W).size(Z, 1) == size(X, 1)andsize(Z, 2) == size(X, 2).size(W) == size(X).all(isfinite, W)andall(x -> x >= 0, W).- Every pair with a positive weight carries a finite return and finite exposures. The
IsNonFiniteErrornames the observation, the asset and the weight.
Returns
act::BitMatrix: Eligibility maskobservations × assets, true where the weight is positive.
Related
PortfolioOptimisers.cross_sectional_coefficients — Function
cross_sectional_coefficients(
cre::CrossSectionalLinearRegression,
A::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
y::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
w::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
t::Integer
) -> Any
Return the factor returns of one observation, through the member's own solve.
CrossSectionalLinearRegression scales the design and the target by sqrt.(w) and hands them to cross_sectional_solve. CrossSectionalTargetRegression hands the unscaled pair to the target, with w as the observation weights, and refuses an empty cross-section.
Arguments
cre: Cross-sectional regression estimator.A::MatNum: Exposures of the eligible assets,eligible assets × factors, already demeaned when an intercept is fitted.y::VecNum: Returns of the eligible assets, already demeaned when an intercept is fitted.w::VecNum: Cross-sectional weights of the eligible assets.t::Integer: Index of the observation.
Validation
- Under
CrossSectionalTargetRegression,!isempty(y). An external target has no cross-section to fit when no asset is eligible, and theArgumentErrornames the observation.
Returns
f::VecNum: Factor returns of the observation, of lengthsize(A, 2).
Related
PortfolioOptimisers.cross_sectional_rank — Function
cross_sectional_rank(
A::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}
) -> Int64
Return the numerical rank of A, read off the diagonal of a column-pivoted QR.
The test is written out rather than delegated to LinearAlgebra.rank(::QRPivoted), which needs Julia 1.12 while this package supports 1.11.
Algorithm
- Return
0whenAhas no row or no column, because a factorisation of it has no pivot to read. - Take the column-pivoted
LinearAlgebra.qrofA. The magnitudes of the diagonal of itsRare non-increasing, so they rank the columns by how much each adds to the span. - Count the leading diagonal entries above
min(size(A)...) * eps(real(eltype(R))) * abs(R[1, 1]), giving the numerical rank. The tolerance is the oneLinearAlgebra.rankapplies to a pivotedQR.
Arguments
A::MatNum: Weighted design of one observation,eligible assets × factors.
Returns
r::Int: Numerical rank ofA.
Related
PortfolioOptimisers.cross_sectional_solve — Function
cross_sectional_solve(alg::AbstractCrossSectionalSolveAlgorithm, A::MatNum, y::VecNum,
t::Integer) -> VecNumSolve the weighted design A against the weighted target y through the branch alg selects.
Algorithm
UncheckedSolvereturnsA \ y, with no rank test.MinimumNormSolvereturnsLinearAlgebra.pinv(A) * y, with no rank test.PseudoInverseFallbacktakescross_sectional_rank. It returnsA \ ywhen the rank equals the factor count, andLinearAlgebra.pinv(A) * yotherwise.RankDeficiencyRefusaltakescross_sectional_rank, refuses when the rank falls short of the factor count, and returnsA \ yotherwise.
Arguments
alg: Cross-sectional solve algorithm.A::MatNum: Weighted design of one observation,eligible assets × factors.y::VecNum: Weighted target of one observation, of lengtheligible assets.t::Integer: Index of the observation, named by the refusal ofRankDeficiencyRefusal.
Validation
- Under
RankDeficiencyRefusal, the rank ofAequalssize(A, 2). TheArgumentErrornames the observation, the rank, the factor count and the count of eligible assets.
Returns
f::VecNum: Factor returns of the observation, of lengthsize(A, 2).
Related
PortfolioOptimisers.cross_sectional_systematic — Function
cross_sectional_systematic(f::MatNum, b::Option{<:VecNum}, Z::Arr3Num) -> MatNumReturn the systematic part of a cross-sectional regression, observations × assets.
Mathematical definition
\[\begin{align} \hat{x}_{t,i} &= b_{t} + \boldsymbol{z}_{t,i}^{\intercal} \boldsymbol{f}_{t}\,. \end{align}\]
Where:
- $\hat{x}_{t,i}$: Systematic return of asset $i$ at observation $t$.
- $\boldsymbol{z}_{t,i}$: Exposures of asset $i$ at observation $t$.
- $\boldsymbol{f}_{t}$: Factor returns of observation $t$.
- $b_{t}$: Intercept of observation $t$. The term is zero when no intercept was fitted.
Arguments
f::MatNum: Factor returns matrixobservations × factors.b::Option{<:VecNum}: Intercept vector, ornothingwhen none was fitted.Z::Arr3Num: Exposure tensorobservations × assets × factors. The asset axis may differ from the one the fit saw; the observation and factor axes may not.
Validation
size(Z, 1) == size(f, 1)andsize(Z, 3) == size(f, 2).
Returns
Xh::MatNum: Systematic returns,observations × assets.
Related