Cross-Sectional Factor Model: private API
Functions
PortfolioOptimisers.assert_idiosyncratic_covariance — Function
assert_idiosyncratic_covariance(esigma::Nothing, N::Integer)
assert_idiosyncratic_covariance(esigma::VecNum, N::Integer)
assert_idiosyncratic_covariance(esigma::MatNum, N::Integer)Check the idiosyncratic covariance of a CrossSectionalFactorModel against the asset count N.
The idiosyncratic covariance takes either of two shapes, and the shape is the dispatch rather than a branch: a vector holds the idiosyncratic variances alone, and a matrix holds the full covariance an idiosyncratic correlation threshold produces. An absent covariance is checked by the method over Nothing, so no caller writes an isnothing test.
Arguments
esigma: Idiosyncratic covariance, a vector of variances, a square matrix, ornothing.N: Number of assets the model carries.
Validation
!isempty(esigma).length(esigma) == Nwhenesigmais a vector.esigmais square, andsize(esigma, 1) == N, whenesigmais a matrix.
Returns
nothing.
Related
PortfolioOptimisers.idiosyncratic_covariance_view — Function
idiosyncratic_covariance_view(esigma::Nothing, i)
idiosyncratic_covariance_view(esigma::VecNum, i)
idiosyncratic_covariance_view(esigma::MatNum, i)Return a view of an idiosyncratic covariance, selecting only the assets indexed by i.
The shape is the dispatch, as it is in assert_idiosyncratic_covariance: a vector of variances is indexed once, and a full covariance matrix is indexed on both of its axes, which keeps the selected block square.
Arguments
esigma: Idiosyncratic covariance, a vector of variances, a square matrix, ornothing.i: Indices of the assets to select.
Returns
esigma::Option{<:VecNum_MatNum}: A view over the selected assets, ornothingwhen the model carries no idiosyncratic covariance.
Examples
julia> PortfolioOptimisers.idiosyncratic_covariance_view([1.0, 2.0, 3.0], [1, 3])2-element view(::Vector{Float64}, [1, 3]) with eltype Float64: 1.0 3.0julia> PortfolioOptimisers.idiosyncratic_covariance_view([1.0 0.0; 0.0 2.0], [2])1×1 view(::Matrix{Float64}, [2], [2]) with eltype Float64: 2.0Related
PortfolioOptimisers.idiosyncratic_variances — Method
idiosyncratic_variances(rr::AbstractLoadingsRegressionResult)
idiosyncratic_variances(esigma::VecNum, rr::AbstractLoadingsRegressionResult)
idiosyncratic_variances(esigma::MatNum, rr::AbstractLoadingsRegressionResult)
idiosyncratic_variances(esigma::Nothing, rr::Regression)
idiosyncratic_variances(esigma::Nothing, rr::CrossSectionalFactorModel)Read the idiosyncratic variance vector off a loadings block, whatever shape the block stores it in.
Both members of AbstractLoadingsRegressionResult carry esigma under one name, and both admit the two shapes: a vector of variances, or a full covariance. A consumer that needs the variances alone — an AbstractUncertaintySetEstimator that weights the cross-section by the inverse idiosyncratic variance is the first one — asks for them here rather than testing the shape at its own site.
The shape is the dispatch, as it is in assert_idiosyncratic_covariance and idiosyncratic_covariance_view. The one-argument entry reads the field and forwards it beside the block, so the two refusals name the block they came from: a Regression is filled by the prior that lifts the factor moments, so its message names rsd, and a CrossSectionalFactorModel is filled by its own fit, so its message names the field.
There is no fallback. A block that carries no idiosyncratic covariance cannot answer, and an answer of ones or of zeros is a different weighting rather than a missing one.
Arguments
esigma: Idiosyncratic covariance, a vector of variances, a square matrix, ornothing.rr: The loadings block the field was read from, which the raise reports.
Validation
!isnothing(esigma), raising anIsNothingError.
Returns
esigma::VecNum: The idiosyncratic variances, one per asset. A vector comes back unchanged, and a matrix comes back as its diagonal.
Examples
julia> re = Regression(; M = [1.0 2.0; 3.0 4.0], esigma = [0.1, 0.2]);julia> PortfolioOptimisers.idiosyncratic_variances(re)2-element Vector{Float64}: 0.1 0.2Related
PortfolioOptimisers.cs_history_assets — Function
cs_history_assets(A::Nothing, N::Integer, sym::Symbol)
cs_history_assets(A::MatNum, N::Integer, sym::Symbol)Check the asset axis of an optional per-asset history of a CrossSectionalFactorModel, and return its observation count.
A per-asset history holds one row per observation and one column per asset, so the asset axis is the second one. The count comes back so that the caller pins the observation axis of two histories against each other with assert_cs_history_obs and needs no isnothing test of its own.
Arguments
A: A per-asset history, ornothing.N: Number of assets the model carries.sym: Name of the field, which the raise reports.
Validation
!isempty(A).size(A, 2) == N.
Returns
T::Option{<:Integer}: The observation count ofA, ornothingwhenAis absent.
Related
PortfolioOptimisers.assert_cs_history_obs — Function
assert_cs_history_obs(a::Option{<:Integer}, b::Option{<:Integer}, asym::Symbol, bsym::Symbol)
assert_cs_history_obs(a::Integer, b::Integer, asym::Symbol, bsym::Symbol)Check that two per-asset histories of a CrossSectionalFactorModel agree on the observation axis.
A history that the model does not carry constrains nothing, so the pair is checked only when cs_history_assets returned a count for both.
Arguments
a: Observation count of the first history, ornothing.b: Observation count of the second history, ornothing.asym: Name of the first field, which the raise reports.bsym: Name of the second field, which the raise reports.
Validation
a == b, when both counts are present.
Returns
nothing.
Related
PortfolioOptimisers.assert_exposure_history — Function
assert_exposure_history(Ms::Nothing, N::Integer, K::Integer)
assert_exposure_history(Ms::Arr3Num, N::Integer, K::Integer)Check the exposure history of a CrossSectionalFactorModel against the asset count N and the factor count K.
The exposure history holds one slice per observation, and a slice has the shape of the loadings matrix, so its second and third axes are the asset axis and the factor axis.
Arguments
Ms: An exposure historyobservations × assets × factors, ornothing.N: Number of assets the model carries.K: Number of raw factors the model carries.
Validation
!isempty(Ms).size(Ms, 2) == N.size(Ms, 3) == K.
Returns
nothing.
Related
PortfolioOptimisers.assert_cs_regression_assets — Function
assert_cs_regression_assets(csr::Nothing, N::Integer)
assert_cs_regression_assets(csr::CrossSectionalRegression, N::Integer)Check the asset axis of the fit a CrossSectionalFactorModel nests against the asset count N.
The residuals of a CrossSectionalRegression hold one row per observation and one column per asset, so the asset axis is the second one, as it is for every per-asset history of the model.
Arguments
csr: The nested cross-sectional regression result, ornothing.N: Number of assets the model carries.
Validation
size(csr.eps, 2) == N.
Returns
nothing.
Related
PortfolioOptimisers.assert_return_forecast_assets — Function
assert_return_forecast_assets(rf::Nothing, N::Integer)
assert_return_forecast_assets(rf::AbstractReturnForecastResult, N::Integer)Check the Return Forecast of a CrossSectionalFactorModel against the asset count N.
A model carries the Return Forecast its prior fitted, or nothing, and the absent case is the method over Nothing. The check reads the two fields every member of the family answers, mu and hist, and never the member's own fields, so a new member needs no new method here.
Arguments
rf: Return Forecast Result, ornothing.N: Number of assets the model carries.
Validation
length(rf.mu) == N.- The rules of
cs_history_assetsonrf.hist.
Returns
nothing.
Related
PortfolioOptimisers.has_family_rebasis — Method
has_family_rebasis(csfm::CrossSectionalFactorModel) -> Bool
State whether the model was fitted in a re-based factor family.
L and fcb are present together and absent together, and the pair is present exactly when a Factor Family was re-based before the fit. The answer is therefore the presence of L, read with getfield rather than through property access: the swap(L, M) rule of CrossSectionalFactorModel makes csfm.L return csfm.M when L is unset, so a property read would answer true for every model.
Arguments
csfm: A cross-sectional factor model result.
Returns
val::Bool:truewhenLis set, so the raw factor axis ofMis a linear image of the re-based one and a factor covariance stated on it is singular;falsewhen the fit ran in the raw basis.
Examples
julia> PortfolioOptimisers.has_family_rebasis(CrossSectionalFactorModel(; M = [1.0 2.0; 3.0 4.0], b = [0.1, 0.2]))falsejulia> fcb = FactorFamilyBasis(; fnm = ["f"], fi = [[1, 2]], di = [2], ratios = reshape([1.0], 1, 1), K = 2);julia> PortfolioOptimisers.has_family_rebasis(CrossSectionalFactorModel(; M = [1.0 2.0; 3.0 4.0], L = reshape([1.0, 2.0], 2, 1), b = [0.1, 0.2], fcb = fcb))trueRelated