cdxcore.rolling#
Robust rolling statistics.
Recursive exponentially weighted estimators of location and scale, in particular robust versions which use
the median and MAD for initialization, flag outliers, and do not let them move the location. They are available
for regular time steps (cdxcore.rolling.robust_rolling_ew()) and irregular time steps
(cdxcore.rolling.robust_rolling_dt_ew()). cdxcore.rolling.robust_fixed_window() is the non-recursive analogue.
import numpy as np
from cdxcore.rolling import robust_rolling_ew, robust_rolling_dt_ew
x = np.random.normal( size=1000 )
x[500] = 10.
loc, vol, outlier = robust_rolling_ew( x, window=20 ) # outlier[500] is True
dt = np.random.uniform( 0.001, 0.01, size=1000 )
dx = 0.1 * dt + 0.2 * np.sqrt( dt ) * np.random.normal( size=1000 )
mu, sigma, outlier = robust_rolling_dt_ew( dx, dt, twindow=0.25, scale_by_dt=True, normalize_by_dt=True )
If numba is installed the recursions are compiled, otherwise they run as plain python loops.
Module Attributes
Gaussian consistency factor for a median absolute deviation. |
Functions
|
Robust location and scale of a fixed set of equally weighted samples. |
|
Computes a robust recursive exponentially weighted mean and volatility for irregular time steps. |
|
Computes a robust recursive exponentially weighted mean and volatility. |
|
Computes a standard recursive exponentially weighted mean and volatility, initialized over |
- cdxcore.rolling.MAD_NORMAL_SCALE = 1.482602218505602#
Gaussian consistency factor for a median absolute deviation.
- cdxcore.rolling.robust_fixed_window(x, dt=None, cutoff=2.5, scale_by_dt=False, normalize_by_dt=False, min_scale=None)[source]#
Robust location and scale of a fixed set of equally weighted samples.
This is the non-recursive analogue of
robust_rolling_dt_ew(): the location is the median, and the scale is the MAD around it, multiplied by 1.4826. There is no warm-up and no outlier mask;cutoffis only retained to match the interface of the recursive functions.If
dtis provided andscale_by_dtisTruethen the modelx[i] = mu * dt[i] + sigma * sqrt(dt[i]) * eps[i]
is assumed:
muis the median ofx/dt, andsigmais the scaled MAD of the residuals(x[i] - mu*dt[i]) / sqrt(dt[i]). Ifnormalize_by_dtisTruethe function returnsmuandsigma. Otherwise it returnsmu*dt_refandsigma*sqrt(dt_ref)wheredt_refis the median ofdt, i.e. quantities in the units ofx.- Parameters:
- xnp.ndarray
One-dimensional samples.
- dtnp.ndarray, optional
Time steps, strictly positive. Ignored unless
scale_by_dtisTrue.- cutofffloat, optional
Not used. Default
2.5.- scale_by_dtbool, optional
Use the increment model described above. Requires
dt. DefaultFalse.- normalize_by_dtbool, optional
Return drift rate and diffusion scale. Requires
scale_by_dt. DefaultFalse.- min_scalefloat, optional
Floor for the scale. Defaults to machine precision times
max(1, max(|x|)).
- Returns:
- locationfloat
Robust location.
- scalefloat
Robust scale, i.e. a standard deviation, not a variance.
- cdxcore.rolling.robust_rolling_dt_ew(x, dt, twindow=0.25, init=10, cutoff=2.5, scale_by_dt=False, normalize_by_dt=False, min_scale=None, on_zero_init='warn')[source]#
Computes a robust recursive exponentially weighted mean and volatility for irregular time steps.
The per-step weight is
w[t] = 1 - exp(-dt[t]/twindow), which is approximatelydt[t]/twindow. Withc = 1/E[min(|Z|,cutoff)]for a standard normalZthe update rule is as follows.If
scale_by_dtisFalse, with the innovationd[t] = x[t] - m[t-1]:m[t] = m[t-1] + w[t] * d[t] v[t] = (1-w[t]) * v[t-1] + w[t] * c * abs( clip( d[t], -cutoff*v[t-1], cutoff*v[t-1] ) )
If
xis itself a return-type quantity such asdSfor a stock, usescale_by_dt=True. The driftmis then a rate, and the innovation is normalized bysqrt(dt):d[t] = ( x[t] - m[t-1]*dt[t] ) / sqrt(dt[t]) m[t] = m[t-1] + w[t] / dt[t] * ( x[t] - m[t-1]*dt[t] ) v[t] = (1-w[t]) * v[t-1] + w[t] * c * abs( clip( d[t], -cutoff*v[t-1], cutoff*v[t-1] ) )
If all time steps are equal to
dtandtwindow = window*dt, this is equivalent torobust_rolling_ew()except that the estimated quantity is the mean ofdx/dt, and the volatility is that of(dx - m*dt)/sqrt(dt).An outlier is identified if
|d[t]|exceedscutoff * v[t-1]. In that casem[t] = m[t-1]. The volatility is updated using the capped innovation and is floored atmin_scale.The state at index
init-1is initialized with the median and MAD (scaled by 1.4826) ofx[:init], or ofx[:init]/dt[:init]and of the normalized innovations ifscale_by_dtisTrue. These are weighted by the weights the observations have in the terminal state of the recursion. Earlier elements are NaN.- Parameters:
- xnp.ndarray
One-dimensional time series.
- dtnp.ndarray
Time steps, strictly positive, same shape as
x.- twindowfloat, optional
Time constant of the weights: a new observation gets the weight
1 - exp(-dt/twindow). Default0.25.- initint, optional
Initial period. Default
10.- cutofffloat, optional
Normalized innovations exceeding this level are considered outliers. Default
2.5.- scale_by_dtbool, optional
Scale returns by
dtand volatilities bysqrt(dt)during estimation, see above. DefaultFalse.- normalize_by_dtbool, optional
Requires
scale_by_dt; otherwise aValueErroris raised. IfTruereturn the drift ratemand volatilityv. IfFalsereturnm*dtandv*sqrt(dt), i.e. quantities in the units ofx. DefaultFalse.- min_scalefloat, optional
Floor for the volatility, in the units of the normalized innovation. Defaults to machine precision times the largest absolute normalized value of the first
initsteps (at least 1).- on_zero_initstr, optional
What to do if the median absolute deviation (MAD) of the initial period is zero. This happens if more than half of the (weighted) observations equal the median, e.g. for zero-inflated non-negative series such as variances or volumes. The initial volatility is then only
min_scale, any later observation which differs from the location is flagged as an outlier and cannot move it, and the location can stay stuck for a long time. It does not apply ifinitis 1. Options:"warn": issue aRuntimeWarningand continue. This is the default."ignore": continue silently."raise": raise anOverflowError."standard": initialize with the (weighted) mean and standard deviation of the initial period instead of the median and MAD. If the initial period is constant the standard deviation is zero as well, and the result is as for"ignore".
- Returns:
- meannp.ndarray
Robust mean.
- volnp.ndarray
Robust volatility, i.e. a standard deviation, not a variance.
- outliernp.ndarray
Boolean array which is
Truewhere an outlier was detected relative to the previous state.outlier[init-1]is alwaysFalse.
- cdxcore.rolling.robust_rolling_ew(x, window, init=10, cutoff=2.5, min_scale=None, on_zero_init='warn')[source]#
Computes a robust recursive exponentially weighted mean and volatility.
With
w = 1/window, the innovationd[t] = x[t] - m[t-1]andc = 1/E[min(|Z|,cutoff)]for a standard normalZ, the update rule is:m[t] = m[t-1] + w * d[t] v[t] = (1-w) * v[t-1] + w * c * abs( clip( d[t], -cutoff*v[t-1], cutoff*v[t-1] ) )
An outlier is identified if
|d[t]|exceedscutoff * v[t-1]. In that case the mean is not updated:m[t] = m[t-1]. The volatility is updated using the capped innovation as above and is floored atmin_scale.The state at index
init-1is initialized with the median and MAD (scaled by 1.4826) ofx[:init], weighted by the weights the observations have in the terminal state of the recursion. Earlier elements are NaN.- Parameters:
- xnp.ndarray
One-dimensional time series.
- windowfloat
The parametrization
w = 1/windowmeans that any new observation gets the same weight as it would get in a rolling estimator with sizewindow. Must be greater than 1.- initint, optional
Initial period. Default
10.- cutofffloat, optional
Normalized innovations exceeding this level are considered outliers. Default
2.5.- min_scalefloat, optional
Floor for the volatility. Defaults to machine precision times
max(1, max(|x[:init]|)).- on_zero_initstr, optional
What to do if the median absolute deviation (MAD) of the initial period is zero. This happens if more than half of the (weighted) observations equal the median, e.g. for zero-inflated non-negative series such as variances or volumes. The initial volatility is then only
min_scale, any later observation which differs from the location is flagged as an outlier and cannot move it, and the location can stay stuck for a long time. It does not apply ifinitis 1. Options:"warn": issue aRuntimeWarningand continue. This is the default."ignore": continue silently."raise": raise anOverflowError."standard": initialize with the (weighted) mean and standard deviation of the initial period instead of the median and MAD. If the initial period is constant the standard deviation is zero as well, and the result is as for"ignore".
- Returns:
- meannp.ndarray
Robust mean.
- volnp.ndarray
Robust volatility, i.e. a standard deviation, not a variance.
- outliernp.ndarray
Boolean array which is
Truewhere an outlier was detected.
- cdxcore.rolling.rolling_ew_std(x, window, init=10, cutoff=2.5)[source]#
Computes a standard recursive exponentially weighted mean and volatility, initialized over
initsteps.With
w = 1/windowand the innovationd[t] = x[t] - m[t-1]the update rule is:m[t] = m[t-1] + w * d[t] v[t] = (1-w) * ( v[t-1] + w * d[t]**2 )
Here
vis the variance; the function returnssqrt(v).An outlier is identified if
|d[t]|exceedscutoff * sqrt(v[t-1]). In that case the mean is not updated, and the variance is updated with the capped innovation:m[t] = m[t-1] v[t] = (1-w) * ( v[t-1] + w * clip( d[t], -cutoff*sqrt(v[t-1]), cutoff*sqrt(v[t-1]) )**2 )
The state is initialized at index
init-1with the mean and variance ofx[:init]; earlier elements are NaN.- Parameters:
- xnp.ndarray
One-dimensional time series.
- windowfloat
The parametrization
w = 1/windowmeans that any new observation gets the same weight as it would get in a rolling estimator with sizewindow. Must be greater than 1.- initint, optional
Initial period. Default
10.- cutofffloat, optional
Normalized innovations exceeding this level are considered outliers. Default
2.5.
- Returns:
- meannp.ndarray
Exponentially weighted mean.
- volnp.ndarray
Exponentially weighted volatility, i.e. a standard deviation.