Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: Add Python 3.13 to run #764

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion arch/tests/unitroot/test_unitroot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
import scipy.stats as stats
from statsmodels.datasets import macrodata, modechoice, nile, randhie, sunspots
from statsmodels.regression.linear_model import OLS
from statsmodels.tsa.stattools import _autolag, lagmat
from statsmodels.tsa.stattools import lagmat

try:
from statsmodels.tsa.stattools import _autolag
except ImportError:
from statsmodels.tsa.stattools._stattools import _autolag

from arch.unitroot import ADF, DFGLS, KPSS, PhillipsPerron, VarianceRatio, ZivotAndrews
from arch.unitroot.critical_values.dickey_fuller import tau_2010
Expand Down
8 changes: 4 additions & 4 deletions arch/tests/univariate/test_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_studentst(self, seed):
# Direct calculation of PDF, then log
constant = np.exp(gammaln(0.5 * (v + 1)) - gammaln(0.5 * v))
pdf = constant / np.sqrt(np.pi * (v - 2) * self.sigma2)
pdf *= (1 + self.resids ** 2.0 / (self.sigma2 * (v - 2))) ** (-(v + 1) / 2)
pdf *= (1 + self.resids**2.0 / (self.sigma2 * (v - 2))) ** (-(v + 1) / 2)
ll2 = np.log(pdf).sum()
assert_almost_equal(ll1, ll2)

Expand Down Expand Up @@ -87,14 +87,14 @@ def test_skewstudent(self, seed):
# Direct calculation of PDF, then log
const_c = gamma((eta + 1) / 2) / ((np.pi * (eta - 2)) ** 0.5 * gamma(eta / 2))
const_a = 4 * lam * const_c * (eta - 2) / (eta - 1)
const_b = (1 + 3 * lam ** 2 - const_a ** 2) ** 0.5
const_b = (1 + 3 * lam**2 - const_a**2) ** 0.5

