financialkit.time_series#

Returns and their stylized facts (the Hill tail index, moments and the Jarque-Bera test); tests of the random walk (serial correlation, Fama’s runs test, Box-Pierce and Ljung-Box, Lo-MacKinlay variance ratios); Yule-Walker autoregressions (scipy.linalg.solve_toeplitz), partial autocorrelations, ARMA simulation (scipy.signal.lfilter) and conditional maximum likelihood (scipy.optimize.least_squares) with AIC/BIC order selection; the augmented Dickey-Fuller and Engle-Granger tests with MacKinnon’s critical values; Hurst’s rescaled range and fractional Gaussian noise; ARCH, GARCH, EGARCH, GJR-GARCH and RiskMetrics EWMA volatility models fitted by maximum likelihood (scipy.optimize.minimize), Engle’s ARCH-LM test, Parkinson’s range estimator and realized variance.

financialkit.time_series: returns, efficiency tests, ARMA, unit roots, long memory and volatility.

Returns and their stylized facts (fat tails by the Hill estimator, the Jarque-Bera test via scipy.stats.jarque_bera()); tests of the random walk (serial correlation by scipy.fft, Fama’s runs test, Box-Pierce and Ljung-Box, Lo-MacKinlay variance ratios); Yule-Walker autoregressions (scipy.linalg.solve_toeplitz()), partial autocorrelations, ARMA simulation (scipy.signal.lfilter()) and conditional maximum likelihood (scipy.optimize.least_squares()) with AIC/BIC order selection; the augmented Dickey-Fuller and Engle-Granger tests with MacKinnon’s critical values; Hurst’s rescaled range and fractional Gaussian noise; and ARCH, GARCH, EGARCH, GJR-GARCH and RiskMetrics EWMA volatility models fitted by maximum likelihood (scipy.optimize.minimize()), Engle’s ARCH-LM test, Parkinson’s range estimator and realized variance.

Returns are decimals per period and variances are per period; annualize with financialkit.constants.TRADING_DAYS_PER_YEAR.

class financialkit.time_series.ARCH(omega, alpha, mu=0.0)[source]#

Bases: VolatilityModel

Engle’s (1982) ARCH(1): \(\sigma_t^2 = \omega + \alpha\,\varepsilon_{t-1}^2\).

Covariance stationary when \(\alpha < 1\), with kurtosis \(3(1-\alpha^2)/(1-3\alpha^2)\) for \(\alpha^2 < 1/3\): the model fattens the tails of returns even with normal innovations.

Parameters:

Examples

>>> m = ARCH(omega=1e-4, alpha=0.5)
>>> round(m.unconditional_variance, 8), round(m.kurtosis, 4)
(0.0002, 9.0)
alpha: float#
property kurtosis: float#

Kurtosis of the returns (inf when \(3\alpha^2 \ge 1\)).

mu: float = 0.0#
news_impact(eps, var_prev)[source]#

Next period’s variance given today’s shock eps and variance var_prev; broadcasts.

omega: float#
param_names: tuple[str, ...] = ('mu', 'omega', 'alpha')#
property unconditional_variance: float#

Long-run variance (inf for a nonstationary model).

variance(returns, v0=None)[source]#

Conditional variances \(\sigma_t^2\) of returns (one-step-ahead forecasts).

Parameters:
  • returns (array_like, shape (n,))

  • v0 (float | None) – Variance of the first observation; defaults to the sample variance of the demeaned returns.

Return type:

ndarray

Returns:

ndarray, shape (n,)

class financialkit.time_series.ARMAResult(ar, ma, mean, sigma2, loglik, nobs, n_params, residuals, data)[source]#

Bases: object

An ARMA(p, q) model fitted by conditional maximum likelihood.

The model is \(\phi(B)(x_t - \mu) = \theta(B)\varepsilon_t\) with \(\phi(B) = 1 - \phi_1 B - \dots - \phi_p B^p\) and \(\theta(B) = 1 + \theta_1 B + \dots + \theta_q B^q\).

Parameters:
property aic: float#

Akaike’s information criterion \(-2\ell + 2k\).

ar: ndarray#

Autoregressive coefficients \(\phi_1..\phi_p\).

Type:

ndarray

property bic: float#

Schwarz’s Bayesian information criterion \(-2\ell + k \ln n\).

data: ndarray#

The series the model was fitted to.

Type:

ndarray

forecast(h)[source]#

Minimum mean-square-error forecasts 1..`h` steps ahead and their standard errors.

Box and Jenkins’s recursion: future innovations are replaced by 0 and future values by their forecasts; the h-step error variance is \(\sigma^2 \sum_{j<h} \psi_j^2\).

Return type:

tuple[ndarray, ndarray]

Returns:

  • mean (ndarray, shape (h,))

  • std_error (ndarray, shape (h,))

Parameters:

h (int)

loglik: float#

Conditional Gaussian log-likelihood.

Type:

float

ma: ndarray#

Moving-average coefficients \(\theta_1..\theta_q\).

Type:

ndarray

mean: float#

\(\mu\) (0 when the mean was not estimated).

Type:

float

n_params: int#

Estimated parameters, including \(\sigma^2\).

Type:

int

nobs: int#

Observations in the likelihood (after conditioning).

Type:

int

psi_weights(n)[source]#

First n weights of the MA(\(\infty\)) representation, \(\psi_0 = 1\).

Return type:

ndarray

Parameters:

n (int)

residuals: ndarray#

Conditional innovations \(\hat\varepsilon_t\) after the conditioning sample.

Type:

ndarray

sigma2: float#

Innovation variance.

Type:

float

class financialkit.time_series.CointegrationResult(statistic, critical_values, intercept, beta, residuals, adf, r_squared)[source]#

Bases: object

An Engle-Granger two-step cointegration test.

Parameters:
adf: UnitRootResult#

The second-step test on the residuals.

Type:

UnitRootResult

beta: ndarray#

Cointegrating coefficients on the regressors.

Type:

ndarray

critical_values: dict#

MacKinnon (2010) critical values for the number of variables.

Type:

dict

intercept: float#

Intercept \(a\) of the first-step regression.

Type:

float

r_squared: float#

\(R^2\) of the first-step regression.

Type:

float

rejects(level='5%')[source]#

Whether “no cointegration” is rejected at level.

Return type:

bool

Parameters:

level (str)

residuals: ndarray#

