Mahalanobis level closure: private API

Functions

PortfolioOptimisers.level_closure_factors — Function
level_closure_factors(
    methods::Tuple,
    decay::Number,
    K::Integer,
    n::Integer,
    hac_lags::Union{Nothing, Integer, AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}}}
) -> Vector

Computes the Mahalanobis bias factor of each method at one count of observations with the closure of GaussianLevelRecursion.

Algorithm

  1. Tabulate the lattice of the count with mahalanobis_lattice, round the normalisation to it, continue it past the cut with mahalanobis_cut!, and fill the differences of mahalanobis_pair_differences!, as mahalanobis_level_bias does.
  2. Run $n - 1$ levels of level_closure_step from a removed part of zero with no variance.
  3. Read each factor off level_closure_transform with regime_bias_factor.

Arguments

  • methods::Tuple: Regime adjustment methods.
  • decay::Number: Decay of the weights.
  • K::Integer: Count of observations.
  • n::Integer: Count of assets that contribute to the statistic, at least two.
  • hac_lags::Option{<:Union{<:Integer, <:VecNum}}: Count of HAC lags, the weight of each lag, or nothing.

Returns

  • factors::VecNum: The factor of each method.

Related

source
PortfolioOptimisers.level_closure_maps — Function
level_closure_maps(
    grid::NamedTuple
) -> NamedTuple{(:By, :NV), <:Tuple{Any, Any}}

Makes the linear maps of the closure on the grid of mahalanobis_bias_grid.

The state of the closure is the removed part $q$ on the nodes, the eight Chebyshev nodes and the grid past the junction. The vector v of mahalanobis_level_step! holds the Chebyshev values, the five grid values at the junction, which the Chebyshev values fix, and the grid past it. The vector e of mahalanobis_q_integral! is linear in v. The closure reads both through one vector $y = (v; e)$.

Arguments

Returns

  • maps::NamedTuple: By, the map from the nodes to $y$; and NV, the length of v.

Related

source
PortfolioOptimisers.level_closure_point — Function
level_closure_point(
    ctx::NamedTuple,
    y::AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    z::Number
) -> Tuple{Any, Any}

Evaluates the mean field of one level at a point: the log-determinant $D = g - Q$ and its derivative $\rho = \rho_{0} - q$.

Arguments

  • ctx::NamedTuple: The context of level_closure_factors.
  • y::VecNum: The mean of $y = (v; e)$.
  • z::Number: Point to evaluate at.

Returns

  • (D, rho)::Tuple{<:Number, <:Number}: The two values.

Related

source
PortfolioOptimisers.level_closure_table — Function
level_closure_table(
    ctx::NamedTuple,
    y::AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}}
) -> LevelClosureTable

Tabulates the mean field of one level, $D$, $\rho$ and $z \rho'$, on a uniform grid of $\ln z$ of step $1/16$ from $-40$ to $40$, for level_closure_kernel, which reads them at about a million points. The derivative is a central difference of $\rho$ in $\ln z$ of step $10^{-4}$, on the interpolants of the grid, which are polynomials.

Arguments

Returns

  • table::LevelClosureTable: The grid and the three columns.

Related

source
PortfolioOptimisers.level_closure_integrand — Function
level_closure_integrand(
    tab::LevelClosureTable,
    s::Number,
    t::Number,
    a::Number,
    b::Number,
    fs::Tuple,
    ft::Tuple
) -> Any

Computes the integrand of level_closure_kernel at one point $(a, b)$.

$V(s) = \ln(x^{\top} M_{s} x) - \ln(x^{\top} M x)$, with $M_{s} = M (I + s M)^{-1}$, is the log-ratio that one removed direction $x$ adds to the log-determinant, and the kernel is the covariance of $V'(s)$ and $V'(t)$. The joint transform of the two quadratic forms of $\ln(x^{\top} M_{s} x)$ and $\ln(x^{\top} M_{t} x)$ at $(a, b)$ is $e^{-E/2}$, with $E = D(p) + D(q) - D(s) - D(t)$ and $p$, $q$ the roots of $(1 + s\mu)(1 + t\mu) + 2 a \mu (1 + t\mu) + 2 b \mu (1 + s\mu)$, so the mixed derivative in $s$ and $t$ reads $D$, $\rho$ and $\rho'$ at the roots. Where the roots are close next to their size, the term $p_{st} (\rho(p) - \rho(q))$, whose factor is $1 / (q - p)$, takes the divided difference of $\rho$, so the round-off of the two values is not amplified.