resids = self.resids / self.sigma2 ** 0.5
resids = self.resids / self.sigma2**0.5
power = -(eta + 1) / 2
pdf = (
const_b
* const_c
/ self.sigma2 ** 0.5
/ self.sigma2**0.5
* (
1
+ 1
Expand Down
2 changes: 1 addition & 1 deletion arch/tests/univariate/test_mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,7 @@ def test_param_cov():
def test_plot_bad_index():
import matplotlib.pyplot as plt

idx = sorted(f"{a}{b}{c}" for a, b, c, in product(*([ascii_lowercase] * 3)))
idx = sorted(f"{a}{b}{c}" for a, b, c in product(*([ascii_lowercase] * 3)))
sp500_copy = SP500.copy()
sp500_copy.index = idx[: sp500_copy.shape[0]]
res = ConstantMean(sp500_copy).fit(disp=False)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def dfgsl_simulation(
results = np.zeros((len(percentiles), len(T), EX_NUM))

for i in range(EX_NUM):
print(f"Experiment Number {i + 1} of {EX_NUM} " "(trend {tr})")
print(f"Experiment Number {i + 1} of {EX_NUM} (trend {tr})")
now = datetime.datetime.now()
parallel, p_func, n_jobs = parallel_func(
wrapper, n_jobs=NUM_JOBS, verbose=2
Expand Down
2 changes: 1 addition & 1 deletion arch/unitroot/unitroot.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@


def _is_reduced_rank(
x: Union[Float64Array, DataFrame]
x: Union[Float64Array, DataFrame],
) -> tuple[bool, Union[int, None]]:
"""
Check if a matrix has reduced rank preferring quick checks
Expand Down
7 changes: 6 additions & 1 deletion arch/univariate/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@
)
from arch.utility.testing import WaldTestStatistic

MPL_LT_310 = False
try:
from matplotlib import __version__
from matplotlib.figure import Figure
from packaging.version import Version

MPL_LT_310 = Version(__version__) < Version("3.10.0")
except ImportError:
pass

Expand Down Expand Up @@ -1642,7 +1647,7 @@ def hedgehog_plot(

fig, ax = plt.subplots(1, 1)
use_date = isinstance(self._dep_var.index, pd.DatetimeIndex)
plot_fn = ax.plot_date if use_date else ax.plot
plot_fn = ax.plot_date if use_date and MPL_LT_310 else ax.plot
x_values = np.array(self._dep_var.index)
if plot_mean:
y_values = np.asarray(self._dep_var)
Expand Down
43 changes: 22 additions & 21 deletions arch/univariate/distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Distributions to use in ARCH models. All distributions must inherit from
:class:`Distribution` and provide the same methods with the same inputs.
"""

from abc import ABCMeta, abstractmethod
from collections.abc import Sequence
from typing import Callable, Optional, Union
Expand Down Expand Up @@ -100,8 +101,8 @@ def _check_constraints(
for p, n, b in zip(params, self.name, bounds):
if not (b[0] <= p <= b[1]):
raise ValueError(
"{} does not satisfy the bounds requirement "
"of ({}, {})".format(n, *b)
f"{n} does not satisfy the bounds requirement of "
f"({b[0]}, {b[1]})"
)
return asarray(params)

Expand Down Expand Up @@ -205,7 +206,7 @@ def loglikelihood(
resids: ArrayLike,
sigma2: ArrayLike,
individual: bool = False,
) -> Union[float , Float64Array]:
) -> Union[float, Float64Array]:
"""
Loglikelihood evaluation.

Expand Down Expand Up @@ -264,7 +265,7 @@ def ppf(
self,
pits: Union[float, Sequence[float], ArrayLike1D],
parameters: Union[Sequence[float], ArrayLike1D, None] = None,
) -> Union[float , Float64Array]:
) -> Union[float, Float64Array]:
"""
Inverse cumulative density function (ICDF)

Expand Down Expand Up @@ -414,7 +415,7 @@ def loglikelihood(
resids: ArrayLike,
sigma2: ArrayLike,
individual: bool = False,
) -> Union[float , Float64Array]:
) -> Union[float, Float64Array]:
r"""Computes the log-likelihood of assuming residuals are normally
distributed, conditional on the variance

Expand Down Expand Up @@ -446,7 +447,7 @@ def loglikelihood(
+\frac{x^{2}}{\sigma^{2}}\right)

"""
lls = -0.5 * (log(2 * pi) + log(sigma2) + resids ** 2.0 / sigma2)
lls = -0.5 * (log(2 * pi) + log(sigma2) + resids**2.0 / sigma2)
if individual:
return lls
else:
Expand Down Expand Up @@ -557,7 +558,7 @@ def loglikelihood(
resids: ArrayLike,
sigma2: ArrayLike,
individual: bool = False,
) -> Union[float , Float64Array]:
) -> Union[float, Float64Array]:
r"""Computes the log-likelihood of assuming residuals are have a
standardized (to have unit variance) Student's t distribution,
conditional on the variance.
Expand Down Expand Up @@ -595,7 +596,7 @@ def loglikelihood(
nu = parameters[0]
lls = gammaln((nu + 1) / 2) - gammaln(nu / 2) - log(pi * (nu - 2)) / 2
lls -= 0.5 * (log(sigma2))
lls -= ((nu + 1) / 2) * (log(1 + (resids ** 2.0) / (sigma2 * (nu - 2))))
lls -= ((nu + 1) / 2) * (log(1 + (resids**2.0) / (sigma2 * (nu - 2))))

if individual:
return lls
Expand Down Expand Up @@ -685,7 +686,7 @@ def partial_moment(
nu = parameters[0]
var = nu / (nu - 2)
scale = 1.0 / sqrt(var)
moment = (scale ** n) * self._ord_t_partial_moment(n, z / scale, nu)
moment = (scale**n) * self._ord_t_partial_moment(n, z / scale, nu)
return moment

@staticmethod
Expand Down Expand Up @@ -729,9 +730,9 @@ def _ord_t_partial_moment(n: int, z: float, nu: float) -> float:
elif n == 1:
c = gamma(0.5 * (nu + 1)) / (sqrt(nu * pi) * gamma(0.5 * nu))
e = 0.5 * (nu + 1)
moment = (0.5 * (c * nu) / (1 - e)) * ((1 + (z ** 2) / nu) ** (1 - e))
moment = (0.5 * (c * nu) / (1 - e)) * ((1 + (z**2) / nu) ** (1 - e))
else:
t1 = (z ** (n - 1)) * (nu + z ** 2) * stats.t.pdf(z, nu)
t1 = (z ** (n - 1)) * (nu + z**2) * stats.t.pdf(z, nu)
t2 = (n - 1) * nu * StudentsT._ord_t_partial_moment(n - 2, z, nu)
moment = (1 / (n - nu)) * (t1 - t2)
return moment
Expand Down Expand Up @@ -846,7 +847,7 @@ def loglikelihood(
const_a = self.__const_a(parameters)
const_b = self.__const_b(parameters)

resids = resids / sigma2 ** 0.5
resids = resids / sigma2**0.5
lls = log(const_b) + const_c - log(sigma2) / 2
if abs(lam) >= 1.0:
lam = sign(lam) * (1.0 - 1e-6)
Expand Down Expand Up @@ -911,7 +912,7 @@ def simulate(
def parameter_names(self) -> list[str]:
return ["eta", "lambda"]

def __const_a(self, parameters: Union[Float64Array , Sequence[float]]) -> float:
def __const_a(self, parameters: Union[Float64Array, Sequence[float]]) -> float:
"""
Compute a constant.

Expand All @@ -930,7 +931,7 @@ def __const_a(self, parameters: Union[Float64Array , Sequence[float]]) -> float:
c = self.__const_c(parameters)
return float(4 * lam * exp(c) * (eta - 2) / (eta - 1))

def __const_b(self, parameters: Union[Float64Array , Sequence[float]]) -> float:
def __const_b(self, parameters: Union[Float64Array, Sequence[float]]) -> float:
"""
Compute b constant.

Expand All @@ -946,7 +947,7 @@ def __const_b(self, parameters: Union[Float64Array , Sequence[float]]) -> float:
"""
lam = float(parameters[1])
a = self.__const_a(parameters)
return (1 + 3 * lam ** 2 - a ** 2) ** 0.5
return (1 + 3 * lam**2 - a**2) ** 0.5

@staticmethod
def __const_c(parameters: Union[Float64Array, Sequence[float]]) -> float:
Expand Down Expand Up @@ -999,7 +1000,7 @@ def ppf(
self,
pits: Union[float, Sequence[float], ArrayLike1D],
parameters: Union[Sequence[float], ArrayLike1D, None] = None,
) -> Union[float , Float64Array]:
) -> Union[float, Float64Array]:
parameters = self._check_constraints(parameters)
scalar = isscalar(pits)
if scalar:
Expand Down Expand Up @@ -1052,8 +1053,8 @@ def moment(
)
l_pmom = ((-1) ** k) * r_pmom

lhs = (1 - lam) * (lscale ** k) * (loc ** (n - k)) * l_pmom
rhs = (1 + lam) * (rscale ** k) * (loc ** (n - k)) * r_pmom
lhs = (1 - lam) * (lscale**k) * (loc ** (n - k)) * l_pmom
rhs = (1 + lam) * (rscale**k) * (loc ** (n - k)) * r_pmom
moment += comb(n, k) * (lhs + rhs)

return moment
Expand Down Expand Up @@ -1083,15 +1084,15 @@ def partial_moment(
lhs = (
(1 - lam)
* (loc ** (n - k))
* (lscale ** k)
* (lscale**k)
* StudentsT._ord_t_partial_moment(k, z=(lbound - loc) / lscale, nu=eta)
)

if z > loc:
rhs = (
(1 + lam)
* (loc ** (n - k))
* (rscale ** k)
* (rscale**k)
* (
StudentsT._ord_t_partial_moment(k, z=(z - loc) / rscale, nu=eta)
- StudentsT._ord_t_partial_moment(k, z=0.0, nu=eta)
Expand Down Expand Up @@ -1285,7 +1286,7 @@ def partial_moment(
parameters = self._check_constraints(parameters)
nu = parameters[0]
scale = 1.0 / sqrt(stats.gennorm(nu).var())
moment = (scale ** n) * self._ord_gennorm_partial_moment(n, z / scale, nu)
moment = (scale**n) * self._ord_gennorm_partial_moment(n, z / scale, nu)
return moment

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion arch/univariate/mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ def forecast(
"Due to backcasting and/or data availability start cannot be less "
"than the index of the largest value in the right-hand-side "
"variables used to fit the first observation. In this model, "
"this value is {}.".format(max(0, earliest - 1))
f"this value is {max(0, earliest - 1)}."
)
# Parse params
params = np.asarray(params)
Expand Down
3 changes: 1 addition & 2 deletions arch/univariate/volatility.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,7 @@ def _bootstrap_forecast(
std_resid = resids / np.sqrt(sigma2)
if start < self._min_bootstrap_obs:
raise ValueError(
"start must include more than {} "
"observations".format(self._min_bootstrap_obs)
f"start must include more than {self._min_bootstrap_obs} observations"
)
rng = BootstrapRng(std_resid, start, random_state=random_state).rng()
return self._simulation_forecast(
Expand Down
2 changes: 2 additions & 0 deletions ci/azure/azure_template_posix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
python_313:
python.version: '3.13'
python_312:
python.version: '3.12'
python_311:
Expand Down
2 changes: 2 additions & 0 deletions ci/azure/azure_template_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
python.version: '3.11'
python312_win_latest:
python.version: '3.12'
python313_win_latest:
python.version: '3.12'
maxParallel: 10

steps:
Expand Down
6 changes: 3 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ pytest-xdist
pytest-cov

# formatting
black[jupyter]~=24.8.0
isort~=5.0
black[jupyter]~=24.10.0
isort~=5.12
colorama
flake8
mypy
ruff
ruff>=0.8.6
pyupgrade>=3.4.0
jupyterlab-code-formatter

Expand Down
Loading