The summary, comparison and re-projection of a covariance forecast evaluation
Three verbs above CovarianceForecastEvaluationResult. covariance_forecast_summary answers a columnar Result with one entry per evaluation, so a side-by-side of two forecasts is its length-2 case; covariance_forecast_compare tests the per-step loss difference of two forecasts with a Diebold–Mariano–West statistic, because the level of a loss on a proxy is not a reading and its difference is; and covariance_forecast_portfolio re-projects stored forecasts on a new test portfolio.
PortfolioOptimisers.CovarianceForecastSummaryResult — Type
struct CovarianceForecastSummaryResult{__T_names, __T_mahalanobis_mean, __T_mahalanobis_median, __T_mahalanobis_p5, __T_mahalanobis_p95, __T_mahalanobis_band_lo, __T_mahalanobis_band_hi, __T_diagonal_mean, __T_diagonal_median, __T_diagonal_p5, __T_diagonal_p95, __T_diagonal_band_lo, __T_diagonal_band_hi, __T_bias_statistic, __T_bias_p5, __T_bias_p25, __T_bias_p75, __T_bias_p95, __T_qlike_mean, __T_frobenius_mean, __T_portfolio_qlike_mean, __T_levels, __T_exceedance, __T_n_steps, __T_n_portfolios, __T_alpha} <: AbstractResultThe headline statistics of one or more covariance forecast evaluations, one entry per evaluation.
CovarianceForecastSummaryResult is what covariance_forecast_summary returns. It is columnar, on an axis whose entries are the evaluations that were summarised, so a single evaluation is the length-1 case and a side-by-side of two forecasts is the length-2 case, and no comparison class ships beside it — the shape ForecastSummaryResult has for the return forecasts. Every column is read off the per-step diagnostics of a CovarianceForecastEvaluationResult.
Mathematical definition
\[\begin{align} \bar{m} &= \frac{\sum_{t=1}^{M} \nu_t\, m_t}{\sum_{t=1}^{M} \nu_t}\,, \quad \nu_t = \operatorname{dof}(N_t, h_t)\,, \\ \bar{d} &= \frac{\sum_{t=1}^{M} \nu'_t\, \bar{d}_t}{\sum_{t=1}^{M} \nu'_t}\,, \quad \nu'_t = \operatorname{dof}'(h_t)\,, \\ \bar{m} &\in 1 \pm z_{\alpha/2} \sqrt{\frac{2}{\sum_{t=1}^{M} \nu_t}}\,, \quad \bar{d} \in 1 \pm z_{\alpha/2} \sqrt{\frac{2}{\sum_{t=1}^{M} \nu'_t}}\,, \\ B &= \sqrt{\frac{1}{M - 1} \sum_{t=1}^{M} \left(b_t - \bar{b}\right)^2}\,, \\ e_q &= \frac{1}{M} \sum_{t=1}^{M} \mathbb{1}\left[\nu_t\, m_t > \chi^2_{\nu_t}(q)\right]\,. \end{align}\]
Where:
- $\bar{m}$: Mahalanobis ratio over the walk-forward.
- $m_t$: Mahalanobis ratio of step $t$.
- $\nu_t$: Degrees of freedom of the Mahalanobis statistic of step $t$ under a Gaussian null, $N_t h_t$ for the realised covariance and $N_t$ for the horizon return.
- $N_t$: Number of active assets at step $t$.
- $h$: Horizon of a step, the number of observations the forecast is judged on.
- $M$: Steps of the walk-forward, the number of forecasts a run scores.
- $\bar{d}$: Diagonal ratio over the walk-forward.
- $\bar{d}_t$: Mean of the diagonal ratio over the active assets of step $t$.
- $\nu'_t$: Degrees of freedom of one asset's step ratio under a Gaussian null, $h_t$ for the realised covariance and $1$ for the horizon return.
- $z_{\alpha/2}$: Upper $\alpha / 2$ quantile of the standard normal distribution.
- $B$: Bias statistic of a test portfolio, the sample standard deviation of its standardised returns.
- $b_t$: Standardised return of the test portfolio at step $t$.
- $e_q$: Exceedance rate at level $q$, the share of steps whose Mahalanobis statistic exceeds the chi-squared quantile of that level.
Under a Gaussian null with the forecast correct and the whitened returns independent, $\sum_t \nu_t\, \bar{m} \sim \chi^2_{\sum_t \nu_t}$, so $\mathbb{E}[\bar{m}] = 1$ and the band holds with probability $1 - \alpha$; the ratio-of-sums form weights a step by its degrees of freedom, which is the plain mean when every step has the same $N_t$ and $h_t$. The band on $\bar{d}$ is the band of one asset's ratio, and it is conservative for a mean over assets whose ratios are correlated. If the whitened coordinates have fourth moment $\kappa$ in place of the Gaussian three, the variance of $\bar{m}$ is $(\kappa - 1) / \sum_t \nu_t$ and the band widens by $\sqrt{(\kappa - 1) / 2}$; the correction is stated here and not computed, so the Gaussian band is a reference and not a test. The median of $\chi^2_{\nu} / \nu$ lies below one, near $1 - 2 / (9 \nu)$, so a median is compared with that and never with one. $B = 1$ under a calibrated forecast, above one when the portfolio's risk is under-predicted. $e_q$ is $1 - q$ under the Gaussian null, and it rises with heavy tails as well as with a misspecified forecast.
Fields
names: Name of each evaluation, one entry per evaluation.
mahalanobis_mean: Mahalanobis ratio over the walk-forward, the degrees-of-freedom-weighted mean of the per-step ratios. One entry per evaluation; the target is one.
mahalanobis_median: Median of the per-step Mahalanobis ratio. One entry per evaluation; its target under a Gaussian null lies below one.
mahalanobis_p5: Fifth percentile of the per-step Mahalanobis ratio. One entry per evaluation.
mahalanobis_p95: Ninety-fifth percentile of the per-step Mahalanobis ratio. One entry per evaluation.
mahalanobis_band_lo: Lower end of the Gaussian band on the Mahalanobis ratio at levelalpha. One entry per evaluation.
mahalanobis_band_hi: Upper end of the Gaussian band on the Mahalanobis ratio at levelalpha. One entry per evaluation.
diagonal_mean: Diagonal ratio over the walk-forward, the degrees-of-freedom-weighted mean of the per-step mean over active assets. One entry per evaluation; the target is one.
diagonal_median: Median of the per-step diagonal ratio, each step's being its mean over active assets. One entry per evaluation.
diagonal_p5: Fifth percentile of the per-step diagonal ratio. One entry per evaluation.
diagonal_p95: Ninety-fifth percentile of the per-step diagonal ratio. One entry per evaluation.
diagonal_band_lo: Lower end of the Gaussian band on one asset's diagonal ratio at levelalpha. One entry per evaluation.
diagonal_band_hi: Upper end of the Gaussian band on one asset's diagonal ratio at levelalpha. One entry per evaluation.
bias_statistic: Bias statistic, the median over the test portfolios of the sample standard deviation of each one's standardised returns. One entry per evaluation; the target is one.
bias_p5: Fifth percentile of the bias statistic over the test portfolios. One entry per evaluation.
bias_p25: Twenty-fifth percentile of the bias statistic over the test portfolios. One entry per evaluation.
bias_p75: Seventy-fifth percentile of the bias statistic over the test portfolios. One entry per evaluation.
bias_p95: Ninety-fifth percentile of the bias statistic over the test portfolios. One entry per evaluation.
qlike_mean: Mean QLIKE loss over the steps. One entry per evaluation; only a difference between evaluations is a reading.
frobenius_mean: Mean Frobenius loss over the steps. One entry per evaluation; only a difference between evaluations is a reading.
portfolio_qlike_mean: Median over the test portfolios of each one's mean portfolio QLIKE loss. One entry per evaluation.
levels: Confidence levels of the exceedance rates, as handed to the summary.
exceedance: Exceedance rate of the per-step Mahalanobis statistic against the chi-squared quantile of each level,evaluations × levels. Its target is one less the level.
n_steps: Number of steps of each evaluation. One entry per evaluation.
n_portfolios: Number of test portfolios of each evaluation. One entry per evaluation.
alpha: Level of the Gaussian bands.
Constructors
CovarianceForecastSummaryResult( names, mahalanobis_mean, mahalanobis_median, mahalanobis_p5, mahalanobis_p95, mahalanobis_band_lo, mahalanobis_band_hi, diagonal_mean, diagonal_median, diagonal_p5, diagonal_p95, diagonal_band_lo, diagonal_band_hi, bias_statistic, bias_p5, bias_p25, bias_p75, bias_p95, qlike_mean, frobenius_mean, portfolio_qlike_mean, levels, exceedance, n_steps, n_portfolios, alpha) -> CovarianceForecastSummaryResultArguments correspond to the struct's fields, in the order they are declared. The type is a Result, so covariance_forecast_summary builds it and a caller reads it; there is no keyword constructor, and the type validates nothing of its own.
Related
PortfolioOptimisers.CovarianceForecastComparisonResult — Type
struct CovarianceForecastComparisonResult{__T_names, __T_mean_difference, __T_variance, __T_z, __T_p, __T_lags, __T_n_steps} <: AbstractResultThe Diebold–Mariano–West comparison of two covariance forecasts, one row per loss.
CovarianceForecastComparisonResult is what covariance_forecast_compare returns. It is columnar on an axis whose entries are the losses compared: the whole-matrix QLIKE, the Frobenius loss, and the portfolio QLIKE of each test portfolio. A positive mean difference says the first forecast lost more.
Fields
names: Name of each loss compared:"qlike","frobenius", then"portfolio_qlike_k"for each test portfoliok.
mean_difference: Mean over the steps of the first forecast's loss less the second's. One entry per loss.
variance: Newey–West long-run variance of the per-step loss difference, atlagslags. One entry per loss.
z: Diebold–Mariano–West statistic, asymptotically standard normal under equal expected loss. One entry per loss.
p: Two-sided p-value of the statistic against the standard normal. One entry per loss.
lags: Number of lags of the Bartlett kernel.
n_steps: Number of steps compared.
Constructors
CovarianceForecastComparisonResult( names, mean_difference, variance, z, p, lags, n_steps) -> CovarianceForecastComparisonResultArguments correspond to the struct's fields, in the order they are declared. The type is a Result, so covariance_forecast_compare builds it and a caller reads it; there is no keyword constructor, and the type validates nothing of its own.
Related
PortfolioOptimisers.covariance_forecast_summary — Function
covariance_forecast_summary(cfers::AbstractVector{<:CovarianceForecastEvaluationResult};
names = nothing, alpha::Real = 0.05,
levels = (0.95, 0.99)) -> CovarianceForecastSummaryResult
covariance_forecast_summary(cfer::CovarianceForecastEvaluationResult; kwargs...)Summarise one or more covariance forecast evaluations, one entry per evaluation.
The verb over CovarianceForecastEvaluationResult: the mean, median and tail percentiles of the two calibration ratios with the Gaussian band on each mean, the bias statistic of the test portfolios with its cross-portfolio percentiles, the mean of each loss, and the exceedance rate of the Mahalanobis statistic at each level. The single-Result method is the length-1 case. The mean of a ratio is a ratio of sums, weighted by each step's degrees of freedom under the evaluation's target (target_dof), so a date walk-forward whose folds differ in length weights each by its length; under an index walk-forward it is the plain mean.
Algorithm
- Per evaluation, weight the per-step Mahalanobis ratio by its degrees of freedom and reduce the diagonal ratio to a per-step mean over active assets, then take the weighted mean, the median and the fifth and ninety-fifth percentiles of each.
- Width the Gaussian band of each mean at
alphafrom the summed degrees of freedom. - Take the sample standard deviation of each test portfolio's standardised returns, and its median and percentiles over the portfolios.
- Take the mean of each loss over the steps, and the median over the portfolios of the mean portfolio QLIKE.
- Count the steps whose Mahalanobis statistic exceeds the chi-squared quantile of each level.
Arguments
cfers: The evaluations to summarise.names: A name per evaluation, ornothingfor"forecast_1","forecast_2", ….alpha: Level of the Gaussian bands,1 - alphacoverage.levels: Confidence levels of the exceedance rates.
Validation
cfersis not empty. AnIsEmptyErroris thrown otherwise.nameshas one entry per evaluation when given. ADimensionMismatchis thrown otherwise.0 < alpha < 1, and every level lies in(0, 1). ADomainErroris thrown otherwise.
Returns
summary::CovarianceForecastSummaryResult: The columnar summary.
Related
PortfolioOptimisers.covariance_forecast_compare — Function
covariance_forecast_compare(a::CovarianceForecastEvaluationResult, b::CovarianceForecastEvaluationResult;
lags::Integer = maximum(a.horizon) - 1) -> CovarianceForecastComparisonResultTest whether two covariance forecasts differ in expected loss, per loss.
Two mean losses side by side invite exactly the reading a loss on a proxy cannot bear — the level of a loss on a proxy is not a calibration reading — so the comparison tests the difference instead. For each loss the per-step difference is a series whose mean is tested against zero with a long-run variance that absorbs the overlap of consecutive steps: the Bartlett kernel at $h - 1$ lags by default, the overlap of steps that share observations.
Mathematical definition
\[\begin{align} \delta_t &= L^{A}_t - L^{B}_t\,, \\ \bar{\delta} &= \frac{1}{M} \sum_{t=1}^{M} \delta_t\,, \\ \hat{\omega}^2 &= \hat{\gamma}_0 + 2 \sum_{k=1}^{\ell} \left(1 - \frac{k}{\ell + 1}\right) \hat{\gamma}_k\,, \\ \mathrm{DMW} &= \frac{\sqrt{M}\, \bar{\delta}}{\sqrt{\hat{\omega}^2}}\,. \end{align}\]
Where:
- $\delta_t$: Difference of the losses of forecasts $A$ and $B$ at step $t$.
- $\bar{\delta}$: Mean loss difference over the walk-forward.
- $\hat{\omega}^2$: Long-run variance of $\delta_t$, the Bartlett-kernel estimate with $\ell$ lags.
- $\hat{\gamma}_k$: Sample autocovariance of $\delta_t$ at lag $k$.
- $\ell$: Number of lags, $h - 1$ by default.
- $h$: Horizon of a step, the number of observations the forecast is judged on.
- $M$: Steps of the walk-forward, the number of forecasts a run scores.
- $\mathrm{DMW}$: Diebold–Mariano–West statistic.
Under equal expected loss, $\mathrm{DMW}$ is asymptotically standard normal. A positive value says forecast $A$ lost more than forecast $B$. Two identical forecasts have $\bar{\delta} = 0$ and $\hat{\omega}^2 = 0$, so their statistic is not a number.
Arguments
a: The first evaluation.b: The second evaluation.lags: Number of lags of the Bartlett kernel.
Validation
a.dates == b.datesanda.horizon == b.horizon. AnArgumentErroris thrown otherwise: two evaluations over different steps compare nothing.aandbcarry the same number of test portfolios. ADimensionMismatchis thrown otherwise.0 <= lags < n_steps. ADomainErroris thrown otherwise.
Returns
cmp::CovarianceForecastComparisonResult: One row per loss.
Related
PortfolioOptimisers.covariance_forecast_portfolio — Function
covariance_forecast_portfolio(cfer::CovarianceForecastEvaluationResult, rd::ReturnsResult,
w::Option{<:VecNum_VecVecNum}) -> NamedTupleRe-project the stored forecasts of an evaluation on a new test portfolio.
The verb a request for the forecasts buys: with store_forecasts = true the Result holds every step's forecast and the location it was centred on, so a new portfolio is scored without rerunning the loop. Each step reads its stored forecast and location, the test rows rd.X[cfer.test_idx[i], :], and the new w, through covariance_forecast_step, and answers the two portfolio diagnostics. Handing the evaluation's own w reproduces its columns.
Arguments
cfer: The evaluation, run withstore_forecasts = true.rd: The returns result to use.w: The test portfolios on the full universe, ascovariance_forecast_evaluationtakes them.
Validation
cfer.sigmais notnothing. AnArgumentErroris thrown otherwise, pointing atstore_forecasts.rd.Xis notnothing. AnIsNothingErroris thrown otherwise.
Returns
proj::NamedTuple:standardised_returnandportfolio_qlike, eachsteps × portfolios.
Related