Implied Volatility: private API

PortfolioOptimisers.realised_volFunction
realised_vol(ce::AbstractVarianceEstimator, X::MatNum, ws::Integer,
             chunk::Option{<:Integer} = nothing, T::Option{<:Integer} = nothing,
             N::Option{<:Integer} = nothing)

Compute realised volatility over non-overlapping rolling windows.

This function splits the last chunk * ws rows of X into chunk non-overlapping blocks of ws rows each, and computes the standard deviation of every asset within each block using the estimator ce. The result is a matrix of size (chunk, N) representing rolling realised volatilities.

Any estimator declared with @propagatable gets its obs_weights_view method generated from the @wprop tag its weights field already carries, so both shipped variance estimators answer with nothing written by hand. An estimator that holds weights outside that tag and defines no method of its own meets a block of ws rows with a vector of T weights, and the call raises.

Mathematical definition

Write $C$ for chunk and $w_s$ for ws. The blocks are counted back from the last observation, so the leading

\[\begin{align} o &= T - C w_s \end{align}\]

rows lie in no block. Block $c$ holds the rows

\[\begin{align} \mathcal{R}_c &= \{o + (c - 1) w_s + 1,\, \ldots,\, o + c w_s\}\,, \qquad c = 1, \ldots, C\,, \end{align}\]

and the realised volatility of asset $i$ over that block is

\[\begin{align} \mathrm{rv}_{c,\,i} &= \operatorname{std}\left(\{x_{t,\,i} : t \in \mathcal{R}_c\}\right)\,. \end{align}\]

Where:

  • $T$: Number of observations.
  • $x_{t,\,i}$: Return of asset $i$ at observation $t$.
  • $o$: Number of leading rows that no block covers.
  • $\mathcal{R}_c$: Rows of block $c$.
  • $\mathrm{rv}_{c,\,i}$: Realised volatility of asset $i$ over block $c$.

The last row of block $c$ is $o + c w_s$, which is the row implied_vol samples for the same window. A window count that does not divide $T$ therefore drops the oldest rows and never the newest.

Algorithm

  1. When chunk, T or N is nothing, read T and N from size(X) and set chunk to div(T, ws).
  2. Compute offset, the number of leading rows of X that no block covers.
  3. For each block c in 1:chunk, form rows, the ws row indices of that block.
  4. Slice ce to rows with obs_weights_view, giving the estimator that measures this block. It indexes every weights field on its own, so an estimator with a weighted mean and an unweighted dispersion keeps that shape, and an unweighted ce is returned unchanged.
  5. Call Statistics.std on that estimator and on the block's rows of X along dims = 1, giving one row of standard deviations. The estimator is called once per block, so it only ever reads a matrix.
  6. Stack the chunk rows with vcat, giving rv.

Arguments

  • ce: Variance estimator used to compute standard deviations within each window. Its observation weights describe the whole sample, and step 4 slices them to each block.
  • X: Data matrix of asset returns (observations × assets).
  • ws: Window size (number of observations per block).
  • chunk: Number of windows (computed as div(T, ws) if not provided).
  • T: Total number of observations (inferred from X if not provided).
  • N: Number of assets (inferred from X if not provided).

Returns

  • rv::Matrix{<:Number}: Rolling realised volatility matrix (chunks × assets).

Examples

julia> PortfolioOptimisers.realised_vol(SimpleVariance(),                                        [0.1 0.2; 0.3 0.1; 0.2 0.4; 0.1 0.1; 0.4 0.2;                                         0.2 0.3], 2)3×2 Matrix{Float64}: 0.141421   0.0707107 0.0707107  0.212132 0.141421   0.0707107

Related

source
PortfolioOptimisers.implied_volFunction
implied_vol(X::MatNum, ws::Integer, chunk::Option{<:Integer} = nothing,
            T::Option{<:Integer} = nothing, N::Option{<:Integer} = nothing)

Extract non-overlapping implied volatility observations from X at the end of each rolling window.

This function selects the rows of X that close each rolling window of size ws, and returns them as a view of shape (chunk, N).

Mathematical definition

Write $C$ for chunk and $w_s$ for ws. The sampled rows are

\[\begin{align} \mathcal{S} &= \{T - (C - 1) w_s,\, T - (C - 2) w_s,\, \ldots,\, T\}\,, \end{align}\]

whose $c$-th entry is

\[\begin{align} \mathcal{S}_c &= o + c w_s\,, \qquad o = T - C w_s\,, \qquad c = 1, \ldots, C\,. \end{align}\]

Where:

  • $T$: Number of observations.
  • $\mathcal{S}$: Sampled rows, one per window.
  • $o$: Number of leading rows that no window covers.

$\mathcal{S}_c$ is the last row of block $c$ of realised_vol, so the two functions read the same windows. The last sampled row is $T$ whatever $w_s$ is, so a window count that does not divide $T$ drops the oldest rows and never the newest.

Algorithm

  1. When chunk, T or N is nothing, read T and N from size(X) and set chunk to div(T, ws).
  2. Return the view of X over the rows (T - (chunk - 1) * ws):ws:T. The result is a view, so it shares its memory with X.

Arguments

  • X: Implied volatility matrix (observations × assets).
  • ws: Window size (number of observations per block).
  • chunk: Number of windows (computed as div(T, ws) if not provided).
  • T: Total number of observations (inferred from X if not provided).
  • N: Number of assets (inferred from X if not provided).

Returns

  • iv::SubArray: End-of-window implied volatility matrix (chunks × assets).

Examples

julia> PortfolioOptimisers.implied_vol([0.1 0.2; 0.3 0.1; 0.2 0.4; 0.1 0.1; 0.4 0.2;                                        0.2 0.3], 2)3×2 view(::Matrix{Float64}, 2:2:6, :) with eltype Float64: 0.3  0.1 0.1  0.1 0.2  0.3

Related

source
PortfolioOptimisers.coverage_reduced_ivpaFunction
coverage_reduced_ivpa(ivpa::Option{<:Number}, cmsk) -> Option{<:Number}
coverage_reduced_ivpa(ivpa::VecNum, cmsk::BitVector) -> VecNum

Reduce a per-asset implied volatility premium to the Coverage Universe.

A scalar premium applies to every asset, so it survives the reduction untouched. A vector premium carries one entry per asset, so it takes the same slice X takes.

Arguments

  • ivpa: The implied volatility premium adjustment, a scalar, a vector, or nothing.
  • cmsk: The Coverage Universe, or nothing.

Returns

  • ivpa: The premium on the Coverage Universe.

Related

source