Implied Volatility: private API
PortfolioOptimisers.realised_vol — Function
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
- When
chunk,TorNisnothing, readTandNfromsize(X)and setchunktodiv(T, ws). - Compute
offset, the number of leading rows ofXthat no block covers. - For each block
cin1:chunk, formrows, thewsrow indices of that block. - Slice
cetorowswithobs_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 unweightedceis returned unchanged. - Call
Statistics.stdon that estimator and on the block's rows ofXalongdims = 1, giving one row of standard deviations. The estimator is called once per block, so it only ever reads a matrix. - Stack the
chunkrows withvcat, givingrv.
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 asdiv(T, ws)if not provided).T: Total number of observations (inferred fromXif not provided).N: Number of assets (inferred fromXif 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.0707107Related
PortfolioOptimisers.implied_vol — Function
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
- When
chunk,TorNisnothing, readTandNfromsize(X)and setchunktodiv(T, ws). - Return the view of
Xover the rows(T - (chunk - 1) * ws):ws:T. The result is a view, so it shares its memory withX.
Arguments
X: Implied volatility matrix (observations × assets).ws: Window size (number of observations per block).chunk: Number of windows (computed asdiv(T, ws)if not provided).T: Total number of observations (inferred fromXif not provided).N: Number of assets (inferred fromXif 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.3Related
PortfolioOptimisers.coverage_reduced_ivpa — Function
coverage_reduced_ivpa(ivpa::Option{<:Number}, cmsk) -> Option{<:Number}
coverage_reduced_ivpa(ivpa::VecNum, cmsk::BitVector) -> VecNumReduce 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, ornothing.cmsk: The Coverage Universe, ornothing.
Returns
ivpa: The premium on the Coverage Universe.
Related