The estimated equilibrium error \(y_t - a - b' x_t\).

Type:

ndarray

statistic: float#

ADF t-ratio of the first-step residuals.

Type:

float

class financialkit.time_series.EGARCH(omega, alpha, gamma, beta, mu=0.0)[source]#

Bases: VolatilityModel

Nelson’s (1991) exponential GARCH(1,1).

\[\ln\sigma_t^2 = \omega + \beta\ln\sigma_{t-1}^2 + \alpha\bigl(|z_{t-1}| - E|z|\bigr) + \gamma z_{t-1}, \qquad z_t = \varepsilon_t / \sigma_t\]

The log form keeps the variance positive with no sign restrictions, and \(\gamma < 0\) makes negative returns raise volatility more than positive ones. Stationary when \(|\beta| < 1\).

Examples

>>> m = EGARCH(omega=-0.2, alpha=0.15, gamma=-0.08, beta=0.98)
>>> bool(m.news_impact(-0.02, 1e-4) > m.news_impact(0.02, 1e-4))
True
Parameters:
alpha: float#
beta: float#
gamma: float#
mu: float = 0.0#
news_impact(eps, var_prev)[source]#

Next period’s variance given today’s shock eps and variance var_prev; broadcasts.

omega: float#
param_names: tuple[str, ...] = ('mu', 'omega', 'alpha', 'gamma', 'beta')#
property unconditional_variance: float#

\(E[\sigma_t^2]\) for normal innovations (Nelson 1991, Theorem 2.1).

\[E[\sigma_t^2] = e^{\omega/(1-\beta)} \prod_{i \ge 0} E\bigl[e^{\beta^i g(z)}\bigr]\]

with \(E[e^{a|z| + bz}] = e^{(a+b)^2/2}\Phi(a+b) + e^{(a-b)^2/2}\Phi(a-b)\).

variance(returns, v0=None)[source]#

Conditional variances \(\sigma_t^2\) of returns (one-step-ahead forecasts).

Parameters:
  • returns (array_like, shape (n,))

  • v0 (float | None) – Variance of the first observation; defaults to the sample variance of the demeaned returns.

Return type:

ndarray

Returns:

ndarray, shape (n,)

class financialkit.time_series.EWMA(lam=0.94)[source]#

Bases: VolatilityModel

RiskMetrics (1994) exponentially weighted moving average variance.

\[\sigma_t^2 = \lambda\,\sigma_{t-1}^2 + (1 - \lambda)\,r_{t-1}^2\]

an integrated GARCH(1,1) with \(\omega = 0\) and zero mean. RiskMetrics fixed \(\lambda = 0.94\) for daily and \(0.97\) for monthly data across all assets; fit() estimates it instead. With no mean reversion, the forecast at every horizon is today’s variance.

Parameters:

lam (float) – Decay factor in (0, 1); the effective memory is about \(1/(1-\lambda)\) periods.

Examples

>>> EWMA(0.94).variance([0.01, -0.02, 0.0], v0=1e-4).round(8).tolist()
[0.0001, 0.0001, 0.000118]
forecast(returns, h)[source]#

Flat variance forecast: \(E_T[\sigma_{T+k}^2] = \sigma_{T+1}^2\) for every k.

Return type:

ndarray

Parameters:

h (int)

lam: float = 0.94#
news_impact(eps, var_prev)[source]#

Next period’s variance given today’s shock eps and variance var_prev; broadcasts.

param_names: tuple[str, ...] = ('lam',)#
property unconditional_variance: float#

Long-run variance (inf for a nonstationary model).

variance(returns, v0=None)[source]#

Conditional variances \(\sigma_t^2\) of returns (one-step-ahead forecasts).

Parameters:
  • returns (array_like, shape (n,))

  • v0 (float | None) – Variance of the first observation; defaults to the sample variance of the demeaned returns.

Return type:

ndarray

Returns:

ndarray, shape (n,)

class financialkit.time_series.GARCH(omega, alpha, beta, mu=0.0)[source]#

Bases: VolatilityModel

Bollerslev’s (1986) GARCH(1,1): \(\sigma_t^2 = \omega + \alpha\,\varepsilon_{t-1}^2 + \beta\,\sigma_{t-1}^2\).

Equivalent to an ARCH(\(\infty\)) with geometrically declining weights. Covariance stationary when the persistence \(\alpha + \beta < 1\); shocks to the variance then decay at rate \((\alpha + \beta)^h\), a half-life of \(\ln\frac12 / \ln(\alpha + \beta)\) periods.

Parameters:

Examples

>>> m = GARCH(omega=2e-6, alpha=0.08, beta=0.9)
>>> round(m.unconditional_variance, 8), round(m.half_life, 1)
(0.0001, 34.3)
alpha: float#
beta: float#
forecast(returns, h)[source]#

Variance forecasts 1..`h` periods after the end of returns.

\[E_T[\sigma_{T+k}^2] = \bar\sigma^2 + (\alpha + \beta)^{k-1}(\sigma_{T+1}^2 - \bar\sigma^2)\]
Return type:

ndarray

Parameters:

h (int)

property half_life: float#

Periods for a variance shock to halve.

mu: float = 0.0#
news_impact(eps, var_prev)[source]#

Next period’s variance given today’s shock eps and variance var_prev; broadcasts.

omega: float#
param_names: tuple[str, ...] = ('mu', 'omega', 'alpha', 'beta')#
property persistence: float#
property unconditional_variance: float#

Long-run variance (inf for a nonstationary model).

variance(returns, v0=None)[source]#

Conditional variances \(\sigma_t^2\) of returns (one-step-ahead forecasts).

Parameters:
  • returns (array_like, shape (n,))

  • v0 (float | None) – Variance of the first observation; defaults to the sample variance of the demeaned returns.

Return type:

ndarray

Returns:

ndarray, shape (n,)

class financialkit.time_series.GJRGARCH(omega, alpha, gamma, beta, mu=0.0)[source]#

Bases: VolatilityModel

Glosten-Jagannathan-Runkle (1993) GARCH with a leverage term.

\[\sigma_t^2 = \omega + (\alpha + \gamma\,\mathbf 1\{\varepsilon_{t-1} < 0\})\,\varepsilon_{t-1}^2 + \beta\,\sigma_{t-1}^2\]

With symmetric innovations the persistence is \(\alpha + \gamma/2 + \beta\). \(\gamma > 0\) makes bad news raise volatility more than good news of the same size.

Examples

>>> m = GJRGARCH(omega=1e-6, alpha=0.02, gamma=0.1, beta=0.9)
>>> round(m.persistence, 2), float(m.news_impact(-0.01, 1e-4) > m.news_impact(0.01, 1e-4))
(0.97, 1.0)
Parameters:
alpha: float#
beta: float#
forecast(returns, h)[source]#

Variance forecasts 1..`h` periods ahead (persistence \(\alpha + \gamma/2 + \beta\)).

Return type:

ndarray

Parameters:

h (int)

gamma: float#
mu: float = 0.0#
news_impact(eps, var_prev)[source]#

Next period’s variance given today’s shock eps and variance var_prev; broadcasts.

omega: float#
param_names: tuple[str, ...] = ('mu', 'omega', 'alpha', 'gamma', 'beta')#
property persistence: float#
property unconditional_variance: float#

Long-run variance (inf for a nonstationary model).

variance(returns, v0=None)[source]#

Conditional variances \(\sigma_t^2\) of returns (one-step-ahead forecasts).

Parameters:
  • returns (array_like, shape (n,))

  • v0 (float | None) – Variance of the first observation; defaults to the sample variance of the demeaned returns.

Return type:

ndarray

Returns:

ndarray, shape (n,)

class financialkit.time_series.HurstResult(window, rs, expected_rs, hurst, hurst_corrected)[source]#

Bases: object

Rescaled-range (R/S) analysis.

Parameters:
expected_rs: ndarray#

Anis-Lloyd expectation of \((R/S)_n\) for independent normals.

Type:

ndarray

hurst: float#

Hurst’s exponent: the slope of \(\log (R/S)_n\) on \(\log n\).

Type:

float

hurst_corrected: float#

\(0.5\) plus the slope of \(\log (R/S)_n - \log E[(R/S)_n]\), which removes the small-sample bias of the raw slope.

Type:

float

rs: ndarray#

Average rescaled range \((R/S)_n\) over non-overlapping windows.

Type:

ndarray

window: ndarray#

Window lengths \(n\).

Type:

ndarray of int

class financialkit.time_series.OHLC(open, high, low, close)[source]#

Bases: object

Open, high, low and close prices per period.

Parameters:
close: ndarray#
high: ndarray#
low: ndarray#
open: ndarray#
class financialkit.time_series.OLSResult(coef, std_errors, t_values, residuals, sigma2, r_squared)[source]#

Bases: object

Ordinary least squares \(y = X b + e\).

Parameters:
coef: ndarray#

Estimated coefficients \(\hat b\).

Type:

ndarray, shape (k,)

r_squared: float#

Centred \(R^2\) (uncentred when X has no constant column).

Type:

float

residuals: ndarray#

\(y - X\hat b\).

Type:

ndarray, shape (n,)

sigma2: float#

Residual variance with n - k degrees of freedom.

Type:

float

std_errors: ndarray#

Classical standard errors.

Type:

ndarray, shape (k,)

t_values: ndarray#

Coefficients divided by their standard errors.

Type:

ndarray, shape (k,)

class financialkit.time_series.OrderSelectionResult(aic, bic)[source]#

Bases: object

Information criteria over a grid of ARMA orders.

Parameters:
aic: ndarray#

Akaike criterion of ARMA(p, q) at [p, q] (NaN where a fit failed).

Type:

ndarray, shape (max_p + 1, max_q + 1)

best(criterion='aic')[source]#

The (p, q) minimizing criterion ("aic" or "bic").

Return type:

tuple[int, int]

Parameters:

criterion (str)

bic: ndarray#

Schwarz criterion of ARMA(p, q) at [p, q] (NaN where a fit failed).

Type:

ndarray, shape (max_p + 1, max_q + 1)

class financialkit.time_series.ReturnStatistics(nobs, mean, std, skewness, excess_kurtosis, jarque_bera, jarque_bera_pvalue)[source]#

Bases: object

Sample moments of a return series and the Jarque-Bera normality test.

Parameters:
excess_kurtosis: float#

Sample excess kurtosis; zero for a normal distribution.

Type:

float

jarque_bera: float#

Jarque-Bera statistic (scipy.stats.jarque_bera()).

Type:

float

jarque_bera_pvalue: float#

Jarque-Bera p-value.

Type:

float

mean: float#

Per-period sample mean.

Type:

float

nobs: int#

Number of returns.

Type:

int

skewness: float#

Sample skewness; zero for a normal distribution.

Type:

float

std: float#

Per-period sample standard deviation (ddof=1).

Type:

float

class financialkit.time_series.TailIndexResult(k, alpha, std_error, threshold)[source]#

Bases: object

Hill estimates of a tail index for a range of order statistics.

Parameters:
alpha: ndarray#

Tail index estimate \(\hat\alpha_k\) for each k.

Type:

ndarray

k: ndarray#

Number of upper order statistics used.

Type:

ndarray of int

std_error: ndarray#

Asymptotic standard error \(\hat\alpha_k / \sqrt{k}\).

Type:

ndarray

threshold: ndarray#

The order statistic \(X_{(k+1)}\) each estimate conditions on.

Type:

ndarray

class financialkit.time_series.TestResult(name, statistic, pvalue, df=None, nobs=0)[source]#

Bases: object

A test statistic with its p-value.

Parameters:
df: int | None = None#

Degrees of freedom of a chi-squared reference distribution.

Type:

int or None

name: str#

Name of the test.

Type:

str

nobs: int = 0#

Observations used.

Type:

int

pvalue: float#

p-value of the statistic.

Type:

float

rejects(level=0.05)[source]#

Whether the null hypothesis is rejected at significance level.

Return type:

bool

Parameters:

level (float)

statistic: float#

The test statistic.

Type:

float

class financialkit.time_series.UnitRootResult(statistic, critical_values, lags, nobs, regression, gamma)[source]#

Bases: object

An augmented Dickey-Fuller test.

Parameters:
critical_values: dict#

MacKinnon (2010) critical values keyed by "1%", "5%", "10%".

Type:

dict

gamma: float#

Estimated \(\gamma = \rho - 1\).

Type:

float

lags: int#

Lagged differences included.

Type:

int

nobs: int#

Observations in the regression.

Type:

int

regression: str#

Deterministic terms: "n", "c" or "ct".

Type:

str

rejects(level='5%')[source]#

Whether the unit root is rejected at level ("1%", "5%" or "10%").

Return type:

bool

Parameters:

level (str)

statistic: float#

The t-ratio of \(\gamma\) in \(\Delta y_t = \text{det}_t + \gamma y_{t-1} + \sum_i \delta_i \Delta y_{t-i} + e_t\).

Type:

float

class financialkit.time_series.VarianceRatioResult(q, ratio, z, z_robust, nobs)[source]#

Bases: object

Lo-MacKinlay variance ratios for one or more horizons.

Parameters:
nobs: int#

Number of one-period returns \(T\).

Type:

int

property pvalue: ndarray#

Two-sided p-values of z.

property pvalue_robust: ndarray#

Two-sided p-values of z_robust.

q: ndarray#

Aggregation horizons.

Type:

ndarray of int

ratio: ndarray#

Bias-corrected variance ratios \(VR(q)\); 1 under a random walk.

Type:

ndarray

z: ndarray#

Standard normal statistics under homoskedastic increments.

Type:

ndarray

z_robust: ndarray#

Heteroskedasticity-consistent statistics \(z^*(q)\).

Type:

ndarray

class financialkit.time_series.VolatilityFit(model, loglik, nobs, variance, std_errors=<factory>, converged=True)[source]#

Bases: object

A volatility model estimated by Gaussian maximum likelihood.

Parameters:
property aic: float#
property bic: float#
converged: bool = True#

Whether the optimizer reported success.

Type:

bool

loglik: float#

Maximized Gaussian log-likelihood.

Type:

float

model: VolatilityModel#

The fitted model, in the units of the input returns.

Type:

VolatilityModel

property n_params: int#
nobs: int#

Number of returns.

Type:

int

property params: dict#

Fitted parameters keyed by name.

std_errors: dict#

Standard errors from the inverse numerical Hessian, keyed by parameter.

Type:

dict

variance: ndarray#

In-sample conditional variances (the one-step-ahead forecasts).

Type:

ndarray

class financialkit.time_series.VolatilityModel[source]#

Bases: ABC

A conditional-variance model \(r_t = \mu + \sigma_t z_t\), \(z_t \sim N(0, 1)\).

Subclasses define their parameters (param_names), the one-step update news_impact(), the bounds and constraints of estimation, and how the parameters change when returns are rescaled. Variance filtering, the log-likelihood, simulation and maximum-likelihood fitting are shared. The pre-sample variance is the sample variance of the demeaned returns (“backcasting”).

classmethod fit(returns)[source]#

Maximum-likelihood estimate on returns (Gaussian quasi-likelihood).

The returns are scaled to unit variance before optimizing (so every parameter is of order one) and the estimate is mapped back, which the Gaussian likelihood allows because each model family is closed under rescaling. scipy.optimize.minimize() (SLSQP) handles the bounds and stationarity constraints.

Return type:

VolatilityFit

Returns:

VolatilityFit

loglikelihood(returns, v0=None)[source]#

Gaussian log-likelihood \(-\tfrac12\sum_t [\ln 2\pi + \ln\sigma_t^2 + \varepsilon_t^2/\sigma_t^2]\).

Return type:

float

Parameters:

v0 (float | None)

property mean: float#
abstractmethod news_impact(eps, var_prev)[source]#

Next period’s variance given today’s shock eps and variance var_prev; broadcasts.

param_names: tuple[str, ...] = ()#
property params: dict#
simulate(n, burn=500, rng=None)[source]#

Simulate n returns with Gaussian innovations, after burn discarded periods.

Return type:

VolatilityPath

Returns:

VolatilityPath

Parameters:
standardized_residuals(returns)[source]#

\(z_t = (r_t - \mu) / \sigma_t\).

Return type:

ndarray

abstract property unconditional_variance: float#

Long-run variance (inf for a nonstationary model).

variance(returns, v0=None)[source]#

Conditional variances \(\sigma_t^2\) of returns (one-step-ahead forecasts).

Parameters:
  • returns (array_like, shape (n,))

  • v0 (float | None) – Variance of the first observation; defaults to the sample variance of the demeaned returns.

Return type:

ndarray

Returns:

ndarray, shape (n,)

class financialkit.time_series.VolatilityPath(returns, variance)[source]#

Bases: object

A simulated return series and its conditional variance.

Parameters:
returns: ndarray#

Simulated returns.

Type:

ndarray, shape (n,)

variance: ndarray#

\(\sigma_t^2\), the variance of returns[t] given the past.

Type:

ndarray, shape (n,)

property volatility: ndarray#

Conditional standard deviation \(\sigma_t\).

financialkit.time_series.adf_test(x, lags=None, regression='c', max_lags=None)[source]#

Augmented Dickey-Fuller test of a unit root.

Regresses

\[\Delta y_t = \text{det}_t + \gamma y_{t-1} + \sum_{i=1}^{k} \delta_i \Delta y_{t-i} + e_t\]

and compares the t-ratio of \(\gamma\) with MacKinnon’s critical values; the null \(\gamma = 0\) (a unit root) is rejected for large negative values.

Parameters:
  • x (array_like)

  • lags (int | None) – Lagged differences \(k\). If omitted, chosen by AIC from 0..max_lags on a common sample, then the test is rerun on all available data.

  • regression (str)

  • max_lags (int | None) – Defaults to Schwert’s rule \(\lfloor 12 (n/100)^{1/4} \rfloor\).

Return type:

UnitRootResult

Returns:

UnitRootResult

Examples

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> adf_test(np.cumsum(rng.standard_normal(500)), lags=0).rejects()
False
>>> adf_test(rng.standard_normal(500), lags=0).rejects()
True
financialkit.time_series.anis_lloyd_expected_rs(n)[source]#

Expected \(R/S\) of n independent normals (Anis and Lloyd 1976).

\[E[(R/S)_n] = \frac{\Gamma(\frac{n-1}{2})}{\sqrt\pi\,\Gamma(\frac n2)} \sum_{i=1}^{n-1}\sqrt{\frac{n-i}{i}}\]

Examples

>>> import numpy as np
>>> float(np.round(anis_lloyd_expected_rs(10), 4))
3.0233
Return type:

ndarray

financialkit.time_series.ar_cycle_period(ar)[source]#

Pseudo-period of the dominant complex pair of AR roots, in periods (inf if all roots are real).

For AR(2) with \(\phi_2 < 0\) and \(\phi_1^2 + 4\phi_2 < 0\), the period is \(2\pi / \arccos\bigl(\phi_1 / (2\sqrt{-\phi_2})\bigr)\).

Return type:

float

Examples

>>> round(ar_cycle_period([1.34, -0.65]), 2)
10.65
financialkit.time_series.arch_lm_test(returns, lags=5, demean=True)[source]#

Engle’s (1982) Lagrange-multiplier test for ARCH effects.

Regresses \(\varepsilon_t^2\) on a constant and \(\varepsilon_{t-1}^2, \dots, \varepsilon_{t-q}^2\); under the null of no ARCH, \(T R^2 \sim \chi^2_q\).

Parameters:
  • returns (array_like)

  • lags (int) – \(q\).

  • demean (bool)

Return type:

TestResult

Returns:

TestResult

Examples

>>> import numpy as np
>>> arch_lm_test(np.random.default_rng(0).standard_normal(2000)).rejects()
False
>>> arch_lm_test(GARCH(0.05, 0.15, 0.8).simulate(2000, rng=0).returns).rejects()
True
financialkit.time_series.arma_acf(ar=None, ma=None, nlags=20, n_terms=2000)[source]#

Theoretical autocorrelations k = 0..nlags of a stationary ARMA process.

Uses \(\gamma_k = \sigma^2 \sum_j \psi_j \psi_{j+k}\) with the MA(\(\infty\)) weights truncated at n_terms.

Return type:

ndarray

Parameters:

Examples

>>> arma_acf(ar=[0.5], nlags=3).round(6).tolist()
[1.0, 0.5, 0.25, 0.125]
financialkit.time_series.arma_psi_weights(ar, ma, n)[source]#

Weights \(\psi_0 = 1, \psi_1, \dots, \psi_{n-1}\) of \(x_t = \sum_j \psi_j \varepsilon_{t-j}\).

Return type:

ndarray

Parameters:

n (int)

Examples

>>> arma_psi_weights([0.5], [0.4], 4).round(4).tolist()
[1.0, 0.9, 0.45, 0.225]
financialkit.time_series.autocorrelation(x, nlags=20)[source]#

Sample autocorrelations \(\hat\rho_k = \hat\gamma_k / \hat\gamma_0\), k = 0..nlags.

Kendall’s (1953) serial correlations: for price changes of a random walk they are close to zero at every lag, while for price levels they are close to one.

Return type:

ndarray

Parameters:

nlags (int)

Examples

>>> import numpy as np
>>> rho = autocorrelation(np.random.default_rng(0).standard_normal(10_000), 3)
>>> float(rho[0]), bool(np.all(np.abs(rho[1:]) < 4 / np.sqrt(10_000)))
(1.0, True)
financialkit.time_series.autocovariance(x, nlags)[source]#

Sample autocovariances \(\hat\gamma_k = \frac1n\sum_{t=k}^{n-1}(x_t-\bar x)(x_{t-k}-\bar x)\), k = 0..nlags.

Computed with scipy.fft.rfft() (the divisor n keeps the sequence positive semidefinite).

Return type:

ndarray

Parameters:

nlags (int)

financialkit.time_series.bartlett_band(nobs, level=0.95)[source]#

Half-width \(z_{1-\alpha/2}/\sqrt n\) of the band that white-noise autocorrelations stay within.

Return type:

float

Parameters:

Examples

>>> round(bartlett_band(400), 4)
0.098
financialkit.time_series.box_pierce(x, lags=10, fitted_params=0)[source]#

Box-Pierce (1970) portmanteau statistic \(Q = n\sum_{k=1}^h \hat\rho_k^2 \sim \chi^2_{h - p - q}\).

Return type:

TestResult

Parameters:
  • lags (int)

  • fitted_params (int)

financialkit.time_series.close_to_close_variance(close)[source]#

Per-period variance proxies \(r_t^2 = (\ln C_t / C_{t-1})^2\) (zero mean assumed).

Return type:

ndarray

Examples

>>> import numpy as np
>>> close_to_close_variance([100.0, 100.0 * np.exp(0.01)]).round(10).tolist()
[0.0001]
financialkit.time_series.engle_granger(y, x, lags=0, trend='c')[source]#

Engle-Granger two-step test of cointegration between y and the columns of x.

Step 1 regresses \(y_t = a + b' x_t + u_t\) by least squares, which is super-consistent when the series are cointegrated. Step 2 runs a Dickey-Fuller test without deterministic terms on \(\hat u_t\). Because \(b\) was estimated to make \(\hat u_t\) look stationary, the critical values are more negative than Dickey and Fuller’s and depend on the number of variables (MacKinnon 2010).

Parameters:
  • y (array_like, shape (n,))

  • x (array_like, shape (n,) or (n, k)) – One to three regressors.

  • lags (int | None) – Lagged differences in step 2 (None chooses by AIC).

  • trend (str) – Deterministic terms of the step-1 regression.

Return type:

CointegrationResult

Returns:

CointegrationResult

Examples

>>> from financialkit.time_series.utils.synthetic import simulate_cointegrated_pair
>>> y, x = simulate_cointegrated_pair(1000, beta=2.0, phi=0.8, rng=0)
>>> res = engle_granger(y, x)
>>> round(float(res.beta[0]), 1), res.rejects()
(2.0, True)
financialkit.time_series.fgn_autocovariance(H, nlags)[source]#

Autocovariances k = 0..nlags of unit-variance fractional Gaussian noise.

Return type:

ndarray

Parameters:

Examples

>>> fgn_autocovariance(0.5, 3).tolist()
[1.0, 0.0, 0.0, 0.0]
financialkit.time_series.fit_arma(x, p, q=0, include_mean=True, start=None)[source]#

Fit ARMA(p, q) by conditional maximum likelihood (Box-Jenkins estimation).

Conditioning on the first start observations and on zero pre-sample innovations, the Gaussian log-likelihood is maximized by minimizing the sum of squared innovations, which scipy.optimize.least_squares() does over a parameterization that keeps the AR part stationary and the MA part invertible (Monahan’s transform of the partial autocorrelations); \(\hat\sigma^2\) is the mean squared innovation. A pure AR model is linear in its parameters and is solved exactly by numpy.linalg.lstsq().

Parameters:
  • x (array_like)

  • p (int) – Autoregressive and moving-average orders.

  • q (int) – Autoregressive and moving-average orders.

  • include_mean (bool) – Estimate the mean \(\mu\) (otherwise \(\mu = 0\)).

  • start (int | None) – Observations conditioned on (default p). Use a common value to compare models of different orders on the same sample.

Return type:

ARMAResult

Returns:

ARMAResult

Examples

>>> x = simulate_arma(ar=[0.7], ma=[0.4], n=5000, mean=1.0, rng=2)
>>> res = fit_arma(x, 1, 1)
>>> res.ar.round(1).tolist(), res.ma.round(1).tolist(), round(res.mean, 1)
([0.7], [0.4], 1.0)
financialkit.time_series.hill_estimator(x, k=None, side='upper')[source]#

Hill’s estimator of the tail index \(\alpha\) from the k largest observations.

\[\hat\alpha_k = \Bigl[\frac1k \sum_{i=1}^{k} \ln X_{(i)} - \ln X_{(k+1)}\Bigr]^{-1}\]

with \(X_{(1)} \ge X_{(2)} \ge \dots\) the descending order statistics. It is the maximum-likelihood estimator for an exact Pareto tail above \(X_{(k+1)}\), with asymptotic standard error \(\alpha/\sqrt k\). Plotting \(\hat\alpha_k\) against k (the Hill plot) shows the trade-off: small k is noisy, large k reaches into the body of the distribution and is biased.

Parameters:
  • x (array_like)

  • k (int or array_like of int, optional) – Numbers of order statistics; defaults to 2 .. n // 4.

  • side (str) – Which tail: positive values, negated negative values, or \(|x|\).

Return type:

TailIndexResult

Returns:

TailIndexResult

Examples

>>> import numpy as np
>>> rng = np.random.default_rng(1)
>>> x = rng.pareto(3.0, 100_000) + 1.0  # exact Pareto tail, alpha = 3
>>> res = hill_estimator(x, k=5000)
>>> bool(abs(res.alpha[0] - 3.0) < 4 * res.std_error[0])
True
financialkit.time_series.hurst_exponent(x, min_window=16, n_windows=12)[source]#

Estimate Hurst’s exponent by rescaled-range (R/S) analysis.

For each window length \(n\) (log-spaced from min_window to half the sample), the series is cut into non-overlapping blocks and the block values of \(R/S\) are averaged. \(H\) is the slope of \(\log (R/S)_n\) on \(\log n\). Because \((R/S)_n\) of independent data approaches \(\sqrt{\pi n/2}\) only slowly, the raw slope exceeds 1/2 in small windows; HurstResult.hurst_corrected regresses the excess over the Anis-Lloyd expectation instead.

Parameters:
  • x (array_like) – Increments (returns), not levels.

  • min_window (int)

  • n_windows (int)

Return type:

HurstResult

Returns:

HurstResult

Examples

>>> res = hurst_exponent(simulate_fgn(8192, 0.8, rng=0))
>>> bool(0.7 < res.hurst_corrected < 0.9)
True
financialkit.time_series.lag_matrix(x, lags)[source]#

Columns x[t-1], ..., x[t-lags] for t = lags .. n-1.

Return type:

ndarray

Parameters:

lags (int)

Examples

>>> lag_matrix([1.0, 2.0, 3.0, 4.0], 2).tolist()
[[2.0, 1.0], [3.0, 2.0]]
financialkit.time_series.ljung_box(x, lags=10, fitted_params=0)[source]#

Ljung-Box (1978) portmanteau statistic.

\[Q = n(n+2)\sum_{k=1}^{h} \frac{\hat\rho_k^2}{n-k} \;\sim\; \chi^2_{h - p - q}\]

The \((n+2)/(n-k)\) weights correct the Box-Pierce statistic’s small-sample downward bias. Apply it to ARMA residuals with fitted_params = p + q, or to squared returns to detect volatility clustering.

Parameters:
  • x (array_like)

  • lags (int) – Number of autocorrelations pooled, \(h\).

  • fitted_params (int) – Degrees of freedom lost to estimation.

Return type:

TestResult

Returns:

TestResult

Examples

>>> import numpy as np
>>> from scipy.signal import lfilter
>>> e = np.random.default_rng(0).standard_normal(1000)
>>> ljung_box(e, 10).rejects(), ljung_box(lfilter([1.0], [1.0, -0.3], e), 10).rejects()
(False, True)
financialkit.time_series.log_returns(prices)[source]#

Continuously compounded returns \(\ln(P_t / P_{t-1})\).

Return type:

ndarray

Examples

>>> import numpy as np
>>> log_returns([100.0, 100.0 * np.e]).round(12).tolist()
[1.0]
financialkit.time_series.mackinnon_critical_values(nobs, regression='c', n_vars=1)[source]#

MacKinnon (2010) finite-sample critical values of the Dickey-Fuller and Engle-Granger tests.

Parameters:
  • nobs (int) – Observations in the test regression.

  • regression (str) – No deterministic terms, a constant, or a constant and a linear trend.

  • n_vars (int) – 1 for a unit-root test; the number of variables in the cointegrating regression (2 to 4) for Engle-Granger.

Return type:

dict

Returns:

dict – {"1%": ..., "5%": ..., "10%": ...}.

Examples

>>> {k: round(v, 3) for k, v in mackinnon_critical_values(10**9).items()}
{'1%': -3.43, '5%': -2.862, '10%': -2.567}
financialkit.time_series.mincer_zarnowitz(proxy, forecast)[source]#

Mincer-Zarnowitz regression \(\text{proxy}_t = a + b\,\text{forecast}_t + e_t\).

An unbiased forecast has \(a = 0, b = 1\); the \(R^2\) measures how much of the proxy’s variation the forecast explains. Andersen and Bollerslev (1998) showed that with \(r_t^2\) as the proxy even a perfect variance forecast has a small \(R^2\) (at most \(1/\kappa\) of the explainable part, \(\kappa\) the kurtosis of \(z_t\)), and that realized variance restores it.

Return type:

OLSResult

Returns:

OLSResult – Coefficients [a, b] and r_squared.

financialkit.time_series.numerical_hessian(f, x, rel_step=0.0001)[source]#

Central-difference Hessian of a scalar function at x.

Return type:

ndarray

Parameters:

Examples

>>> import numpy as np
>>> numerical_hessian(lambda v: v[0] ** 2 + 3 * v[0] * v[1], np.array([1.0, 2.0])).round(6).tolist()
[[2.0, 3.0], [3.0, 0.0]]
financialkit.time_series.ols(y, X)[source]#

Least squares by numpy.linalg.lstsq(), with classical standard errors.

Parameters:
  • y (array_like, shape (n,))

  • X (array_like, shape (n, k))

Return type:

OLSResult

Returns:

OLSResult

Examples

>>> import numpy as np
>>> x = np.arange(5.0)
>>> res = ols(1.0 + 2.0 * x, np.column_stack([np.ones(5), x]))
>>> res.coef.round(12).tolist(), res.r_squared
([1.0, 2.0], 1.0)
financialkit.time_series.parkinson_variance(high, low)[source]#

Parkinson’s per-period variance estimates \((\ln H_t/L_t)^2 / (4\ln 2)\).

Unbiased for driftless Brownian motion observed continuously; average over periods (or smooth) to estimate a variance, and multiply by periods per year to annualize. Discrete sampling of the high and low biases it slightly downward.

Return type:

ndarray

Examples

>>> import numpy as np
>>> float(parkinson_variance([np.exp(0.02)], [1.0])[0].round(8))
0.00014427
financialkit.time_series.partial_autocorrelation(x, nlags=20)[source]#

Sample partial autocorrelations by the Durbin-Levinson recursion, k = 0..nlags.

The lag-k value is the last coefficient of the AR(k) Yule-Walker fit; it cuts off after lag p for an AR(p) process, which is how Box and Jenkins identify the autoregressive order.

Return type:

ndarray

Parameters:

nlags (int)

Examples

>>> import numpy as np
>>> pacf = partial_autocorrelation(simulate_arma(ar=[0.6], n=20_000, rng=1), 3)
>>> round(float(pacf[1]), 1), bool(abs(pacf[2]) < 0.03)
(0.6, True)
financialkit.time_series.plot_acf(x, nlags=20, partial=False, ax=None, label='')[source]#

Correlogram of x (lags 1..`nlags`) with the 95% white-noise band.

Parameters:
  • x (array_like)

  • nlags (int)

  • partial (bool) – Plot partial autocorrelations instead.

  • ax (matplotlib.axes.Axes, optional)

  • label (str) – Legend label.

Returns:

matplotlib.axes.Axes

financialkit.time_series.plot_conditional_volatility(returns, variance, ax=None, periods_per_year=None)[source]#

Returns with a \(\pm 2\sigma_t\) envelope of the conditional volatility.

Parameters:
  • returns (array_like, shape (n,))

  • variance (array_like, shape (n,))

  • ax (matplotlib.axes.Axes, optional)

  • periods_per_year (int | None) – If given, also draw the annualized volatility on a twin axis.

Returns:

matplotlib.axes.Axes

financialkit.time_series.plot_hill(result, true_alpha=None, ax=None, label='')[source]#

Hill plot: \(\hat\alpha_k\) against k with a two-standard-error band.

Returns:

matplotlib.axes.Axes

Parameters:
financialkit.time_series.plot_news_impact(models, var_prev, eps_range=None, ax=None)[source]#

News impact curves: next period’s variance against today’s shock, from the same var_prev.

Parameters:
  • models (dict)

  • var_prev (float) – Today’s conditional variance.

  • eps_range (float | None) – Shocks span [-eps_range, eps_range] (default five standard deviations).

Returns:

matplotlib.axes.Axes

financialkit.time_series.plot_rescaled_range(result, ax=None, label='')[source]#

\((R/S)_n\) against \(n\) on log-log axes, with the fitted slope and the Anis-Lloyd benchmark.

Returns:

matplotlib.axes.Axes

Parameters:
financialkit.time_series.plot_tail(x, ax=None, label='', side='both')[source]#

Empirical survival function \(P(|X| > u)\) on log-log axes.

Returns:

matplotlib.axes.Axes

Parameters:
financialkit.time_series.plot_variance_ratio(result, ax=None, label='')[source]#

Variance ratios against horizon q, with 95% bands under the homoskedastic random walk.

Returns:

matplotlib.axes.Axes

Parameters:
financialkit.time_series.realized_variance(intraday_returns, axis=-1)[source]#

Realized variance \(RV_t = \sum_i r_{t,i}^2\), summing intraday returns along axis.

As the sampling interval shrinks, \(RV_t\) converges to the integrated variance \(\int_{t-1}^{t}\sigma_s^2\,ds\) of the day.

Return type:

ndarray

Parameters:

axis (int)

Examples

>>> realized_variance([[0.01, -0.01], [0.02, 0.0]]).round(8).tolist()
[0.0002, 0.0004]
financialkit.time_series.rescaled_range(x)[source]#

Hurst’s adjusted rescaled range \(R/S\) of one block.

\(R\) is the range of the cumulative sums of deviations from the block mean and \(S\) the block standard deviation.

Return type:

float

Examples

>>> rescaled_range([1.0, -1.0, 1.0, -1.0])
1.0
financialkit.time_series.return_statistics(returns)[source]#

Mean, volatility, skewness, excess kurtosis and the Jarque-Bera test.

Parameters:

returns (array_like)

Return type:

ReturnStatistics

Returns:

ReturnStatistics

Examples

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> s = return_statistics(rng.standard_t(3, 20_000))
>>> bool(s.excess_kurtosis > 3), bool(s.jarque_bera_pvalue < 1e-6)
(True, True)
financialkit.time_series.runs_test(x)[source]#

Fama’s (1965) runs test on the signs of price changes.

A run is a maximal sequence of changes with the same sign (+, - or 0). With \(n_i\) changes of sign \(i\) out of \(N\), the number of runs under independence has mean and variance

\[m = \frac{N(N+1) - \sum_i n_i^2}{N}, \qquad \sigma_m^2 = \frac{\sum_i n_i^2\bigl[\sum_i n_i^2 + N(N+1)\bigr] - 2N\sum_i n_i^3 - N^3}{N^2(N-1)}.\]

Too few runs means positive dependence (trends), too many means reversals. The statistic is the normal approximation with a half-run continuity correction; with two signs it reduces to the Wald-Wolfowitz test.

Return type:

TestResult

Returns:

TestResult – Two-sided p-value; statistic is negative when there are fewer runs than expected.

Examples

>>> res = runs_test([1, 1, 1, 1, 1, -1, -1, -1, -1, -1] * 4)
>>> bool(res.statistic < -3)
True
financialkit.time_series.select_arma_order(x, max_p=4, max_q=2, include_mean=True)[source]#

AIC and BIC of every ARMA(p, q) with p <= max_p and q <= max_q.

All models are fitted on the same sample (conditioning on the first max_p observations), so their likelihoods are comparable. Akaike’s criterion \(-2\ell + 2k\) estimates the expected Kullback-Leibler divergence and tends to overfit in large samples; Schwarz’s \(-2\ell + k\ln n\) is consistent.

Return type:

OrderSelectionResult

Returns:

OrderSelectionResult

Parameters:

Examples

>>> x = simulate_arma(ar=[0.5, 0.3], n=3000, rng=4)
>>> select_arma_order(x, max_p=4, max_q=0).best("bic")
(2, 0)
financialkit.time_series.simple_returns(prices)[source]#

Simple returns \(P_t / P_{t-1} - 1\).

Return type:

ndarray

Examples

>>> simple_returns([100.0, 110.0, 99.0]).round(12).tolist()
[0.1, -0.1]
financialkit.time_series.simulate_arma(ar=None, ma=None, n=1000, sigma=1.0, mean=0.0, burn=500, rng=None)[source]#

Simulate \(\phi(B)(x_t - \mu) = \theta(B)\varepsilon_t\) with Gaussian innovations.

Filters white noise through scipy.signal.lfilter() and discards burn start-up values.

Parameters:
  • ar (array_like, optional) – \(\phi_1..\phi_p\) and \(\theta_1..\theta_q\).

  • ma (array_like, optional) – \(\phi_1..\phi_p\) and \(\theta_1..\theta_q\).

  • n (int)

  • sigma (float) – Innovation standard deviation.

  • mean (float)

  • burn (int)

  • rng (Generator | int | None)

Return type:

ndarray

Returns:

ndarray, shape (n,)

financialkit.time_series.simulate_cointegrated_pair(n, beta=1.0, intercept=0.0, phi=0.9, sigma_x=1.0, sigma_u=1.0, rng=None)[source]#

A random walk x and y = intercept + beta x + u with a stationary AR(1) error u.

Return type:

tuple[ndarray, ndarray]

Returns:

y, x (ndarray, shape (n,))

Parameters:
financialkit.time_series.simulate_dickey_fuller(n_obs, n_sims, regression='c', rng=None)[source]#

Dickey-Fuller t-statistics of n_sims driftless Gaussian random walks.

Regresses \(\Delta y_t\) on \(y_{t-1}\) (plus a constant for "c", and a trend for "ct") for all walks at once, which traces out the nonstandard null distribution that Dickey and Fuller tabulated.

Return type:

ndarray

Returns:

ndarray, shape (n_sims,)

Parameters:
financialkit.time_series.simulate_fgn(n, H, sigma=1.0, rng=None)[source]#

Exact fractional Gaussian noise by circulant embedding (Davies and Harte 1987).

The autocovariance is embedded in a circulant matrix of size \(2n\), whose eigenvalues are its FFT (scipy.fft.fft()) and are nonnegative for fractional Gaussian noise; colouring complex white noise by their square roots and transforming back gives a sample with exactly the target covariance. np.cumsum of the result is fractional Brownian motion.

Parameters:
  • n (int)

  • H (float) – Hurst exponent in (0, 1); 1/2 gives white noise.

  • sigma (float) – Standard deviation of each increment.

  • rng (Generator | int | None)

Return type:

ndarray

Returns:

ndarray, shape (n,)

financialkit.time_series.simulate_intraday_returns(daily_variance, m, rng=None)[source]#

Intraday returns whose day-t variance sums to daily_variance[t].

Each of the m intraday returns of day t is \(\sigma_t z_{t,i} / \sqrt m\), so the daily return \(\sum_i r_{t,i}\) has exactly variance \(\sigma_t^2\), as in the continuous-time GARCH diffusion behind Andersen and Bollerslev (1998).

Return type:

ndarray

Returns:

ndarray, shape (n_days, m)

Parameters:
financialkit.time_series.simulate_ohlc(n_days, sigma, steps_per_day=390, s0=100.0, mu=0.0, rng=None)[source]#

Daily open, high, low and close of geometric Brownian motion.

Each day is sampled on steps_per_day points of an exact GBM path (financialkit.integrators.gbm_paths()); the next day opens at the previous close. The sampled high and low miss the true extremes between grid points, so range-based estimators are biased slightly downward on coarse grids.

Parameters:
  • n_days (int)

  • sigma (float) – Annual volatility.

  • steps_per_day (int) – Intraday grid (390 one-minute bars by default).

  • s0 (float) – Initial price and annual drift.

  • mu (float) – Initial price and annual drift.

  • rng (Generator | int | None)

Return type:

OHLC

Returns:

OHLC

financialkit.time_series.tail_survival(x, side='both')[source]#

Empirical survival function \(P(|X| > u)\) at the sorted sample points.

On log-log axes a power-law tail \(P(X > u) \sim u^{-\alpha}\) is a straight line of slope \(-\alpha\), Mandelbrot’s diagnostic.

Parameters:
  • x (array_like)

  • side (str) – Use \(|x|\), the positive values, or the magnitudes of the negative values.

Return type:

tuple[ndarray, ndarray]

Returns:

  • u (ndarray) – Sorted magnitudes (ascending).

  • prob (ndarray) – Fraction of the sample strictly above each u, i.e. (n - i) / n shifted so the largest point has probability 1/n.

financialkit.time_series.variance_ratio(log_prices, q=(2, 4, 8, 16))[source]#

Lo-MacKinlay (1988) variance-ratio test of the random walk.

If log prices follow a random walk, the variance of q-period returns is q times that of one-period returns. With overlapping q-period returns and both variances bias-corrected,

\[VR(q) = \frac{\hat\sigma_c^2(q)}{\hat\sigma_a^2}, \qquad z(q) = \frac{VR(q) - 1}{\sqrt{2(2q-1)(q-1)/(3qT)}},\]

and the heteroskedasticity-consistent \(z^*(q) = \sqrt T\,(VR(q)-1)/\sqrt{\hat\theta(q)}\) with \(\hat\theta(q) = \sum_{j=1}^{q-1} [2(q-j)/q]^2 \hat\delta(j)\) stays valid under volatility clustering (Lo and MacKinlay 1988, eqs. (12)-(14) and Theorem 3). Since \(VR(q) - 1 \approx 2\sum_{k<q}(1-k/q)\rho_k\), positive autocorrelation pushes the ratio above one.

Parameters:
  • log_prices (array_like, shape (T + 1,))

  • q (int or sequence of int) – Horizons, each at least 2.

Return type:

VarianceRatioResult

Returns:

VarianceRatioResult

Examples

>>> import numpy as np
>>> p = np.cumsum(np.random.default_rng(3).standard_normal(5001))
>>> res = variance_ratio(p, q=[2, 4])
>>> bool(np.all(np.abs(res.z) < 3))
True
financialkit.time_series.yule_walker(x, order, demean=True)[source]#

Fit an AR(order) model by solving the Yule-Walker equations.

The equations \(\rho_k = \sum_{i=1}^p \phi_i \rho_{k-i}\), k = 1..p, form a Toeplitz system in the sample autocorrelations, and \(\sigma^2 = \hat\gamma_0 (1 - \sum_i \phi_i \hat\rho_i)\). Yule’s (1927) sunspot fit was \(\phi_1 \approx 1.34\), \(\phi_2 \approx -0.65\).

Parameters:
  • x (array_like)

  • order (int)

  • demean (bool) – Subtract the sample mean first.

Return type:

ARMAResult

Returns:

ARMAResult – With ma empty; the log-likelihood is conditional on the first order values.

Examples

>>> import numpy as np
>>> x = simulate_arma(ar=[1.34, -0.65], n=50_000, rng=0)
>>> yule_walker(x, 2).ar.round(2).tolist()
[1.34, -0.65]