Smyth-Broby Covariance: private API

PortfolioOptimisers.BaseSmythBrobyCovarianceType
abstract type BaseSmythBrobyCovariance <: BaseGerberCovariance

Abstract supertype for all Smyth-Broby covariance estimators.

All concrete and/or abstract types implementing Smyth-Broby covariance estimation algorithms should be subtypes of BaseSmythBrobyCovariance. It is a subtype of BaseGerberCovariance, because a Smyth-Broby statistic is a Gerber statistic with a second zone and a real-valued contribution in place of the vote. The Gerber statistic itself is stated in 01_GerberCovariance.jl and is not restated here.

Related

References

  • [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
source
PortfolioOptimisers.SmythBrobyCovarianceAlgorithmType
abstract type SmythBrobyCovarianceAlgorithm <: AbstractMomentAlgorithm

Abstract supertype for all Smyth-Broby covariance algorithm types.

All concrete and/or abstract types implementing specific Smyth-Broby covariance algorithms should be subtypes of SmythBrobyCovarianceAlgorithm.

These types are used to specify the algorithm when constructing a SmythBrobyCovariance estimator. A marker names two independent choices at once: its prefix selects the score triple through sb_pair_scores, and its trailing digit selects the denominator through comovement_ratio. The digit means the same thing here as it does in the Gerber family.

Related

References

  • [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
source
PortfolioOptimisers.GerberComovementZeroType

Union of the Gerber-family markers whose pairwise statistic divides the net score by the sum of the concordant and the discordant score, guarded to zero when the denominator vanishes.

The group exists because the trailing 0 means the same thing in all four families of the Gerber lineage, and one method of comovement_ratio serves them all. A family adds a member to this union rather than adding a branch to that method.

Related

source
PortfolioOptimisers.GerberComovementOneType

Union of the Gerber-family markers whose pairwise statistic divides the net score by the sum of all three scores, the neutral one included, guarded to zero when the denominator vanishes.

The group exists because the trailing 1 means the same thing in all four families of the Gerber lineage, and one method of comovement_ratio serves them all. The neutral term is what keeps the statistic positive semidefinite, so this is the canonical member of each family.

Related

source
PortfolioOptimisers.GerberComovementTwoType

Union of the Gerber-family markers whose pairwise statistic is the net score itself, with the assembled matrix normalised afterwards by the geometric mean of its own diagonal.

The group exists because the trailing 2 means the same thing in all four families of the Gerber lineage. It is the one variant whose normalisation is a property of the whole matrix rather than of one pair, so it is also the only one that reaches the acting method of standardise_comovement!.

Related

source
PortfolioOptimisers.SmythBrobyDeltaAlgType

Union of the Smyth-Broby markers that accumulate the sb_delta contributions only, and discard the counts.

The group exists because the marker prefix selects the score triple while the trailing digit selects the denominator, and the two choices are independent. This is the prefix the source itself defines: it sums contributions and counts no votes.

Related

source
PortfolioOptimisers.SmythBrobyGerberAlgType

Union of the Smyth-Broby markers that accumulate both the sb_delta contributions and the co-movement counts, and score a pair by their product.

The group exists because the marker prefix selects the score triple while the trailing digit selects the denominator, and the two choices are independent. The source's conclusion suggests keeping a count beside the sum and states no formula for it, so the product is the library's reading of that sentence.

Related

source
PortfolioOptimisers.SmythBrobyCountAlgType

Union of the Smyth-Broby markers that accumulate the co-movement counts only, and never evaluate sb_delta.

The group exists because the marker prefix selects the score triple while the trailing digit selects the denominator, and the two choices are independent. This prefix recovers a Gerber statistic evaluated on the Smyth-Broby zoning, so it is the library's own construction: the source counts no votes.

Related

source
PortfolioOptimisers.SmythBrobyKernelType
struct SmythBrobyKernel{T1<:SmythBrobyCovarianceAlgorithm, T2<:(AbstractArray{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}), T3<:(AbstractArray{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}), T4<:Number, T5<:Number, T6<:Number, T7<:Number}

Co-movement policy for gerber_comovement! implementing the Smyth-Broby family.

The confusion zone thresholds the raw, uncentred return by c1 * sigma. Observations that pass it are centred and standardised per asset, restricted to the significance zone by c2 through sb_crossed and by c3, and classified by the sign of the product of the standardised returns. The alg marker selects the accumulation family (sb_add_pos) and the denominator policy (comovement_ratio). This type is configuration handed to gerber_comovement!; it holds no result and it is never mutated.

Fields

  • alg: Smyth-Broby covariance algorithm.
  • mu: Vector of asset means, one entry per asset.
  • sd: Standard deviation vector of X, shaped to be consistent with X.
  • c1: Zone of confusion threshold, in units of the asset's standard deviation. It is read against the raw, uncentred return, and it rejects an observation only when both assets fall inside it.
  • c2: Zone of indecision threshold, in units of the asset's standard deviation. It is read against the centred, standardised return, and it rejects an observation when both assets fall inside it. A centred return of exactly zero is inside it at every c2.
  • c3: Outer cut-off, in units of the asset's standard deviation. It is read against the centred, standardised return, and it rejects an observation when either asset exceeds it.
  • n: Severity exponent of the Smyth-Broby contribution. It sets how hard the divergence of a pair is penalised.

Related

References

  • [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
source
PortfolioOptimisers.sb_deltaFunction
sb_delta(ri::Number, rj::Number, n::Number) -> Number

Contribution of one admitted observation to a Smyth-Broby pair score.

This is the quantity that replaces the Gerber vote: an observation contributes a finite real number rather than a count of one, so a co-movement of four standard deviations weighs more than one of a single standard deviation. Both arguments are already absolute, and the caller has already centred and standardised them.

Mathematical definition

\[\begin{align} \kappa &= \sqrt{\left(1 + |\tilde{r}_{t,\,i}|\right) \left(1 + |\tilde{r}_{t,\,j}|\right)}\,, \\ \gamma &= \left\lVert |\tilde{r}_{t,\,i}| - |\tilde{r}_{t,\,j}| \right\rVert\,, \\ \delta &= \frac{\kappa}{1 + \gamma^{n}}\,. \end{align}\]

Where:

  • $\tilde{r}_{t,\,i} = (x_{t,\,i} - \mu_i) / \sigma_i$: Centred, standardised return of asset $i$ at observation $t$.
  • $\kappa$: Amplitude kernel of a pair, the geometric mean of the two gross standardised magnitudes.
  • $\gamma$: Divergence of a pair, the absolute difference of the two standardised magnitudes.
  • $\delta$: Smyth-Broby contribution of one admitted observation, in place of the Gerber vote.
  • $n$: Severity exponent. It sets how hard the divergence of a pair is penalised.

$\kappa$ rewards magnitude and $\gamma^{n}$ penalises a pair whose two magnitudes disagree, so the contribution is largest when both assets move far and move by the same amount. $\gamma$ is the absolute difference of the two magnitudes, not of the two signed returns; the sign has already been read by the caller, which is what put the observation in the concordant or the discordant set.

Algorithm

  1. Multiply the two gross magnitudes 1 + ri and 1 + rj and take the square root, giving the amplitude kappa.
  2. Take the absolute difference of ri and rj, giving the divergence gamma.
  3. Return kappa / (1 + gamma^n).

Arguments

  • ri: Absolute centred standardised return of asset i at the observation.
  • rj: Absolute centred standardised return of asset j at the observation.
  • n: Severity exponent of the Smyth-Broby contribution. It sets how hard the divergence of a pair is penalised.

Returns

  • delta::Number: The contribution of the observation to the pair's score.

Related

References

  • [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
source
PortfolioOptimisers.smythbrobyFunction
smythbroby(ce::SmythBrobyCovariance, X::MatNum, mu::ArrNum, sd::ArrNum)

Compute the Smyth-Broby co-movement correlation matrix for the algorithm marker in ce.alg.

All nine variants share the pairwise kernel gerber_comovement! through a SmythBrobyKernel policy: observations are noise-gated by c1 * sigma, standardised, restricted to the [c2, c3] significance zone by sb_crossed, and classified as concordant, discordant, or neutral by the sign of the product of standardised returns. The marker selects the accumulation family and denominator policy.

Mathematical definition

For each pair $(i, j)$ an observation $t$ passes two admission tests. The noise gate compares the raw, uncentred return against $c_1 \sigma$, and rejects $t$ only when both assets fall inside it:

\[\begin{align} |x_{ti}| < c_1 \sigma_i \quad \text{and} \quad |x_{tj}| < c_1 \sigma_j\,. \end{align}\]

The significance zone compares the centred, standardised return $\tilde{r}_{ti} = (x_{ti} - \mu_i) / \sigma_i$. Asset $i$ crosses at $t$ when

\[\begin{align} |\tilde{r}_{ti}| \geq c_2 \quad \text{and} \quad \tilde{r}_{ti} \neq 0\,, \end{align}\]

and the zone rejects $t$ when either asset exceeds $c_3$ or neither asset crosses. The second test of the crossing binds only at $c_2 = 0$, because $|\tilde{r}| \geq c_2 > 0$ already excludes a zero return. A return of exactly zero never crosses for this family, and sb_crossed is where the code states it. The gate reads the uncentred return and the zone reads the centred one; this mix is the source's, not an oversight. Centering the gate as well moves the statistic, and the rule binds on the centred quantity alone.

An admitted observation is concordant when both assets cross and $\tilde{r}_{ti} \tilde{r}_{tj} > 0$, discordant when both cross and the product is negative, and neutral otherwise, which is the case where exactly one asset crosses. Accumulate the kernel and the count of each class over the admitted observations:

\[\begin{align} \text{pos} &= \sum_t \delta_t \, \mathbf{1}[t \in C]\,, \quad \text{neg} = \sum_t \delta_t \, \mathbf{1}[t \in D]\,, \quad \text{nn} = \sum_t \delta_t \, \mathbf{1}[t \in N]\,, \\ c^{+} &= |C|\,, \quad c^{-} = |D|\,, \quad c^{0} = |N|\,, \end{align}\]

Where:

  • $\tilde{r}_{t,\,i} = (x_{t,\,i} - \mu_i) / \sigma_i$: Centred, standardised return of asset $i$ at observation $t$.
  • $x_{t,\,i}$: Return of asset $i$ at observation $t$.
  • $\sigma_i$: Standard deviation of asset $i$.
  • $c_1$: Confusion-zone threshold. It is read against the raw, uncentred return, and it rejects an observation only when both assets fall inside it.
  • $c_2$: Indecision-zone threshold. It is read against the centred, standardised return, and it rejects an observation when both assets fall inside it. A centred return of exactly zero is inside it at every $c_2$.
  • $c_3$: Outer cut-off. It is read against the centred, standardised return, and it rejects an observation when either asset exceeds it.
  • $\delta$: Smyth-Broby contribution of one admitted observation, in place of the Gerber vote.
  • $C$, $D$, $N$: Concordant, discordant and neutral observation sets of a pair, over the admitted observations.
  • $\mathrm{pos}$, $\mathrm{neg}$, $\mathrm{nn}$: Contribution sums of a pair over $C$, $D$ and $N$.
  • $c^{+}$, $c^{-}$, $c^{0}$: Observation counts of a pair over $C$, $D$ and $N$.
  • $p$, $q$, $u$: Concordant, discordant and neutral scores of a pair, chosen from the sums and the counts by the marker prefix.

with $\delta_t = \delta(|\tilde{r}_{t,\,i}|, |\tilde{r}_{t,\,j}|, n)$ the sb_delta contribution. The marker prefix selects the three scores $(p, q, u)$:

  • SmythBroby*: $(\text{pos},\, \text{neg},\, \text{nn})$.
  • SmythBrobyGerber*: $(\text{pos} \, c^{+},\, \text{neg} \, c^{-},\, \text{nn} \, c^{0})$. Every term carries its own count, the neutral one included.
  • SmythBrobyCount*: $(c^{+},\, c^{-},\, c^{0})$.

The variant number selects the reduction, with $h_{ij} = p - q$ the raw difference:

\[\begin{align} \hat{\rho}_{ij} &= \begin{cases} (p - q) / (p + q) & 0 \\ (p - q) / (p + q + u) & 1 \\ h_{ij} / \sqrt{h_{ii} \, h_{jj}} & 2 \end{cases}\,. \end{align}\]

Variants 0 and 1 return zero when their denominator vanishes. Variant 2 divides the net score matrix by the geometric mean of its own diagonal, with the roots clamped below at $\sqrt{\varepsilon}$. It does not normalise the variant 0 ratio: the two agree only where $p + q$ is constant across pairs.

Only the SmythBroby1 composition is the source's own. It is equation (5) of the source, and the source defines no other statistic. The trailing 0 and 2 are the library's reductions, on the shape Gerber0 and Gerber2 set. The SmythBrobyGerber* prefix reads one sentence of the source's conclusion, which suggests keeping a count beside the sum and states no formula. The SmythBrobyCount* prefix is the library's own: the source counts no votes, and that prefix recovers the Gerber statistic on the Smyth-Broby zoning.

Algorithm

  1. Read the asset count N from the second dimension of X, and open the N × N output rho.
  2. Build the policy pol as a SmythBrobyKernel from ce.alg, mu, sd, ce.c1, ce.c2, ce.c3 and ce.n.
  3. Fill rho with gerber_comovement!, over the executor ce.ex.
  4. Normalise rho in place with standardise_comovement!. Only a 2 marker changes it.
  5. Write one onto a zero diagonal entry of rho with comovement_unit_diagonal!. An asset that qualifies no observation reduces to a zero diagonal entry, and that entry is one by definition.
  6. Repair rho with posdef! and the estimator's pdm. A Smyth-Broby matrix is a matrix of pairwise scores and is not positive definite in general.

Arguments

  • ce: Smyth-Broby covariance estimator.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • mu: Vector of asset means, one entry per asset.
  • sd: Standard deviation vector of X, shaped to be consistent with X.

Returns

  • rho::Matrix{<:Number}: The Smyth-Broby correlation matrix, projected to be positive definite using the estimator's pdm field.

Related

References

  • [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
source
PortfolioOptimisers.gerber_comovement!Function
gerber_comovement!(
    rho::AbstractMatrix,
    ex::Transducers.Executor,
    X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
    pol
) -> Any

Fill the symmetric co-movement matrix rho by running the shared Gerber-family pairwise kernel.

The policy object pol (for example SmythBrobyKernel or GerberIQKernel) owns the thresholding, the classification and the weighting of a single observation, and the reduction of a pair's accumulator. The loop skeleton lives here once. It writes into rho and into nothing else, so X and pol are unchanged afterwards.

Algorithm

  1. Read the observation count T from the first dimension of X.
  2. For every asset pair (i, j) with i at most j, run steps 3 to 6. The outer index is parallelised over the executor ex.
  3. Build the pair state st with comovement_pair_state.
  4. Open the accumulator acc as the named tuple (pos, neg, nn, cpos, cneg, cnn, di, dj), with the five scores at zero of eltype(X) and the three counts at integer zero. A policy reads the slots its marker needs and leaves the rest at zero. di and dj carry the two diagonal projections that the Gerber IQ 2 marker divides by; iq_add_diagonal is their only writer.
  5. Fold every observation k of the pair through comovement_step into acc.
  6. Reduce acc with comovement_finalise and write the result into rho[i, j] and rho[j, i].

Arguments

  • rho::AbstractMatrix: N × N output matrix, overwritten.
  • ex: FLoops executor parallelising over the outer asset index.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • pol: Co-movement policy object.

Returns

  • nothing.

Related

source
PortfolioOptimisers.comovement_pair_stateFunction
comovement_pair_state(
    pol::SmythBrobyKernel,
    i::Integer,
    j::Integer
) -> NamedTuple{(:mui, :muj, :sigmai, :sigmaj, :c1i, :c1j), <:NTuple{6, Any}}

Build the per-pair state consumed by comovement_step.

The state holds every quantity that depends on the pair but not on the observation, so the inner loop reads it rather than recomputing it. The Gerber IQ method returns the pair's threshold scaling factors and scaled thresholds instead.

Algorithm

The Smyth-Broby method runs these steps.

  1. Read the two standard deviations pol.sd[i] and pol.sd[j], giving sigmai and sigmaj.
  2. Multiply each by pol.c1, giving the two confusion-zone thresholds c1i and c1j.
  3. Return the named tuple (mui, muj, sigmai, sigmaj, c1i, c1j), with the two means read from pol.mu.

Arguments

  • pol: Co-movement policy object.
  • i, j: Indices of the two assets of the pair.

Returns

  • The per-pair state, as a named tuple.

Related

source
PortfolioOptimisers.sb_crossedFunction
sb_crossed(r::Number, ar::Number, c::Number) -> Any

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

An asset leaves the indecision zone when the magnitude of its centred, standardised return reaches c2 and that return is not exactly zero. The sign test is redundant for a positive threshold, because ar >= c > 0 already implies that r is not zero. It binds only at c2 = 0, where the closed comparison ar >= 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 Smyth-Broby 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 a GerberComovementOne marker divides by. Without the sign test a zero return crossed on both axes but carried no sign, so it fell through to that accumulator and pulled the diagonal below one.

The rule binds on this gate and not on the confusion zone. The two gates read different quantities. Here the quantity is centred, so an exactly zero return is an asset that did not move away from its own mean, and it has no sign to classify. The confusion zone reads the raw, uncentred return, whose zero is an arbitrary point of the scale of the data: an asset whose raw return is zero moved by $-\mu$ against its mean, which is a deviation with a sign. That gate also only rejects and never classifies, so it produces no wrong count of its own.

Arguments

  • r: Centred, standardised return of the asset at the observation.
  • ar: Its absolute value.
  • c: The indecision-zone threshold c2.

Returns

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

Related

source
PortfolioOptimisers.comovement_stepFunction
comovement_step(
    pol::SmythBrobyKernel,
    acc,
    st,
    xi::Number,
    xj::Number,
    _::Integer,
    _::Integer
) -> Any

Fold one observation of a pair into the co-movement accumulator.

The confusion zone reads the raw, uncentred return and the indecision zone reads the centred, standardised one. That mix is the source's, not an oversight, and centring the confusion zone as well moves the statistic. The mix also decides which gate carries the rule that a return of exactly zero never crosses: sb_crossed keeps a return of exactly zero inside the indecision zone, and the confusion zone takes no such test, because the zero of a raw return is an arbitrary point of the scale of the data. The Gerber IQ method thresholds absolute returns against the pair's scaled thresholds with iq_crossed, and weights observations by the IQ template and temporal decay via gerber_IQ_delta.

Algorithm

The Smyth-Broby method runs these steps. It reads T and k in neither, because the family applies no temporal decay.

  1. Return acc unchanged when abs(xi) is below st.c1i and abs(xj) is below st.c1j. This is the confusion zone, read on the raw return.
  2. Centre and standardise both returns with the pair state, giving ri and rj, and take their magnitudes ari and arj.
  3. Decide with sb_crossed whether each asset left the indecision zone of pol.c2.
  4. Return acc unchanged when either magnitude exceeds pol.c3, or when neither asset left the indecision zone. The first is the outer cut-off and the second is the indecision zone itself.
  5. Accumulate through sb_add_pos when both assets crossed and the product ri * rj is positive.
  6. Accumulate through sb_add_neg when both assets crossed and the product is negative.
  7. Accumulate through sb_add_neutral otherwise, which is the case where exactly one asset crossed. Two crossings give a product that is not zero, so the three branches are exhaustive.

Arguments

  • pol: Co-movement policy object.
  • acc: Pair accumulator (pos, neg, nn, cpos, cneg, cnn).
  • st: Pair state from comovement_pair_state.
  • xi, xj: Returns of assets i and j at observation k.
  • T: Number of observations.
  • k: Observation index.

Returns

  • The updated accumulator.

Related

source
PortfolioOptimisers.comovement_finaliseFunction
comovement_finalise(
    pol::SmythBrobyKernel,
    acc,
    _::Type{T}
) -> Any

Reduce a pair's accumulator to the pairwise co-movement statistic.

It joins the two halves of the marker: the prefix chooses the scores and the trailing digit chooses the denominator.

Algorithm

  1. Select the score triple (p, n, nn) from acc with sb_pair_scores, which the marker prefix dispatches.
  2. Reduce the triple with comovement_ratio, which the trailing digit dispatches, and return the result.

Arguments

  • pol: Co-movement policy object.
  • acc: Pair accumulator (pos, neg, nn, cpos, cneg, cnn).
  • T: Element type used for the guarded zero.

Returns

  • The pairwise co-movement statistic.

Related

source
PortfolioOptimisers.comovement_ratioFunction
comovement_ratio(
    _::Union{Gerber0, SmythBroby0, SmythBrobyCount0, SmythBrobyGerber0},
    p::Number,
    n::Number,
    nn::Number,
    _::Type{T}
) -> Any

Reduce a pair's accumulated positive, negative, and neutral co-movement scores to the pairwise correlation entry.

The variant marker selects the denominator policy. n here is the discordant score, not the severity exponent of sb_delta; the two share a glyph and nothing else.

Algorithm

The marker selects one of three branches.

  1. GerberComovementZero: return (p - n) / (p + n), or zero(T) when p + n is zero. It does not read nn.
  2. GerberComovementOne: return (p - n) / (p + n + nn), or zero(T) when p + n + nn is zero. This is the only branch that reads nn.
  3. GerberComovementTwo: return p - n, and apply no denominator. standardise_comovement! normalises the assembled matrix afterwards.

A zero denominator means that the pair qualified no observation, and the guarded zero is the right answer for an off-diagonal entry. It is the wrong answer on the diagonal, where a correlation is one by definition. This function cannot separate the two cases, because it does not know whether the pair is (i, i). comovement_unit_diagonal! writes the diagonal after the matrix is assembled.

Arguments

  • alg: Co-movement algorithm marker.
  • p, n, nn: Accumulated concordant, discordant and neutral scores of one pair.
  • T: Element type used for the guarded zero.

Returns

  • The pairwise co-movement statistic.

Related

source
PortfolioOptimisers.standardise_comovement!Function
standardise_comovement!(_, _::AbstractMatrix)

Normalise a net co-movement matrix in place by the geometric mean of its own diagonal.

Only the GerberComovementTwo markers reach the acting method; the fall-through method is a no-op, so every caller may call this unconditionally. It writes into rho and into nothing else, so the marker it is handed and the estimator that owns the marker are unchanged afterwards.

The Gerber IQ family does not call this function. Its thresholds move with the pair whenever sc is not pair-separable, so an asset's magnitude class off the diagonal is not the class the assembled diagonal records, and the ratio leaves [-1, 1]. gerber_IQ divides by the pair's own two diagonal projections instead, which iq_add_diagonal accumulates. The other three families threshold each asset in its own units, so the assembled diagonal is the same number and this function stands.

Algorithm

The acting method runs these steps. The fall-through method runs none of them.

  1. Take the square roots of the diagonal of rho, clamped from below by sqrt(eps(eltype(rho))), giving h. The clamp is what keeps an asset that admits no observation from a division by zero.
  2. Divide rho element-wise by the outer product h * transpose(h), and write the upper triangle back symmetrically.

Arguments

  • alg: Co-movement algorithm marker. It selects the acting method or the no-op.
  • rho: N × N co-movement matrix, overwritten.

Returns

  • nothing.

Related

source
PortfolioOptimisers.comovement_unit_diagonal!Function
comovement_unit_diagonal!(rho::AbstractMatrix)

Write one onto a zero diagonal entry of an assembled co-movement matrix, in place.

The correlation of an asset with itself is one by definition, whatever the sample holds. Every reduction of comovement_ratio already returns one there when the asset crosses its threshold at least once, so only the degenerate case is left. An asset that crosses no threshold gives a zero denominator for every pair it belongs to, takes the guarded zero(T) over its whole row, and takes it on its diagonal entry too. It writes into rho and into nothing else, so every other entry is unchanged afterwards.

The write is guarded by iszero, and does not restate a diagonal that is already one. A 2 marker divides the diagonal by its own square root twice, so its diagonal entry is one to within a unit in the last place rather than exactly one. posdef! reads its diagonal with an exact isone test to decide whether it holds a correlation matrix or a covariance matrix, and the two branches answer differently. Writing an exact one over an entry that already reads as one moves that branch, and with it the answer of a sample that carries no degenerate asset. The guard keeps this function to the defect it fixes.

Algorithm

  1. For each index i of the diagonal, write one(eltype(rho)) onto rho[i, i] when that entry is zero.

Arguments

  • rho: N × N co-movement matrix, whose zero diagonal entries are overwritten.

Returns

  • nothing.

Related

source
PortfolioOptimisers.sb_add_posFunction
sb_add_pos(
    _::Union{SmythBroby0, SmythBroby1, SmythBroby2},
    acc,
    ari::Number,
    arj::Number,
    n::Number
) -> Union{NamedTuple, DataStructures.SortedMultiDict}

Accumulate a concordant observation into the pair accumulator, according to the Smyth-Broby family of alg.

The accumulator is a named tuple and every method returns a new one, so nothing is mutated.

Algorithm

The marker prefix selects one of three branches.

  1. SmythBrobyDeltaAlg: add sb_delta to acc.pos, and leave acc.cpos alone.
  2. SmythBrobyGerberAlg: add sb_delta to acc.pos, and add one to acc.cpos.
  3. SmythBrobyCountAlg: add one to acc.cpos, and never evaluate sb_delta.

Arguments

  • alg: Smyth-Broby algorithm marker.
  • acc: Pair accumulator (pos, neg, nn, cpos, cneg, cnn).
  • ari, arj: Absolute centred standardised returns of the two assets at the observation.
  • n: Severity exponent of the Smyth-Broby contribution. It sets how hard the divergence of a pair is penalised.

Returns

  • The updated accumulator.

Related

source
PortfolioOptimisers.sb_add_negFunction
sb_add_neg(
    _::Union{SmythBroby0, SmythBroby1, SmythBroby2},
    acc,
    ari::Number,
    arj::Number,
    n::Number
) -> Union{NamedTuple, DataStructures.SortedMultiDict}

Accumulate a discordant observation into the pair accumulator, according to the Smyth-Broby family of alg.

It mirrors sb_add_pos on the discordant score and count, branch for branch.

Algorithm

The marker prefix selects one of three branches.

  1. SmythBrobyDeltaAlg: add sb_delta to acc.neg, and leave acc.cneg alone.
  2. SmythBrobyGerberAlg: add sb_delta to acc.neg, and add one to acc.cneg.
  3. SmythBrobyCountAlg: add one to acc.cneg, and never evaluate sb_delta.

Arguments

  • alg: Smyth-Broby algorithm marker.
  • acc: Pair accumulator (pos, neg, nn, cpos, cneg, cnn).
  • ari, arj: Absolute centred standardised returns of the two assets at the observation.
  • n: Severity exponent of the Smyth-Broby contribution. It sets how hard the divergence of a pair is penalised.

Returns

  • The updated accumulator.

Related

source
PortfolioOptimisers.sb_add_neutralFunction
sb_add_neutral(
    _::SmythBroby1,
    acc,
    ari::Number,
    arj::Number,
    n::Number
) -> Union{NamedTuple, DataStructures.SortedMultiDict}

Accumulate a neutral observation into the pair accumulator. An observation is neutral when exactly one of the two assets left the indecision zone, which sb_crossed decides.

Only the GerberComovementOne markers reach an acting method, because they are the only ones whose denominator carries a neutral term. The fall-through method returns the accumulator unchanged, so the neutral score of every other marker stays at zero and is read by no reduction.

Algorithm

The marker selects one of four branches.

  1. SmythBroby1: add sb_delta to acc.nn.
  2. SmythBrobyGerber1: add sb_delta to acc.nn, and add one to acc.cnn.
  3. SmythBrobyCount1: add one to acc.cnn, and never evaluate sb_delta.
  4. Any other SmythBrobyCovarianceAlgorithm: return acc unchanged.

Arguments

  • alg: Smyth-Broby algorithm marker.
  • acc: Pair accumulator (pos, neg, nn, cpos, cneg, cnn).
  • ari, arj: Absolute centred standardised returns of the two assets at the observation. The fall-through method reads neither.
  • n: Severity exponent of the Smyth-Broby contribution. It sets how hard the divergence of a pair is penalised.

Returns

  • The updated accumulator.

Related

source
PortfolioOptimisers.sb_pair_scoresFunction
sb_pair_scores(
    _::Union{SmythBroby0, SmythBroby1, SmythBroby2},
    acc
) -> Tuple{Any, Any, Any}

Select the pair's concordant, discordant and neutral scores from the accumulator, according to the Smyth-Broby family of alg.

This is the half of the marker that the prefix owns. comovement_ratio owns the other half, which the trailing digit selects.

Algorithm

The marker prefix selects one of three branches.

  1. SmythBrobyDeltaAlg: return the contribution sums (acc.pos, acc.neg, acc.nn).
  2. SmythBrobyGerberAlg: return each sum times its own count, (acc.pos * acc.cpos, acc.neg * acc.cneg, acc.nn * acc.cnn).
  3. SmythBrobyCountAlg: return the counts (acc.cpos, acc.cneg, acc.cnn).

Arguments

  • alg: Smyth-Broby algorithm marker.
  • acc: Pair accumulator (pos, neg, nn, cpos, cneg, cnn).

Returns

  • The score triple (p, q, u) of the pair.

Related

source

References

[14]
W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).