diff --git a/src/fpm_risk_model/accuracy/bias.py b/src/fpm_risk_model/accuracy/bias.py index 291d157..dcd7e46 100644 --- a/src/fpm_risk_model/accuracy/bias.py +++ b/src/fpm_risk_model/accuracy/bias.py @@ -1,3 +1,5 @@ +from typing import Optional + from numpy import ndarray, sqrt, sum from pandas import Series @@ -39,3 +41,47 @@ def compute_standardized_returns( b_t[index] = returns / vol return b_t + + +def compute_bias_statistics( + X: ndarray, + weights: ndarray, + rolling_risk_model: RollingFactorRiskModel, + rolling_timeframe: int, + min_periods: Optional[int] = None, +) -> Series: + """ + Compute the bias statistics. + + Standardized return is defined as + + .. math:: + b_t = \\frac{r_t}{\\sigma_t} + + and the bias statistic is expressed as + + ..math:: + 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. + rolling_risk_model: RollingFactorRiskModel + The rolling risk model. + + Returns + ------- + Series + A timeseries of bias statistic. + """ + standardized_returns = compute_standardized_returns( + X=X, + weights=weights, + rolling_risk_model=rolling_risk_model, + ) + return standardized_returns.rolling( + rolling_timeframe, min_periods=min_periods + ).std() diff --git a/tests/accuracy/test_bias.py b/tests/accuracy/test_bias.py index 18b3ed3..99b8a16 100644 --- a/tests/accuracy/test_bias.py +++ b/tests/accuracy/test_bias.py @@ -2,7 +2,10 @@ from pandas import Series from pandas.testing import assert_series_equal -from fpm_risk_model.accuracy.bias import compute_standardized_returns +from fpm_risk_model.accuracy.bias import ( + compute_bias_statistics, + compute_standardized_returns, +) def test_compute_standardized_returns( @@ -18,3 +21,18 @@ def test_compute_standardized_returns( index=list(rolling_factor_risk_model.keys()), ) assert_series_equal(standardized_returns, expected_standardized_returns) + + +def test_compute_bias_statistics(daily_returns, weights, rolling_factor_risk_model): + bias_statistics = compute_bias_statistics( + X=daily_returns, + weights=weights, + rolling_risk_model=rolling_factor_risk_model, + rolling_timeframe=5, + min_periods=0, + ) + expected_bias_statistics = Series( + array([nan, nan, 1.8305485, 1.47255984, 1.31524515]), + index=list(rolling_factor_risk_model.keys()), + ) + assert_series_equal(expected_bias_statistics, bias_statistics)