Regime Adjusted Exponential Weighted Variance
Types
PortfolioOptimisers.RegimeAdjustedMethod — Type
abstract type RegimeAdjustedMethod <: AbstractEstimatorAbstract supertype for all regime adjustment methods.
All concrete subtypes should subtype RegimeAdjustedMethod and implement the regime_multiplier interface.
Interfaces
In order to implement a new regime adjustment method that works seamlessly with the library, subtype RegimeAdjustedMethod and implement the following method:
regime_multiplier interface
regime_multiplier(method::RegimeAdjustedMethod, regime_state::Number) -> Number: Computes the variance scaling multiplier from the smoothed regime state.
Arguments
method: The concrete regime adjustment method instance.regime_state::Number: The current smoothed regime state value.
Returns
mult::Number: The multiplicative scaling factor applied to the variance.
Examples
julia> struct MyRegimeMethod <: PortfolioOptimisers.RegimeAdjustedMethod endjulia> function PortfolioOptimisers.regime_multiplier(::MyRegimeMethod, s::Number) return abs(s) endjulia> PortfolioOptimisers.regime_multiplier(MyRegimeMethod(), -1.5)1.5Related
PortfolioOptimisers.LogRegimeAdjusted — Type
struct LogRegimeAdjusted{__T_x, __T_y, __T_kappa} <: RegimeAdjustedMethodRegime adjustment method that scales variance exponentially with the smoothed log-deviation of standardised squared returns from its expected value under stationarity.
Mathematical definition
The regime state $s$ is defined as $\bar{s} = \frac{1}{T}\sum_t \ln\max(z_t^2, \varepsilon) - \kappa$, where $\kappa = \psi(x) + \ln y$ ($\psi$ = digamma) is the stationary expectation of $\ln z^2$ under a $\chi^2(1)$ distribution scaled by $y$, and $\varepsilon$ is a small positive threshold.
\[\begin{align} \kappa &= \psi(x) + \ln y\,, \\ s &= \frac{1}{T}\sum_{t} \ln\!\max(z_t^2, \varepsilon) - \kappa\,, \\ \mathrm{mult} &= \exp(x \cdot s)\,. \end{align}\]
Where:
- $\kappa$: Stationary expectation of $\ln z^2$ under the specified distribution.
- $\psi$: Digamma function.
- $x$, $y$: Parameters of
LogRegimeAdjusted. - $s$: Smoothed log-deviation regime state.
- $T$: Number of observations.
- $z_t^2$: Standardised squared return at time $t$.
- $\varepsilon$: Small positive threshold for numerical stability.
- $\mathrm{mult}$: Variance scaling multiplier.
Fields
x: Shape parameter of the log regime adjustment.
y: Scale parameter of the log regime adjustment.
kappa: Precomputed normalisation constantdigamma(x) + log(y)for the log regime adjustment.
Constructors
LogRegimeAdjusted(; x::Number = 0.5, y::Number = 2.0) -> LogRegimeAdjustedKeywords correspond to the struct's fields. The kappa field is derived from x and y and cannot be set directly.
Validation
xis valid (i.e.,x >= 0, finite, and non-empty).yis valid (i.e.,y >= 0, finite, and non-empty).
Examples
julia> LogRegimeAdjusted()LogRegimeAdjusted x ┼ Float64: 0.5 y ┼ Float64: 2.0 kappa ┴ Float64: -1.2703628454614782Related
PortfolioOptimisers.FirstMomentRegimeAdjusted — Type
struct FirstMomentRegimeAdjusted{__T_x} <: RegimeAdjustedMethodRegime adjustment method that scales variance by the ratio of the mean absolute deviation of standardised returns to the first-moment normalisation constant x.
Mathematical definition
The regime state $s$ and multiplier are:
\[\begin{align} s &= \frac{1}{x} \cdot \frac{1}{T}\sum_t \sqrt{\max(z_t^2, 0)}\,, \\ \mathrm{mult} &= s\,. \end{align}\]
Where:
- $s$: Regime state (ratio of mean absolute deviation to normalisation constant $x$).
- $x = \sqrt{2/\pi}$: Expected value of $|z|$ for a standard normal $z$.
- $T$: Number of observations.
- $z_t$: Standardised return at time $t$.
- $\mathrm{mult}$: Variance scaling multiplier.
Fields
x: First-moment normalisation constant for the regime adjustment.
Constructors
FirstMomentRegimeAdjusted(; x::Number = sqrt(2 * inv(π))) -> FirstMomentRegimeAdjustedKeywords correspond to the struct's fields.
Validation
xis valid (i.e.,x >= 0, finite, and non-empty).
Examples
julia> FirstMomentRegimeAdjusted()FirstMomentRegimeAdjusted x ┴ Float64: 0.7978845608028654Related
PortfolioOptimisers.RootMeanSquaredAdjusted — Type
struct RootMeanSquaredAdjusted <: RegimeAdjustedMethodRegime adjustment method that scales variance by the square root of the mean of the standardised squared returns.
Mathematical definition
\[\begin{align} s &= \frac{1}{T}\sum_t z_t^2\,, \\ \mathrm{mult} &= \sqrt{\max(s, 0)}\,. \end{align}\]
Where:
- $s$: Mean of standardised squared returns.
- $T$: Number of observations.
- $z_t$: Standardised return at time $t$.
- $\mathrm{mult}$: Variance scaling multiplier.
Related
PortfolioOptimisers.RegimeAdjustedExpWeightedVariance — Type
struct RegimeAdjustedExpWeightedVariance{__T_decay, __T_min_obs, __T_hac_lags, __T_regime_method, __T_regime_decay, __T_regime_min_obs, __T_regime_lohi_mult, __T_min_val, __T_centred, __T_cache} <: AbstractVarianceEstimatorOnline exponentially weighted variance estimator with regime-state adjustment.
At each observation, it updates a running exponentially weighted variance and computes a standardised squared innovation z². After accumulating enough observations, it smooths a regime state using regime_decay, then scales the final variance by regime_multiplier(regime_method, regime_state)².
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. That is what a consumer needs when it reads a volatility rather than a regime-scaled risk figure, and EWVolatility is the one in the library.
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 variance 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.
Mathematical definition
EWM variance update (decay $\lambda$):
\[\begin{align} v_t &= \lambda v_{t-1} + (1 - \lambda)(r_t - \bar{r})^2\,. \end{align}\]
Standardised innovation:
\[\begin{align} z_t^2 &= (r_t - \bar{r})^2 / v_t\,. \end{align}\]
Regime state smoothed with regime_decay $\lambda_r$ ($g$ defined by RegimeAdjustedMethod):
\[\begin{align} s_t &= \lambda_r s_{t-1} + (1 - \lambda_r) \cdot g(z_t^2)\,. \end{align}\]
Final variance:
\[\begin{align} \hat{\sigma}^2 &= \mathrm{mult}(s_T)^2 \cdot v_T\,. \end{align}\]
When regime_lohi_mult is not nothing, mult(s_T) is clamped to the (lo, hi) range that field gives before the square is taken.
Where:
- $v_t$: Exponentially weighted variance at time $t$.
- $\lambda$: EWM decay parameter (
decayfield). - $r_t$: Return at time $t$.
- $\bar{r}$: Mean return.
- $z_t^2$: Standardised squared innovation $(r_t - \bar{r})^2 / v_t$.
- $s_t$: Smoothed regime state at time $t$.
- $\lambda_r$: Regime decay parameter (
regime_decayfield). - $g(\cdot)$: Regime state transformation (see
RegimeAdjustedMethod). - $\hat{\sigma}^2$: Final regime-adjusted variance.
- $\mathrm{mult}(s_T)$: Variance scaling multiplier (see
RegimeAdjustedMethod). - $T$: Number of observations.
Fields
decay: Exponential decay factor for the exponentially weighted estimator.
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_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.var(ce::RegimeAdjustedExpWeightedVariance)reads it, and a fit over a matrix ignores it.
Constructors
RegimeAdjustedExpWeightedVariance(; decay::Number = exp2(-inv(40.0)), min_obs::Integer = round(Int, max(1, inv(log2(inv(decay))))), hac_lags::Option{<:Integer} = nothing, regime_method::Option{<:RegimeAdjustedMethod} = FirstMomentRegimeAdjusted(), regime_decay::Number = exp2(-2 / inv(log2(inv(decay)))), regime_min_obs::Integer = round(Int, max(1, inv(log2(inv(decay))) / 2)), regime_lohi_mult::Option{<:Tuple{<:Number, <:Number}} = nothing, min_val::Number = sqrt(eps()), centred::Bool = false, cache::Option{<:AbstractPartialFitState} = nothing) -> RegimeAdjustedExpWeightedVarianceKeywords correspond to the struct's fields.
Validation
decay > 0.min_obs > 0.- If
hac_lagsis notnothing,hac_lags > 0. regime_min_obs > 0.- If
regime_lohi_multis notnothing,0 < regime_lohi_mult[1] < regime_lohi_mult[2].
Examples
julia> ce = RegimeAdjustedExpWeightedVariance();julia> ce.decay ≈ exp2(-inv(40.0))truejulia> ce.min_obs40Related
Functions
PortfolioOptimisers.regime_multiplier — Function
regime_multiplier(
method::LogRegimeAdjusted,
regime_state::Number
) -> Any
Computes the variance scaling multiplier for the log regime adjustment method.
Arguments
method::LogRegimeAdjusted: Log regime adjustment method.regime_state::Number: Current smoothed regime state.
Returns
mult::Number: Variance scaling multiplierexp(method.x * regime_state).
Related
regime_multiplier(
_::FirstMomentRegimeAdjusted,
regime_state::Number
) -> Number
Computes the variance scaling multiplier for the first-moment regime adjustment method.
Arguments
::FirstMomentRegimeAdjusted: First-moment regime adjustment method (unused).regime_state::Number: Current smoothed regime state.
Returns
mult::Number: Variance scaling multiplier equal toregime_statedirectly.
Related
regime_multiplier(
_::RootMeanSquaredAdjusted,
regime_state::Number
) -> Any
Computes the variance scaling multiplier for the root-mean-squared regime adjustment method.
Arguments
::RootMeanSquaredAdjusted: Root-mean-squared regime adjustment method (unused).regime_state::Number: Current smoothed regime state.
Returns
mult::Number: Variance scaling multipliersqrt(max(regime_state, 0)).
Related
Statistics.var — Method
Statistics.var(
ce::RegimeAdjustedExpWeightedVariance,
X::MatNum;
dims::Int = 1,
estimation_mask::Option{<:AbstractMatrix{<:Bool}} = nothing,
active_mask::Option{<:AbstractMatrix{<:Bool}} = nothing,
kwargs...
) -> Vector{<:Number}Compute the regime-adjusted exponentially weighted variance for each asset.
Iterates over the observation dimension of X, updating an online variance cache at each step. After processing all observations, applies a bias-correction factor and scales the result by the square of the regime multiplier derived from the smoothed regime state.
Arguments
ce: Regime-adjusted exponentially weighted variance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.dims: Dimension along which to perform the computation.estimation_mask: Optional boolean matrix with the same size asX. When provided, only assets whereestimation_mask[i, :](or[:, i]) istruecontribute to the regime state update for observationi.active_mask: Optional boolean matrix with the same size asX. When provided, assets that become inactive have their variance and observation count reset.kwargs: Additional keyword arguments (ignored).
Validation
dims in (1, 2).- If
estimation_maskis notnothing,size(X) == size(estimation_mask). - If
active_maskis notnothing,size(X) == size(active_mask).
Returns
var::Vector{<:Number}: Per-asset regime-adjusted exponentially weighted variance vector of lengthassets. Assets with fewer thance.min_obsobservations returnNaN.
Related
Statistics.var — Method
Statistics.var(ce::RegimeAdjustedExpWeightedVariance, X::MatNum,
pnl::Option{<:AssetPanel}; dims::Int = 1, kwargs...) -> MatNum
Statistics.std(ce::RegimeAdjustedExpWeightedVariance, X::MatNum,
pnl::Option{<:AssetPanel}; dims::Int = 1, kwargs...) -> MatNum
variance_series(ce::RegimeAdjustedExpWeightedVariance, X::MatNum,
pnl::Option{<:AssetPanel}; dims::Int = 1, kwargs...) -> MatNumTake the whole window, and read the two universe masks of the Asset Panel.
RegimeAdjustedExpWeightedVariance is mask-aware, so it overrides the reduce-and-expand root of its verb. It knows its own warm-up, its freeze on a holiday and its reset on an inactive period, so it emits its own frame over the whole window rather than taking a clean block from coverage_reduction. An asset outside the Coverage Universe therefore keeps a number here, where a plain estimator would carry NaN.
The panel travels as the third positional argument, and this method unpacks it onto the active_mask and estimation_mask keywords the estimator already has. No panel, and a static panel, both give the unmasked path.
Algorithm
- Read the two masks with
panel_moment_masks. - Delegate to the two-argument method with them on its keywords.
Arguments
ce: Covariance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.pnl: OptionalAssetPanel, whose active mask the Coverage Universe of the fit is derived from.nothingmakes the rule finiteness alone.dims: Dimension along which to perform the computation.kwargs...: Additional keyword arguments passed to the two-argument method.
Returns
sigma::MatNum: The variance, or the standard deviation, of every asset of the window.
Related
PortfolioOptimisers.partial_fit! — Method
partial_fit!(
est::Union{AbstractEstimator, CovarianceEstimator},
X::Union{AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}};
dims,
active_mask,
estimation_mask
) -> Any
Folds observations into the sample buffer an estimator carries.
The buffering arm of partial_fit!, and the method every estimator carrying a SampleBufferState reaches. A family that folds exactly writes methods of its own, and each of them narrows the cache type parameter of its own estimator to the state that fold reads, so a buffer never meets them and this method is what remains. The state's type is therefore the whole route, and nothing refuses the step.
It is one method over both arms of the interface rather than two, because the families that refuse the step declare one method over both arms too, and a pair of narrower methods here would be ambiguous against each of them. So the arm is chosen by the type of X inside the body, which is statically resolved at every call site.
A buffer carries the per-observation masks beside the observations, so a CoveragePolicy mask threads through the wrapper as it does through an estimator's own accumulator, and the read-out hands it back to the batch verb. A wrapped estimator folded under a policy therefore answers what a batch fit over the same window under the same policy answers, and the unwrapped and wrapped paths agree.
Algorithm
- Read the buffer out of the
cachefield withassert_sample_buffer, which refuses an estimator that was never wrapped inOnline. - Fold a matrix and its masks through the block arm of
partial_fit!, and a vector and its masks through the single-observation arm. - Rebind
est.cachewithAccessors.@reset, and return the estimator.
Arguments
est: Estimator whose buffer is folded forward.X: Observations to fold. A matrix holds one observation per row whendims == 1, and one per column whendims == 2. A vector is a single observation across the assets, anddimsis ignored.dims: Dimension along which to perform the computation.active_mask: The active mask of the block, of the shape ofX, or of one entry per asset whenXis one observation, ornothing.estimation_mask: The estimation mask, on the same terms asactive_mask.
Validation
estcarries aSampleBufferState. AnArgumentErroris thrown otherwise.- The masks, when they are not
nothing, have the shape ofX. ADimensionMismatchis thrown otherwise. - A buffer holding observations is given the masks it already records. An
ArgumentErroris thrown otherwise. dims in (1, 2).
Returns
est: The estimator, with itscachefield rebound to the buffer after the last observation.
Related
PortfolioOptimisers.partial_fit! — Method
partial_fit!(
est::Union{AbstractEstimator, CovarianceEstimator},
X::Union{AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}};
dims,
active_mask,
estimation_mask
) -> Any
Folds observations into the sample buffer an estimator carries.
The buffering arm of partial_fit!, and the method every estimator carrying a SampleBufferState reaches. A family that folds exactly writes methods of its own, and each of them narrows the cache type parameter of its own estimator to the state that fold reads, so a buffer never meets them and this method is what remains. The state's type is therefore the whole route, and nothing refuses the step.
It is one method over both arms of the interface rather than two, because the families that refuse the step declare one method over both arms too, and a pair of narrower methods here would be ambiguous against each of them. So the arm is chosen by the type of X inside the body, which is statically resolved at every call site.
A buffer carries the per-observation masks beside the observations, so a CoveragePolicy mask threads through the wrapper as it does through an estimator's own accumulator, and the read-out hands it back to the batch verb. A wrapped estimator folded under a policy therefore answers what a batch fit over the same window under the same policy answers, and the unwrapped and wrapped paths agree.
Algorithm
- Read the buffer out of the
cachefield withassert_sample_buffer, which refuses an estimator that was never wrapped inOnline. - Fold a matrix and its masks through the block arm of
partial_fit!, and a vector and its masks through the single-observation arm. - Rebind
est.cachewithAccessors.@reset, and return the estimator.
Arguments
est: Estimator whose buffer is folded forward.X: Observations to fold. A matrix holds one observation per row whendims == 1, and one per column whendims == 2. A vector is a single observation across the assets, anddimsis ignored.dims: Dimension along which to perform the computation.active_mask: The active mask of the block, of the shape ofX, or of one entry per asset whenXis one observation, ornothing.estimation_mask: The estimation mask, on the same terms asactive_mask.
Validation
estcarries aSampleBufferState. AnArgumentErroris thrown otherwise.- The masks, when they are not
nothing, have the shape ofX. ADimensionMismatchis thrown otherwise. - A buffer holding observations is given the masks it already records. An
ArgumentErroris thrown otherwise. dims in (1, 2).
Returns
est: The estimator, with itscachefield rebound to the buffer after the last observation.
Related
Statistics.var — Method
Statistics.var(
ce::RegimeAdjustedExpWeightedVariance,
state::RegimeAdjustedVarianceState;
kwargs...
) -> Vector{<:Number}Read the regime-adjusted variance out of a state held by hand.
This is regime_adjusted_variance under the family's public verb, so a state a caller keeps outside an estimator answers the same call as one the estimator holds. The state is read and never written.
Arguments
ce: Regime-adjusted exponentially weighted variance estimator.state: Running state of an incremental fit.kwargs: Additional keyword arguments (ignored).
Returns
var::Vector{<:Number}: Per-asset regime-adjusted exponentially weighted variance vector of lengthassets. An asset with fewer thance.min_obsobservations isNaN.
Examples
julia> X = [0.01 -0.02; -0.015 0.03; 0.02 -0.01; -0.005 0.012];julia> ce = partial_fit!(RegimeAdjustedExpWeightedVariance(; decay = 0.9, min_obs = 2, regime_min_obs = 2), X);julia> isequal(var(ce, ce.cache), var(ce))trueRelated
Statistics.var — Method
Statistics.var(ce::RegimeAdjustedExpWeightedVariance; kwargs...) -> Vector{<:Number}Read the regime-adjusted variance out of the estimator's own state.
The one-argument form is what an incremental fit answers: partial_fit! leaves the state in the cache field, and this verb turns it into the ordinary answer. An estimator that has been given no observation carries no state, so the call is refused rather than answered with a zero.
Arguments
ce: Regime-adjusted exponentially weighted variance estimator carrying a state.kwargs: Additional keyword arguments (ignored).
Validation
ce.cacheis notnothing. AnArgumentErroris thrown otherwise.
Returns
var::Vector{<:Number}: Per-asset regime-adjusted exponentially weighted variance vector of lengthassets. An asset with fewer thance.min_obsobservations isNaN.
Examples
julia> X = [0.01 -0.02; -0.015 0.03; 0.02 -0.01; -0.005 0.012];julia> ce = partial_fit!(RegimeAdjustedExpWeightedVariance(; decay = 0.9, min_obs = 2, regime_min_obs = 2), X);julia> length(var(ce))2julia> var(RegimeAdjustedExpWeightedVariance())ERROR: ArgumentError: `ce` holds no partial-fit state, so there is nothing to read. Call `partial_fit!(ce, X)` first, or `var(ce, X)` for a fit over a whole sample.[...]Related
partial_fit!(ce::RegimeAdjustedExpWeightedVariance, X::MatNum; dims::Int = 1, estimation_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, active_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, kwargs...)Statistics.var(ce::RegimeAdjustedExpWeightedVariance, state::RegimeAdjustedVarianceState; kwargs...)RegimeAdjustedVarianceState
Statistics.std — Method
Statistics.std(
ce::RegimeAdjustedExpWeightedVariance,
X::MatNum;
dims::Int = 1,
estimation_mask::Option{<:AbstractMatrix{<:Bool}} = nothing,
active_mask::Option{<:AbstractMatrix{<:Bool}} = nothing,
kwargs...
) -> Vector{<:Number}Compute the regime-adjusted exponentially weighted standard deviation for each asset.
The root of Statistics.var(ce::RegimeAdjustedExpWeightedVariance, X::MatNum; dims::Int = 1, estimation_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, active_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, kwargs...). The variance is a non-negative exponentially weighted average scaled by a squared multiplier, so the root is real. An asset that var answers with NaN stays NaN.
Arguments
ce: Regime-adjusted exponentially weighted variance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.dims: Dimension along which to perform the computation.estimation_mask: Optional boolean matrix with the same size asX. When provided, only assets whereestimation_mask[i, :](or[:, i]) istruecontribute to the regime state update for observationi.active_mask: Optional boolean matrix with the same size asX. When provided, assets that become inactive have their variance and observation count reset.kwargs: Additional keyword arguments (ignored).
Validation
dims in (1, 2).- If
estimation_maskis notnothing,size(X) == size(estimation_mask). - If
active_maskis notnothing,size(X) == size(active_mask).
Returns
std::Vector{<:Number}: Per-asset regime-adjusted exponentially weighted standard deviation vector of lengthassets. Assets with fewer thance.min_obsobservations returnNaN.
Examples
julia> X = [0.01 -0.02; -0.015 0.03; 0.02 -0.01; -0.005 0.012];julia> ce = RegimeAdjustedExpWeightedVariance(; decay = 0.9, min_obs = 2, regime_min_obs = 2);julia> isapprox(std(ce, X), sqrt.(var(ce, X)))trueRelated
Statistics.std — Method
Statistics.std(
ce::RegimeAdjustedExpWeightedVariance,
state::RegimeAdjustedVarianceState;
kwargs...
) -> Vector{<:Number}Read the regime-adjusted standard deviation out of a state held by hand.
The root of Statistics.var(ce::RegimeAdjustedExpWeightedVariance, state::RegimeAdjustedVarianceState; kwargs...), so a state a caller keeps outside an estimator answers the same call as one the estimator holds. The state is read and never written.
Arguments
ce: Regime-adjusted exponentially weighted variance estimator.state: Running state of an incremental fit.kwargs: Additional keyword arguments (ignored).
Returns
std::Vector{<:Number}: Per-asset regime-adjusted exponentially weighted standard deviation vector of lengthassets. An asset with fewer thance.min_obsobservations isNaN.
Examples
julia> X = [0.01 -0.02; -0.015 0.03; 0.02 -0.01; -0.005 0.012];julia> ce = partial_fit!(RegimeAdjustedExpWeightedVariance(; decay = 0.9, min_obs = 2, regime_min_obs = 2), X);julia> isequal(std(ce, ce.cache), std(ce))trueRelated
Statistics.std — Method
Statistics.std(ce::RegimeAdjustedExpWeightedVariance; kwargs...) -> Vector{<:Number}Read the regime-adjusted standard deviation out of the estimator's own state.
The one-argument form is what an incremental fit answers: partial_fit! leaves the state in the cache field, and this verb turns it into the ordinary answer. An estimator that has been given no observation carries no state, so the call is refused rather than answered with a zero.
Arguments
ce: Regime-adjusted exponentially weighted variance estimator carrying a state.kwargs: Additional keyword arguments (ignored).
Validation
ce.cacheis notnothing. AnArgumentErroris thrown otherwise.
Returns
std::Vector{<:Number}: Per-asset regime-adjusted exponentially weighted standard deviation vector of lengthassets. An asset with fewer thance.min_obsobservations isNaN.
Examples
julia> X = [0.01 -0.02; -0.015 0.03; 0.02 -0.01; -0.005 0.012];julia> ce = partial_fit!(RegimeAdjustedExpWeightedVariance(; decay = 0.9, min_obs = 2, regime_min_obs = 2), X);julia> length(std(ce))2julia> std(RegimeAdjustedExpWeightedVariance())ERROR: ArgumentError: `ce` holds no partial-fit state, so there is nothing to read. Call `partial_fit!(ce, X)` first, or `std(ce, X)` for a fit over a whole sample.[...]Related
partial_fit!(ce::RegimeAdjustedExpWeightedVariance, X::MatNum; dims::Int = 1, estimation_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, active_mask::Option{<:AbstractMatrix{<:Bool}} = nothing, kwargs...)Statistics.std(ce::RegimeAdjustedExpWeightedVariance, state::RegimeAdjustedVarianceState; kwargs...)Statistics.var(ce::RegimeAdjustedExpWeightedVariance; kwargs...)
PortfolioOptimisers.merge_states — Method
merge_states(
a::RegimeAdjustedVarianceState,
b::RegimeAdjustedVarianceState
) -> Union{}Refuses a pair of regime-adjusted states, because this family does not merge.
A merge needs the state of a block to be a sufficient statistic for what that block contributes, and this one is not. The regime state reads each observation's standardised squared innovation, which divides by the running variance and is gated by the running observation count, so a block fitted from a cold start weighs its own first observations differently from the same block fitted after another. The exponentially weighted accumulator itself does fold, as $\lambda^{n_B} v_A + v_B$, but the regime state that scales it does not, and an uncentred fit also carries its running location while a HAC fit carries its buffer of recent returns.
Fold the second block into the first with partial_fit! instead. A sequential fit is exact, and it is the route this family gives.
Arguments
a: The state of the first block of observations.b: The state of the second block of observations.
Validation
aandbpassassert_mergeable_states, so a mismatched pair is named as such.- The pair is then refused with an
ArgumentError, whatever it holds.
Returns
- Nothing is returned. The method always throws.
Examples
julia> X = [0.01 -0.02; -0.015 0.03; 0.02 -0.01; -0.005 0.012];julia> ce = partial_fit!(RegimeAdjustedExpWeightedVariance(; decay = 0.9, min_obs = 2, regime_min_obs = 2), X);julia> try PortfolioOptimisers.merge_states(ce.cache, ce.cache) catch err err isa ArgumentError endtrueRelated