quantlab.risk.bias.bias_statistics#
- quantlab.risk.bias.bias_statistics(realized, forecast, window=None, min_observations=None)[source]#
Return the bias statistics of volatility forecasts against realized returns.
- Parameters:
- realizedxr.DataArray
On
(timestamp, <portfolio dim>): each portfolio’s return over the bar aftertimestamp.- forecastxr.DataArray
Same coordinates: the volatility forecast for that return, made at
timestamp. A forecast that is missing or not positive gives no outcome.- windowint, optional
Bars per rolling window; without it no rolling statistics are returned. USE4 rolls 12-month windows (252 daily bars).
- min_observationsint, optional
Fewest outcomes a rolling window needs for a bias statistic; NaN with fewer. Defaults to half the window, rounded up (our choice: a portfolio may miss a few bars, a symbol on a halt).
- Returns:
- xr.Dataset
realized,forecastandoutcome(their ratio, A1) on the input’s dimensions. Over the whole range, one window (A2, A3), per portfolio:bias,count(outcomes) andband(the half-width of the confidence interval,sqrt(2 / count)). Withwindow, on the input’s dimensions, labelled by each window’s last bar:rolling_bias(A4),rolling_countandrolling_band; and ontimestamp, across portfolios,rolling_mean(A5),rolling_p5,rolling_p95androlling_mrad(A6).
- Raises:
- ValueError
If
windowis below 2, ormin_observationsis not between 2 andwindow.
Examples
Twenty portfolios over 1000 bars, their returns drawn with exactly the forecast volatility
sigma:>>> import numpy as np, pandas as pd, xarray as xr >>> rng = np.random.default_rng(0) >>> sigma = xr.DataArray( ... np.full((1000, 20), 0.01), dims=("timestamp", "portfolio"), ... coords={"timestamp": pd.bdate_range("2020-01-01", periods=1000)}, ... ) >>> returns = sigma * rng.standard_normal((1000, 20)) >>> stats = bias_statistics(returns, sigma, window=252) >>> round(float(stats["bias"].mean()), 2), round(float(stats["band"][0]), 3) (1.0, 0.045) >>> round(float(stats["rolling_mean"].isel(timestamp=-1)), 2) 0.99
A forecast of half the volatility underpredicts risk by two:
>>> round(float(bias_statistics(returns, sigma / 2)["bias"].mean()), 2) 1.99