Bias

The objective of a bias test is to examine the forecasting accuracy of volatility on a time series of observed portfolio returns.

First, standardardized returns \(b_t\) are defined as the observed returns \(r_t\) normalised by the volatility forecast \(\sigma_t\) deduced from the risk model

\[ b_t = \frac{r_t}{\sigma_t} \]

where \(r_t\) is the return obtained from the price change in the interval \([t, t+1]\) and \(\sigma_t\) is the volatility forecast of which its risk model is trained / fitted until time \(t\).

Given a rolling window \(T\), the bias statistic is defined as

\[ B_T(t) = \sqrt{\frac{1}{T-1} \sum_{\tau=t-T+1}^{t} (b_{\tau} - \bar{b})^2} \]

The expected bias statistic would be equal to one, while the risk model

  • overestimates the risk if it is below one, and

  • underestimates the risk otherwise

Assuming the portfolio returns are normally distributed, the 95% confidence bounds for \(B_T(t)\) are between \(1-\sqrt{\frac{2}{T}}\) and \(1+\sqrt{\frac{2}{T}}\).

Usage

Assume that you have market returns returns in a DataFrame, portfolio weights weights in a DataFrame (it could be equally weighted, or market cap weighted), and rolling risk models, which can be a RollingRiskModel object, or just a dictionary of covariances. To compute the bias statistic in a 21-day rolling window, you can use the following code snippet.

from fpm_risk_model.accuracy.bias import compute_bias_statistics

compute_bias_statistics(
  X=returns,
  weights=weights,
  rolling_risk_model=rolling_risk_model,
  window=30,
)

In the meantime, if you have the forecast portfolio volatility, named forecast_vols, from vendor, you can directly pass it into the function as well.

compute_bias_statistics(
  X=returns,
  weights=weights,
  forecast_vols=forecast_vols,
  window=30,
)

Please refer to the below section for more information.

Reference

Alexander, Carol (2009). Market risk analysis, value at risk models. John Wiley & Sons.

Module

fpm_risk_model.accuracy.bias.compute_standardized_returns(X: DataFrame, weights: DataFrame, rolling_risk_model: Optional[Union[RollingFactorRiskModel, Dict[Any, Any]]] = None, forecast_vols: Optional[Series] = None, cov_halflife: Optional[float] = None) Series

Compute the standardized returns given the rolling risk model.

Standardized return is defined as

\[b_t = \frac{r_t}{\sigma_t}\]

Parameters

X: ndarray

The instrument forecast returns.

weights: ndarray

Weights of the instruments.

rolling_risk_model: Union[RollingFactorRiskModel, Dict[Any, Any]]

A rolling risk model object or dictionary of covariances of which the keys and values are dates and covariances.

forecast_vols: Series

The forecast volatility.

cov_halflife: Optional[float]

Halflife in computing covariances.

Returns

Series

A timeseries of standardized returns.

fpm_risk_model.accuracy.bias.compute_bias_statistics(X: DataFrame, weights: DataFrame, window: int, rolling_risk_model: Optional[Union[RollingFactorRiskModel, Dict[Any, Any]]] = None, forecast_vols: Optional[Series] = None, min_periods: Optional[int] = None, cov_halflife: Optional[float] = None) Series

Compute the bias statistics.

Standardized return is defined as

\[b_t = \frac{r_t}{\sigma_t}\]

and the bias statistic is expressed as

\[B_T(t) = \sqrt{\frac{1}{T} \sigma_{\tau}(b_{\tau} - \bar{b})^2}\]

Parameters

X: ndarray

The instrument forecast returns.

weights: ndarray

Weights of the instruments.

forecast_vols: Optional[Series]

The forecast volatility.

rolling_risk_model: Union[RollingFactorRiskModel, Dict[Any, Any]]

A rolling risk model object or dictionary of covariances of which the keys and values are dates and covariances.

cov_halflife: Optional[float]

Halflife in computing covariances.

Returns

Series

A timeseries of bias statistic.