Arguments

  • tab::LevelClosureTable: The table of level_closure_table.
  • s::Number, t::Number: The two points of the kernel.
  • a::Number, b::Number: The point of the quadrature.
  • fs::Tuple, ft::Tuple: $(D, \rho)$ at s and at t.

Returns

  • val::Number: $e^{-E/2} (E_{s} E_{t} / 4 - E_{st} / 2)$.

Related

source
PortfolioOptimisers.level_closure_kernel — Function
level_closure_kernel(
    tab::LevelClosureTable,
    ::Type{T}
) -> Tuple{Any, Any}
level_closure_kernel(
    tab::LevelClosureTable,
    ::Type{T},
    tol::Number
) -> Tuple{Any, Any}

Computes the covariance that one removed direction adds to the removed part of the next level, $(1 + s)(1 + t) K_{\mathrm{int}}(s, t)$, on a grid of $\ln s$ of step one.

$K_{\mathrm{int}}(s, t) = \partial_{s} \partial_{t} \operatorname{Cov}(\ln A_{s}, \ln A_{t})$ with $A_{s} = x^{\top} M_{s} x$, for the mean field of the level, and $\operatorname{Cov}(\ln A_{s}, \ln A_{t}) = \iint \operatorname{Cov}(e^{-a A_{s}}, e^{-b A_{t}})\, \mathrm{d}\ln a\, \mathrm{d}\ln b$. The trapezoid rule of step one in $\ln a$ and $\ln b$ on $[-16, 26]$ holds it. The scaled kernel is bounded: it tends to $\operatorname{Var}[q(0)]$ at zero and to zero past the saturation, where $s q(s)$ is the count of the removed directions, so its interpolant has no error that $s t$ multiplies. The grid stops three steps past the point where the saturated count $s \rho(s)$ reaches its limit to $10^{-4}$, and the kernel is constant past it.

Arguments

Returns

  • (xc, K)::Tuple: The grid of $\ln s$ and the scaled kernel on it.

Related

source
PortfolioOptimisers.level_closure_span — Function
level_closure_span(
    dm::AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    tol::Number
) -> Any

Returns the points of the quadrature in $\ln a$ where one node of the kernel holds weight: the span where $|\partial_{s} m_{1}(s, a)|$ is at least tol times its largest value. The covariance of the two exponentials falls with each of the two factors, so the points outside the span add nothing that the rule resolves.

Arguments

  • dm::VecNum: $\partial_{s} m_{1}(s, a)$ at each point.
  • tol::Number: The relative floor.

Returns

  • span::UnitRange{Int}: The points.

Related

source
PortfolioOptimisers.level_closure_form — Function
level_closure_form(
    Y::AbstractMatrix{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    i0::Integer,
    w::NTuple{8, var"#s3185"} where var"#s3185"<:Number
) -> Any

Computes the quadratic form $w^{\top} Y w$ of one 8-point stencil of $y$, the variance of the value that the stencil reads.

Arguments

  • Y::MatNum: Covariance of $y$.
  • i0::Integer: Index of the first point of the stencil in $y$.
  • w::NTuple{8, <:Number}: Its weights.

Returns

  • val::Number: The form.

Related

source
PortfolioOptimisers.level_closure_node — Function
level_closure_node(
    grid::NamedTuple,
    NV::Integer,
    a::Integer,
    Y::AbstractMatrix{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}}
) -> NamedTuple{(:qi, :qw, :Qi, :Qw, :Yq, :YQ, :vQ, :cQq), <:Tuple{Vector, Vector, Vector, Vararg{Any, 5}}}

Returns the stencils of the removed part $q$ and of its integral $Q$ at one node, with their products with the covariance of $y$, which every step of the node reads.

A Chebyshev node reads its own value of v, and its integral through the Chebyshev weights; a grid node reads v and e at its own index.

Arguments

  • grid::NamedTuple: Grids of mahalanobis_bias_grid.
  • NV::Integer: The length of v.
  • a::Integer: The node.
  • Y::MatNum: The covariance of $y = (v; e)$.

