Regime Adjusted Exponential Weighted Covariance (a)
Types
PortfolioOptimisers.RegimeAdjustedTarget — Type
abstract type RegimeAdjustedTarget <: AbstractAlgorithmAbstract supertype for all regime-adjustment target structures used in RegimeAdjustedExpWeightedCovariance.
A target defines how the regime-adjusted covariance update is structured (e.g., which baseline covariance form is shrunk toward).
Interfaces
In order to implement a new regime-adjustment target, subtype RegimeAdjustedTarget and optionally implement min_active_assets.
min_active_assets interface
min_active_assets(target::RegimeAdjustedTarget) -> Int: Returns the minimum number of active assets required to use this target. Defaults to1.
Arguments
target: The concrete target instance.
Returns
n::Int: Minimum required active assets.
Examples
julia> struct MyTarget <: PortfolioOptimisers.RegimeAdjustedTarget endjulia> PortfolioOptimisers.min_active_assets(MyTarget())1Related
PortfolioOptimisers.MahalanobisTarget — Type
struct MahalanobisTarget <: RegimeAdjustedTargetRegime-adjustment target that uses a Mahalanobis-distance-based baseline covariance structure. Requires at least two active assets.
Related
PortfolioOptimisers.DiagonalTarget — Type
struct DiagonalTarget <: RegimeAdjustedTargetTargets the diagonal of a covariance matrix, in a regime adjustment and in a geodesic shrinkage.
In a regime adjustment, the baseline covariance structure is diagonal, so the regime statistic reads the variances alone. In a GeodesicShrinkageCovariance, the target matrix is the diagonal of the matrix being shrunk, which keeps the variances and removes every correlation.
Related
RegimeAdjustedTargetMahalanobisTargetPortfolioTargetRegimeAdjustedExpWeightedCovarianceGeodesicShrinkageCovarianceAbstractCovarianceShrinkageTarget: the other target rules of a geodesic shrinkage.
PortfolioOptimisers.PortfolioTarget — Type
struct PortfolioTarget{__T_w} <: RegimeAdjustedTargetRegime-adjustment target that uses a portfolio-weighted baseline covariance structure.
Fields
w: Optional portfolio weights for the portfolio target, as one vector over the assets or as a matrix whose rows are portfolios. Ifnothing, inverse-volatility weights are used, and they are rebuilt from the running variance at each observation.
Constructors
PortfolioTarget(; w::Option{<:Union{<:VecNum, <:MatNum}} = nothing) -> PortfolioTargetKeywords correspond to the struct's fields. The bound is the pair of shapes the fit can honour, because Statistics.cov(ce::RegimeAdjustedExpWeightedCovariance, X::MatNum; dims::Int = 1, estimation_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, active_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, kwargs...) reads a bare matrix and carries no asset names. The count of assets, the sign of each weight and the sum of each row are checked at the fit, where the universe is known.
Validation
- If
wis notnothing,!isempty(w).
Examples
julia> PortfolioTarget()PortfolioTarget w ┴ nothingRelated
PortfolioOptimisers.RegimeAdjustedExpWeightedCovariance — Type
struct RegimeAdjustedExpWeightedCovariance{__T_decay, __T_cor_decay, __T_min_obs, __T_hac_lags, __T_regime_method, __T_regime_decay, __T_regime_min_obs, __T_regime_target, __T_regime_lohi_mult, __T_min_val, __T_centred, __T_cache} <: AbstractCovarianceEstimatorOnline exponentially weighted covariance estimator with regime-state adjustment.
At each observation it updates a running exponentially weighted covariance, and it forms a one-step-ahead statistic that compares the realised risk of that observation against the risk the state predicted before it. The statistic is smoothed by regime_decay into a scalar regime state, and the covariance is scaled by the square of the multiplier that state names.
The estimator is the covariance twin of RegimeAdjustedExpWeightedVariance. It shares that type's RegimeAdjustedMethod family, and it adds a RegimeAdjustedTarget, which states what the statistic measures: one portfolio direction, the marginal volatilities alone, or the whole covariance structure.
This estimator is mask-aware, so a prior fitted with it keeps a young asset investable and zero-fills the rows the asset was missing through scenario_fill: every consumer of a Prior Result reads its returns matrix, and a scenario-based measure then reads a zero return where the asset had none and understates that asset's risk over those rows, while the covariance stays the estimate this recursion made from the rows it saw. The fill is silent at or below the fitting prior's own fill_limit field, a share of that asset's own observations, warns above it, and refuses any fill under strict; fill_limit defaults to nothing, and this family carries no CoveragePolicy to derive a limit from, so every fill is named.
A regime_method of nothing turns the adjustment off: no regime state advances, so the multiplier stays at one and the estimator is the plain exponentially weighted recursion.
Mathematical definition
Write $\lambda$ for decay and $\lambda_c$ for cor_decay. Where cor_decay is nothing, one recursion carries the whole matrix:
\[\begin{align} S_{t} &= \lambda S_{t-1} + (1-\lambda) \boldsymbol{u}_{t} \boldsymbol{u}_{t}^{\intercal}\,. \end{align}\]
Where:
- $S_{t}$: Raw exponentially weighted covariance state at time $t$, seeded at zero.
- $\boldsymbol{u}_{t}$: Observation $t$, centred where
centredisfalse, and HAC-adjusted wherehac_lagsis notnothing.
Where cor_decay is not nothing, the variance and the correlation run at their own decays and are recombined:
\[\begin{align} v_{i,t} &= \lambda v_{i,t-1} + (1-\lambda) u_{i,t}^{2}\,, \\ Q_{ij,t} &= \lambda_c Q_{ij,t-1} + (1-\lambda_c) \frac{u_{i,t} u_{j,t}}{\sqrt{v_{i,t} v_{j,t}}}\,, \\ \rho_{ij,t} &= \frac{Q_{ij,t}}{\sqrt{Q_{ii,t} Q_{jj,t}}}\,. \end{align}\]
Where:
- $v_{i,t}$: Raw exponentially weighted variance of asset $i$.
- $Q_{ij,t}$: Raw exponentially weighted correlation state. On a holiday of asset $i$, $Q_{ii}$ holds and $Q_{ij}$ decays by $\sqrt{\lambda_c}$, so each correlation $\rho_{ij}$ holds and $Q$ stays positive semidefinite.
- $\rho_{ij,t}$: Correlation, normalised from $Q$.
A zero seed damps the state, so the read-out removes the damping before it reports:
\[\begin{align} \hat{\Sigma}_{ij} &= \mathrm{mult}(s_T)^{2}\, \frac{S_{ij,T}}{\sqrt{(1-\lambda^{n_i})(1-\lambda^{n_j})}}\,. \end{align}\]
Where:
- $\hat{\mathbf{\Sigma}}$: Estimated covariance matrix.
- $n_i$: Count of valid observations of asset $i$. The same correction of $Q$ at $\lambda_c$ cancels in the normalisation to $\rho$, so $Q$ needs none.
- $\mathrm{mult}(s_T)$: Regime multiplier of the smoothed regime state $s_T$, clamped to
regime_lohi_multwhere that field is notnothing.
Fields
decay: Exponential decay factor for the exponentially weighted estimator.
cor_decay: Exponential decay factor for the correlation smoother.
min_obs: Minimum number of observations required before the estimator produces a valid result.
hac_lags: Optional number of lags for Heteroskedasticity and Autocorrelation Consistent (HAC) kernel correction of squared returns. Ifnothing, no HAC correction is applied.
regime_method: Regime adjustment method used to compute the per-observation regime state, ornothingto apply no regime adjustment.
regime_decay: Exponential decay factor for smoothing the regime state.
regime_min_obs: Minimum number of regime observations required before the regime multiplier is applied.
regime_target: Target structure for the regime-adjusted covariance update.
regime_lohi_mult: Optional(lo, hi)tuple bounding the regime multiplier range. Ifnothing, no clamping is applied.
min_val: Minimum threshold to prevent division by zero or degenerate estimates.
centred: Whether to treat the returns as pre-centred (mean zero). Iffalse, the location is estimated online.
cache: Running state of an incremental fit, ornothingbefore the first call topartial_fit!. It is the one Result this estimator holds, and its type bound is the enforcement of that exception.Statistics.cov(ce::RegimeAdjustedExpWeightedCovariance)reads it, and a fit over a matrix ignores it.
Constructors
RegimeAdjustedExpWeightedCovariance(; decay::Number = exp2(-inv(40.0)), cor_decay::Option{<:Number} = nothing, min_obs::Integer = round(Int, max(1, decay_half_life(decay), isnothing(cor_decay) ? 1 : decay_half_life(cor_decay, :cor_decay))), hac_lags::Option{<:Integer} = nothing, regime_method::Option{<:RegimeAdjustedMethod} = FirstMomentRegimeAdjusted(), regime_decay::Number = exp2(-2 / decay_half_life(decay)), regime_min_obs::Integer = round(Int, max(1, decay_half_life(decay) / 2)), regime_target::RegimeAdjustedTarget = PortfolioTarget(), regime_lohi_mult::Option{<:Tuple{<:Number, <:Number}} = nothing, min_val::Number = sqrt(eps()), centred::Bool = false, cache::Option{<:AbstractPartialFitState} = nothing) -> RegimeAdjustedExpWeightedCovarianceKeywords correspond to the struct's fields. Where cor_decay is not nothing, the default min_obs reads the slower of the two decays.
Validation
0 < decay < 1.- If
cor_decayis notnothing,0 < cor_decay < 1. min_obs > 0andregime_min_obs > 0.- If
hac_lagsis notnothing,hac_lags > 0. - If
regime_lohi_multis notnothing,0 < regime_lohi_mult[1] < regime_lohi_mult[2].
Examples
julia> ce = RegimeAdjustedExpWeightedCovariance();julia> ce.decay ≈ exp2(-inv(40.0))truejulia> isnothing(ce.cor_decay)trueRelated
Functions
PortfolioOptimisers.min_active_assets — Function
min_active_assets(_::RegimeAdjustedTarget) -> Int64
Returns the minimum number of active assets required for this regime-adjustment target.
Arguments
::RegimeAdjustedTarget: Regime-adjustment target (unused by this default method).
Returns
1::Int: The default minimum is one active asset.
Related
min_active_assets(_::MahalanobisTarget) -> Int64
Returns the minimum number of active assets required for the Mahalanobis target.
Arguments
::MahalanobisTarget: Mahalanobis regime-adjustment target (unused).
Returns
2::Int: At least two active assets are required.
Related