Gerber Information Quality Covariance (b): private API

PortfolioOptimisers.iq_crossed — Function
iq_crossed(x::Number, ax::Number, c::Number) -> Any

Decide whether one asset left the noise zone at one observation.

An asset leaves the noise zone when its return reaches the pair's scaled threshold and is not exactly zero. The sign test is redundant for a positive threshold, because ax >= c > 0 already implies that x is not zero. It binds only at c = 0, where the closed comparison ax >= 0 holds for every return, including one that is exactly zero. A return of exactly zero never crosses, and this is that rule for the Gerber IQ family.

The rule is what keeps the diagonal of the statistic at one. The pair (i, i) either crosses on both axes or on neither, so it never reaches the neutral accumulator that Gerber1 divides by. Without the sign test a zero return crosses on both axes but has no sign, so it fell through to that accumulator and pulled the diagonal below one.

Arguments

  • x: Return of the asset at the observation.
  • ax: Its absolute value.
  • c: The asset's scaled noise threshold, from comovement_pair_state.

Returns

  • crossed::Bool: true when the asset left the noise zone.

Related

source
PortfolioOptimisers.gerber_IQ — Function
gerber_IQ(
    ce::GerberIQCovariance,
    X::MatNum,
    sd::ArrNum
) -> MatNum

Computes the Gerber IQ statistic matrix using noise compression template in ce.kind and numerator/denominator definition according to ce.alg.

Mathematical definition

For each asset pair $(i,j)$ accumulate weighted concordant and discordant counts:

\[\begin{align} H_{ij}^{+} &= \sum_{k=1}^{T} w_{ij,k} \cdot d_k \cdot \mathbf{1}[\text{concordant}]\,, \\ H_{ij}^{-} &= \sum_{k=1}^{T} w_{ij,k} \cdot d_k \cdot \mathbf{1}[\text{discordant}]\,. \end{align}\]

Where:

  • $H_{ij}^{+}$, $H_{ij}^{-}$: Weighted concordant and discordant co-movement accumulators.
  • $T$: Number of observations.
  • $w_{ij,k}$: Region weight from the IQ template for observation $k$.
  • $d_k = \exp[-y \max(0, T-k-e)]$: Temporal decay at observation $k$.

GerberIQ correlation:

\[\begin{align} \rho_{ij} &= \begin{cases} (H_{ij}^{+} - H_{ij}^{-}) / (H_{ij}^{+} + H_{ij}^{-}) & \text{Gerber0} \\ (H_{ij}^{+} - H_{ij}^{-}) / (H_{ij}^{+} + H_{ij}^{-} + H_{ij}^{0}) & \text{Gerber1} \\ (H_{ij}^{+} - H_{ij}^{-}) / \sqrt{D_{ij}\,D_{ji}} & \text{Gerber2} \end{cases}\,. \end{align}\]

Where:

  • $\rho_{ij}$: GerberIQ correlation between assets $i$ and $j$.
  • $H_{ij}^{+}$, $H_{ij}^{-}$: Weighted concordant and discordant accumulators.
  • $H_{ij}^{0}$: Weighted neutral (neither concordant nor discordant) accumulator (Gerber1 only).
  • $D_{ij} = \sum_{k} w_{ii,k}\, d_{k}$, over the observations on which asset $i$ left the noise zone: the projection of asset $i$ onto the lead diagonal, in the units of the pair $(i, j)$. The projected co-movement $(x_{ki}, x_{ki})$ falls in one magnitude class on both axes, so $w_{ii,k}$ is the diagonal weight of asset $i$ at that observation. $D_{ij}$ and $D_{ji}$ differ, and both move with the pair whenever sc is not pair-separable.

The Gerber1 branch is the source's own statistic. Its numerator runs over the observations on which both assets left the noise zone, and its denominator over those on which at least one did. The Gerber0 and Gerber2 branches are the classic Gerber family's denominators, applied here to the weighted, discounted accumulators; the source's main text states neither. The source's internet appendix states a third form, whose denominator is the geometric mean of the two diagonal projections taken over the observations on which both assets crossed. This library does not ship that form. Gerber2 projects the same way but keeps the classic denominator's observation set, which is the one that reduces to GerberCovariance.

The Gerber statistic is the special case of this one that switches the squeezing and the decay off. With every weight set to one, $\gamma = 0$, the per-asset volatility scaling of AssetVolatilityGerberIQScaler, and $c$ equal to a Gerber threshold, all three branches reproduce GerberCovariance to the last bit. The reduction holds at $c = 0$ as it does at every positive threshold, because iq_crossed gives this family the same rule as that one: a return of exactly zero never leaves the noise zone.

All three branches are bounded by $|\rho_{ij}| \leq 1$. Gerber0 and Gerber1 are bounded by construction, because each divides by a sum of the same weights it subtracts. Gerber2 is bounded by the source's own condition on the template: every weight that joins two distinct magnitude classes is at most the geometric mean of the two diagonal weights of those classes. clamp_gerber_iq_n enforces that condition on every such weight, and the source proves it necessary and sufficient. Cauchy-Schwarz then bounds the ratio, because $D_{ij}$ reads asset $i$'s class in the same units the numerator reads it in, whatever sc does. The diagonal is exactly one, because the pair $(i, i)$ makes the numerator and both projections the same sum.

Algorithm

  1. Allocate the N × N output matrix rho.
  2. Resolve the decay estimator against X with regenerate_decay, so its delay and rate are numbers before the loop starts.
  3. Build the GerberIQKernel policy from the resolved decay and the estimator's alg, kind, sc, c and the standard deviations sd.
  4. Fill rho with gerber_comovement!, which walks every pair and every observation and reduces each pair's accumulators. That loop skeleton is shared with the Smyth-Broby family and lives in one place.
  5. Write one onto a zero diagonal entry with comovement_unit_diagonal!. An asset that never leaves its noise zone reduces to a zero diagonal entry, and that entry is one by definition.
  6. Repair the matrix with posdef!, because the statistic is not guaranteed to be positive semi-definite. The source records the same and repairs by the nearest correlation matrix.

Step 4 is where the three GerberCovarianceAlgorithm branches differ. comovement_ratio owns the Gerber0 and Gerber1 denominators, and comovement_finalise owns the Gerber2 one. This family does not call standardise_comovement!, which normalises after assembly and cannot read the pair's units.

Arguments

  • ce: Covariance estimator.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • sd: Standard deviation vector of X, shaped to be consistent with X.

Returns

  • rho::MatNum: Correlation matrix assets x assets.

Related

References

  • [15] S. Gerber, W. Smyth, H. Markowitz, Y. Miao, P. Ernst and P. Sargen. Squeezing financial noise: A novel approach to covariance matrix estimation. Available at SSRN 4986939 (2025).
source

References

[15]
S. Gerber, W. Smyth, H. Markowitz, Y. Miao, P. Ernst and P. Sargen. Squeezing financial noise: A novel approach to covariance matrix estimation. Available at SSRN 4986939 (2025).