Returns

  • node::NamedTuple: The indices qi, Qi and weights qw, Qw of the two stencils, Yq = Y q and YQ = Y Q, $\operatorname{Var}[Q]$ as vQ and $\operatorname{Cov}(Q, q)$ as cQq.

Related

source
PortfolioOptimisers.level_closure_pair — Function
level_closure_pair(
    Y::AbstractMatrix{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    y::AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    node::NamedTuple,
    qs::Tuple,
    Qs::Tuple,
    NV::Integer
) -> NTuple{4, Any}

Reads one step of one node of the closure: the values of the two stencils of the point $s + u$ on the mean, and the variance of $\Delta Q$ and its covariance with $\Delta q$, the differences between $s + u$ and the node.

Arguments

  • Y::MatNum: The covariance of $y = (v; e)$.
  • y::VecNum: The mean of $y$.
  • node::NamedTuple: The node, from level_closure_node.
  • qs::Tuple, Qs::Tuple: The stencils of the point on v and on e, from the pairs of mahalanobis_bias_grid.
  • NV::Integer: The length of v.

Returns

  • (yq, yQ, var, cov)::NTuple{4, <:Number}: $q$ and $Q$ at the point, $\operatorname{Var}[\Delta Q]$ and $\operatorname{Cov}(\Delta Q, \Delta q)$.

Related

source
PortfolioOptimisers.level_closure_spread — Function
level_closure_spread(
    xc::AbstractRange,
    Kc::AbstractMatrix{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    sn::AbstractArray{T, 1}
) -> Any

Reads the scaled kernel of level_closure_kernel at every pair of nodes, and removes its scale: $K_{\mathrm{int}}(s, t)$ is the kernel read with a clamped 8-point Lagrange stencil in $\ln s$ and in $\ln t$, over $(1 + s)(1 + t)$. The clamp holds the kernel constant past the ends of its grid.

Arguments

  • xc::AbstractRange: The grid of $\ln s$ of the kernel.
  • Kc::MatNum: The scaled kernel on it.
  • sn::AbstractVector{T}: The nodes.

Returns

  • Kint::Matrix{T}: The kernel at each pair of nodes.

Related

source
PortfolioOptimisers.level_closure_step — Function
level_closure_step(
    ctx::NamedTuple,
    nq::AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    Kq::AbstractMatrix{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}}
) -> Tuple{Any, Any}

Runs one level of the closure: the mean of the removed part on the nodes and its covariance.

Algorithm

  1. Map the mean and the covariance of the nodes to $y = (v; e)$.
  2. At each node $s$ and step $u$, average the integrand of mahalanobis_level_step! over the Gaussian law of the level: with $\Delta Q$ and $\Delta q$ the differences between $s + u$ and $s$, the integrand is $e^{-\Delta D / 2 + \operatorname{Var}[\Delta Q] / 8} (\Delta \rho - \operatorname{Cov}(\Delta Q, \Delta q) / 2)$.
  3. Accumulate the linear response of the step: a perturbation of the level moves the new removed part by $\frac{h}{2} \sum_{u} \psi (\Delta \delta q - \frac{1}{2} \Delta \rho\, \Delta \delta Q)$. Every term of it vanishes as $u \to 0$.
  4. The new covariance is the response of the old one plus the kernel of level_closure_kernel at the nodes, read with a clamped 8-point Lagrange stencil.

Arguments

  • ctx::NamedTuple: The context of level_closure_factors.
  • nq::VecNum: The mean of the removed part on the nodes.
  • Kq::MatNum: Its covariance.

Returns

  • (nq, Kq)::Tuple: The mean and the covariance of the next level.

Related

source
PortfolioOptimisers.level_closure_transform — Function
level_closure_transform(
    ctx::NamedTuple,
    y::AbstractVector{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}},
    Y::AbstractMatrix{<:Union{var"#s152", var"#s69"} where {var"#s152"<:Number, var"#s69"<:AbstractJuMPScalar}}
) -> Tuple{Any, Any}

Evaluates the last transform of the closure, $e^{-D/2 + \operatorname{Var}[Q]/8}$, on the output grid, with the cut of mahalanobis_transform where the count has one.

Arguments

  • ctx::NamedTuple: The context of level_closure_factors.
  • y::VecNum: The mean of $y = (v; e)$.
  • Y::MatNum: Its covariance.

Returns

  • (so, L)::Tuple{<:VecNum, <:VecNum}: The grid and the transform on it.

Related

source