Smyth-Broby Covariance: private API
PortfolioOptimisers.BaseSmythBrobyCovariance — Type
abstract type BaseSmythBrobyCovariance <: BaseGerberCovarianceAbstract 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).
PortfolioOptimisers.SmythBrobyCovarianceAlgorithm — Type
abstract type SmythBrobyCovarianceAlgorithm <: AbstractMomentAlgorithmAbstract 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
BaseSmythBrobyCovarianceSmythBrobyCovarianceSmythBrobyDeltaAlgSmythBrobyGerberAlgSmythBrobyCountAlgGerberComovementZeroGerberComovementOneGerberComovementTwo
References
- [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
PortfolioOptimisers.GerberComovementZero — Type
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
Gerber0SmythBroby0SmythBrobyGerber0SmythBrobyCount0comovement_ratio: the method that dispatches on this alias.GerberComovementOneGerberComovementTwo
PortfolioOptimisers.GerberComovementOne — Type
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
Gerber1SmythBroby1SmythBrobyGerber1SmythBrobyCount1comovement_ratio: the method that dispatches on this alias.sb_add_neutral: the accumulator that fills the neutral score, and which only these markers reach.GerberComovementZeroGerberComovementTwo
PortfolioOptimisers.GerberComovementTwo — Type
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
Gerber2SmythBroby2SmythBrobyGerber2SmythBrobyCount2comovement_ratio: the method that dispatches on this alias.standardise_comovement!: the acting method that dispatches on this alias.GerberComovementZeroGerberComovementOne
PortfolioOptimisers.SmythBrobyDeltaAlg — Type
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
SmythBroby0SmythBroby1SmythBroby2sb_add_pos: the accumulator that dispatches on this alias.sb_pair_scores: the selector that dispatches on this alias.SmythBrobyGerberAlgSmythBrobyCountAlg
PortfolioOptimisers.SmythBrobyGerberAlg — Type
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
SmythBrobyGerber0SmythBrobyGerber1SmythBrobyGerber2sb_add_pos: the accumulator that dispatches on this alias.sb_pair_scores: the selector that dispatches on this alias.SmythBrobyDeltaAlgSmythBrobyCountAlg
PortfolioOptimisers.SmythBrobyCountAlg — Type
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
SmythBrobyCount0SmythBrobyCount1SmythBrobyCount2sb_add_pos: the accumulator that dispatches on this alias.sb_pair_scores: the selector that dispatches on this alias.GerberCovariance: the statistic this prefix recovers when the confusion zone is switched off, the outer cut-off is lifted, and the centre is zero.SmythBrobyDeltaAlgSmythBrobyGerberAlg
PortfolioOptimisers.SmythBrobyKernel — Type
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 ofX, shaped to be consistent withX.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 everyc2.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
SmythBrobyCovariancesmythbroby: the caller that builds this policy.gerber_comovement!comovement_pair_statecomovement_stepcomovement_finalise
References
- [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
PortfolioOptimisers.sb_delta — Function
sb_delta(ri::Number, rj::Number, n::Number) -> NumberContribution 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
- Multiply the two gross magnitudes
1 + riand1 + rjand take the square root, giving the amplitudekappa. - Take the absolute difference of
riandrj, giving the divergencegamma. - Return
kappa / (1 + gamma^n).
Arguments
ri: Absolute centred standardised return of assetiat the observation.rj: Absolute centred standardised return of assetjat 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).
PortfolioOptimisers.smythbroby — Function
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
- Read the asset count
Nfrom the second dimension ofX, and open theN × Noutputrho. - Build the policy
polas aSmythBrobyKernelfromce.alg,mu,sd,ce.c1,ce.c2,ce.c3andce.n. - Fill
rhowithgerber_comovement!, over the executorce.ex. - Normalise
rhoin place withstandardise_comovement!. Only a2marker changes it. - Write one onto a zero diagonal entry of
rhowithcomovement_unit_diagonal!. An asset that qualifies no observation reduces to a zero diagonal entry, and that entry is one by definition. - Repair
rhowithposdef!and the estimator'spdm. 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 matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.mu: Vector of asset means, one entry per asset.sd: Standard deviation vector ofX, shaped to be consistent withX.
Returns
rho::Matrix{<:Number}: The Smyth-Broby correlation matrix, projected to be positive definite using the estimator'spdmfield.
Related
SmythBrobyCovarianceSmythBrobyKernelgerber_comovement!standardise_comovement!comovement_unit_diagonal!sb_deltaposdef!GerberCovariance: the statistic this family extends. Its matrix form is stated there and is not repeated here.
References
- [14] W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).
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
- Read the observation count
Tfrom the first dimension ofX. - For every asset pair
(i, j)withiat mostj, run steps 3 to 6. The outer index is parallelised over the executorex. - Build the pair state
stwithcomovement_pair_state. - Open the accumulator
accas the named tuple(pos, neg, nn, cpos, cneg, cnn, di, dj), with the five scores at zero ofeltype(X)and the three counts at integer zero. A policy reads the slots its marker needs and leaves the rest at zero.dianddjcarry the two diagonal projections that the Gerber IQ2marker divides by;iq_add_diagonalis their only writer. - Fold every observation
kof the pair throughcomovement_stepintoacc. - Reduce
accwithcomovement_finaliseand write the result intorho[i, j]andrho[j, i].
Arguments
rho::AbstractMatrix:N × Noutput matrix, overwritten.ex:FLoopsexecutor parallelising over the outer asset index.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.pol: Co-movement policy object.
Returns
nothing.
Related
PortfolioOptimisers.comovement_pair_state — Function
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.
- Read the two standard deviations
pol.sd[i]andpol.sd[j], givingsigmaiandsigmaj. - Multiply each by
pol.c1, giving the two confusion-zone thresholdsc1iandc1j. - Return the named tuple
(mui, muj, sigmai, sigmaj, c1i, c1j), with the two means read frompol.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
gerber_comovement!comovement_step: the consumer of this state.SmythBrobyKernel
PortfolioOptimisers.sb_crossed — Function
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 thresholdc2.
Returns
crossed::Bool:truewhen the asset left the indecision zone.
Related
PortfolioOptimisers.comovement_step — Function
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.
- Return
accunchanged whenabs(xi)is belowst.c1iandabs(xj)is belowst.c1j. This is the confusion zone, read on the raw return. - Centre and standardise both returns with the pair state, giving
riandrj, and take their magnitudesariandarj. - Decide with
sb_crossedwhether each asset left the indecision zone ofpol.c2. - Return
accunchanged when either magnitude exceedspol.c3, or when neither asset left the indecision zone. The first is the outer cut-off and the second is the indecision zone itself. - Accumulate through
sb_add_poswhen both assets crossed and the productri * rjis positive. - Accumulate through
sb_add_negwhen both assets crossed and the product is negative. - Accumulate through
sb_add_neutralotherwise, 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 fromcomovement_pair_state.xi,xj: Returns of assetsiandjat observationk.T: Number of observations.k: Observation index.
Returns
- The updated accumulator.
Related
PortfolioOptimisers.comovement_finalise — Function
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
- Select the score triple
(p, n, nn)fromaccwithsb_pair_scores, which the marker prefix dispatches. - 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
PortfolioOptimisers.comovement_ratio — Function
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.
GerberComovementZero: return(p - n) / (p + n), orzero(T)whenp + nis zero. It does not readnn.GerberComovementOne: return(p - n) / (p + n + nn), orzero(T)whenp + n + nnis zero. This is the only branch that readsnn.GerberComovementTwo: returnp - 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
gerber_comovement!comovement_finalise: the caller that reaches this function once per pair.standardise_comovement!comovement_unit_diagonal!: the function that corrects the guarded zero on the diagonal.GerberComovementZeroGerberComovementOneGerberComovementTwo
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.
- Take the square roots of the diagonal of
rho, clamped from below bysqrt(eps(eltype(rho))), givingh. The clamp is what keeps an asset that admits no observation from a division by zero. - Divide
rhoelement-wise by the outer producth * 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 × Nco-movement matrix, overwritten.
Returns
nothing.
Related
comovement_ratio: the reduction whoseGerberComovementTwobranch leaves the net score for this function to normalise.comovement_unit_diagonal!: the repair of the diagonal that runs immediately after this function.gerber_comovement!GerberComovementTwo
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
- For each index
iof the diagonal, writeone(eltype(rho))ontorho[i, i]when that entry is zero.
Arguments
rho:N × Nco-movement matrix, whose zero diagonal entries are overwritten.
Returns
nothing.
Related
comovement_ratio: the reduction whose guarded zero reaches the diagonal.standardise_comovement!: the normalisation that runs immediately before this function.gerber_comovement!posdef!: the repair that runs immediately after this function, and that a zero diagonal turns into aNaN.
PortfolioOptimisers.sb_add_pos — Function
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.
SmythBrobyDeltaAlg: addsb_deltatoacc.pos, and leaveacc.cposalone.SmythBrobyGerberAlg: addsb_deltatoacc.pos, and add one toacc.cpos.SmythBrobyCountAlg: add one toacc.cpos, and never evaluatesb_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
PortfolioOptimisers.sb_add_neg — Function
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.
SmythBrobyDeltaAlg: addsb_deltatoacc.neg, and leaveacc.cnegalone.SmythBrobyGerberAlg: addsb_deltatoacc.neg, and add one toacc.cneg.SmythBrobyCountAlg: add one toacc.cneg, and never evaluatesb_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
PortfolioOptimisers.sb_add_neutral — Function
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.
SmythBroby1: addsb_deltatoacc.nn.SmythBrobyGerber1: addsb_deltatoacc.nn, and add one toacc.cnn.SmythBrobyCount1: add one toacc.cnn, and never evaluatesb_delta.- Any other
SmythBrobyCovarianceAlgorithm: returnaccunchanged.
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
PortfolioOptimisers.sb_pair_scores — Function
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.
SmythBrobyDeltaAlg: return the contribution sums(acc.pos, acc.neg, acc.nn).SmythBrobyGerberAlg: return each sum times its own count,(acc.pos * acc.cpos, acc.neg * acc.cneg, acc.nn * acc.cnn).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
comovement_finalise: the caller that reaches this function once per pair.comovement_ratioSmythBrobyDeltaAlgSmythBrobyGerberAlgSmythBrobyCountAlg
References
- [14]
- W. Smyth and D. Broby. An enhanced Gerber statistic for portfolio optimization. Finance Research Letters 49, 103229 (2022).