forecastscope 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ """Finite-prefix forecasts and causal historical forecast combinations."""
2
+ from .api import METHOD_NAMES, combine, forecast
3
+
4
+ __version__ = "0.1.0"
5
+ __all__ = ["METHOD_NAMES", "combine", "forecast"]
forecastscope/api.py ADDED
@@ -0,0 +1,72 @@
1
+ """Validated entry points; legacy numerical kernels retain their original equations."""
2
+ from __future__ import annotations
3
+
4
+ from itertools import pairwise
5
+
6
+ import numpy as np
7
+
8
+ from .combinations.context_memory import MemoryFit, fit_context_memory
9
+ from .combinations.validated import ValidatedFit, fit_validated
10
+ from .forecasting import METHOD_FNS, gaussian_quantiles
11
+
12
+ METHOD_NAMES = tuple(METHOD_FNS)
13
+
14
+
15
+ def _request(history, seasonality, horizon, quantiles):
16
+ y = np.asarray(history, dtype=float)
17
+ if y.ndim != 1 or len(y) < 2 or not np.isfinite(y).all():
18
+ raise ValueError("A contiguous finite one-dimensional history of at least two observations is required")
19
+ for name, value in [("seasonality", seasonality), ("horizon", horizon)]:
20
+ if isinstance(value, (bool, np.bool_)) or not isinstance(value, (int, np.integer)) or value < 1:
21
+ raise ValueError(f"{name} must be a positive integer")
22
+ if seasonality >= len(y):
23
+ raise ValueError("seasonality must be smaller than the observed history length")
24
+ levels = tuple(float(q) for q in quantiles)
25
+ if not levels or not np.isfinite(levels).all() or not all(0 < q < 1 for q in levels) or not all(a < b for a, b in pairwise(levels)):
26
+ raise ValueError("Quantiles must be finite, strictly increasing probabilities between zero and one")
27
+ return y, int(seasonality), int(horizon), levels
28
+
29
+
30
+ def _output(values, horizon, levels):
31
+ a = np.asarray(values, dtype=float)
32
+ if a.shape != (horizon, len(levels)) or not np.isfinite(a).all() or np.any(np.diff(a, axis=1) < 0):
33
+ raise ValueError("The method returned invalid forecast dimensions, nonfinite values or crossing columns")
34
+ return a
35
+
36
+
37
+ def forecast(method: str, history, *, seasonality: int = 1, horizon: int = 1, quantiles=(.1, .5, .9)) -> np.ndarray:
38
+ """Return full-precision horizon-by-quantile Gaussian residual columns.
39
+
40
+ Inputs must be contiguous and finite; no imputation, source acquisition or
41
+ seasonal-period selection is performed. These approximate intervals carry no
42
+ calibration guarantee. Methods refit on the whole supplied prefix.
43
+ """
44
+ y, m, h, levels = _request(history, seasonality, horizon, quantiles)
45
+ if method not in METHOD_FNS:
46
+ raise ValueError(f"Unknown method {method!r}; choose from {METHOD_NAMES}")
47
+ point, sigma = METHOD_FNS[method](y, m, h)
48
+ return _output(gaussian_quantiles(point, sigma, levels), h, levels)
49
+
50
+
51
+ def combine(method: str, history, *, seasonality: int = 1, horizon: int = 1, quantiles=(.1, .5, .9)) -> MemoryFit | ValidatedFit:
52
+ """Fit a five-expert combination without accepting a reserved future block.
53
+
54
+ The returned object retains weights and complete historical origins. The
55
+ validated variants additionally retain candidate scores and inner splits.
56
+ Their canonical probability grid is fixed; unsupported grids are refused.
57
+ """
58
+ y, m, h, levels = _request(history, seasonality, horizon, quantiles)
59
+ modes = {"ContextMemory": "context", "RecencyMean": "recency", "EqualMean": "uniform"}
60
+ if method in modes:
61
+ result = fit_context_memory(y, m, h, levels, mode=modes[method])
62
+ elif method in ("ContextMemoryCV", "ValidationMix"):
63
+ if levels != (.1, .5, .9):
64
+ raise ValueError("Temporally validated combinations require quantiles (0.1, 0.5, 0.9)")
65
+ result = fit_validated(y, m, h, stacking=method == "ValidationMix")
66
+ else:
67
+ raise ValueError(f"Unknown combination {method!r}")
68
+ _output(result.quantiles, h, levels)
69
+ weights = np.asarray(result.weights)
70
+ if weights.shape != (5,) or not np.isfinite(weights).all() or np.any(weights < 0) or not np.isclose(weights.sum(), 1):
71
+ raise ValueError("Invalid expert allocation")
72
+ return result
@@ -0,0 +1 @@
1
+ """Fixed-context and temporally validated combinations of five reference experts."""
@@ -0,0 +1,127 @@
1
+ """ContextMemory: a within-series forecast-combination proposal and its ablations.
2
+
3
+ Published feature-based averaging and dynamic ensembles motivate the proposal; this
4
+ specific recurrence/recency rule is an experiment, with no claim of priority or superiority.
5
+ All training targets end before the supplied history ends. The final holdout is never an input.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ from functools import lru_cache
11
+
12
+ import numpy as np
13
+
14
+ from ..forecasting import METHODS, Forecaster, _clean, gaussian_quantiles
15
+
16
+ CONFIG = {
17
+ "memory_origins": 12,
18
+ "half_life_origins": 6.0,
19
+ "global_shrinkage": 0.25,
20
+ "uniform_floor": 0.05,
21
+ "temperature": 1.0,
22
+ "kernel_bandwidth_floor": 0.25,
23
+ }
24
+ EXPERT_NAMES = tuple(name for name, _, _ in METHODS)
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class MemoryFit:
29
+ quantiles: np.ndarray
30
+ weights: np.ndarray
31
+ origins: tuple[int, ...]
32
+ context: np.ndarray
33
+
34
+
35
+ def context_features(y: np.ndarray, m: int) -> np.ndarray:
36
+ """Four bounded, location-invariant and positive-scale-invariant summaries."""
37
+ w = min(len(y) // 2, max(8, min(2 * max(m, 1), 48)))
38
+ if w < 2:
39
+ return np.zeros(4)
40
+ recent, previous = y[-w:], y[-2 * w:-w]
41
+ scale = float(np.std(y[-2 * w:]))
42
+ if scale < 1e-12:
43
+ return np.zeros(4)
44
+ half = max(1, w // 2)
45
+ slope = (np.mean(recent[-half:]) - np.mean(recent[:half])) / scale
46
+ shift = (np.mean(recent) - np.mean(previous)) / scale
47
+ vr, vp = float(np.std(np.diff(recent))), float(np.std(np.diff(previous)))
48
+ volatility = np.log((vr + scale * 1e-6) / (vp + scale * 1e-6))
49
+ periodicity = 0.0
50
+ if m >= 2 and len(y) >= 2 * m + 2:
51
+ a, b = y[-2 * m:-m], y[-m:]
52
+ if np.std(a) > 1e-12 and np.std(b) > 1e-12:
53
+ periodicity = float(np.corrcoef(a, b)[0, 1])
54
+ return np.clip([slope, shift, volatility, periodicity], -4, 4)
55
+
56
+
57
+ def _scale(y: np.ndarray, m: int) -> float:
58
+ lag = max(1, min(m, len(y) - 1))
59
+ value = float(np.mean(np.abs(y[lag:] - y[:-lag])))
60
+ return value if value > 1e-12 else max(float(np.std(y)), 1e-12)
61
+
62
+
63
+ @lru_cache(maxsize=64)
64
+ def _memory(values: tuple[float, ...], m: int, h: int):
65
+ y = np.asarray(values)
66
+ first, last = max(2 * m, 2 * h + 8, 24), len(y) - h
67
+ if last < first:
68
+ return (), np.empty((0, 4)), np.empty((0, len(METHODS)))
69
+ origins = tuple(int(o) for o in np.unique(np.linspace(first, last, CONFIG["memory_origins"], dtype=int)))
70
+ features, losses = [], []
71
+ for origin in origins:
72
+ history, truth = y[:origin], y[origin:origin + h]
73
+ features.append(context_features(history, m))
74
+ losses.append([
75
+ float(np.mean(np.abs(fn(history, m, h)[0] - truth))) / _scale(history, m)
76
+ for _, _, fn in METHODS
77
+ ])
78
+ return origins, np.asarray(features), np.asarray(losses)
79
+
80
+
81
+ def fit_context_memory(y: np.ndarray, m: int, h: int, levels=(0.1, 0.5, 0.9), mode="context") -> MemoryFit:
82
+ """Fit from completed historical origins, then combine experts at the query origin.
83
+
84
+ The recency ablation removes the context kernel; the uniform ablation removes
85
+ both learning components. Configuration is fixed before the released holdout run.
86
+ Weighted quantiles are a quantile combination, not a calibrated mixture distribution.
87
+ """
88
+ y = _clean(np.asarray(y, dtype=float))
89
+ if len(y) < 2 or not np.isfinite(y).all() or h < 1 or m < 1:
90
+ raise ValueError("ContextMemory requires finite history, positive horizon and seasonality")
91
+ if mode not in {"context", "recency", "uniform"}:
92
+ raise ValueError(f"Unknown combination mode: {mode}")
93
+ origins, features, losses = _memory(tuple(float(v) for v in y), m, h)
94
+ query = context_features(y, m)
95
+ weights = np.full(len(METHODS), 1 / len(METHODS))
96
+ if len(origins) and mode != "uniform":
97
+ ages = np.arange(len(origins) - 1, -1, -1)
98
+ recency = np.exp2(-ages / CONFIG["half_life_origins"])
99
+ global_loss = np.average(losses, axis=0, weights=recency)
100
+ score = global_loss
101
+ if mode == "context":
102
+ distance = np.sqrt(np.mean((features - query) ** 2, axis=1))
103
+ bandwidth = max(float(np.median(distance)), CONFIG["kernel_bandwidth_floor"])
104
+ local = recency * np.exp(-0.5 * (distance / bandwidth) ** 2)
105
+ local_loss = np.average(losses, axis=0, weights=local)
106
+ shrink = CONFIG["global_shrinkage"]
107
+ score = (1 - shrink) * local_loss + shrink * global_loss
108
+ logits = -(score - np.min(score)) / CONFIG["temperature"]
109
+ weights = np.exp(np.clip(logits, -700, 0))
110
+ weights /= weights.sum()
111
+ floor = CONFIG["uniform_floor"]
112
+ weights = (1 - floor) * weights + floor / len(METHODS)
113
+ forecasts = []
114
+ for _, _, fn in METHODS:
115
+ point, sigma = fn(y, m, h)
116
+ forecasts.append(gaussian_quantiles(point, sigma, tuple(levels)))
117
+ combined = np.tensordot(weights, np.asarray(forecasts), axes=(0, 0))
118
+ return MemoryFit(combined, weights, origins, query)
119
+
120
+
121
+ class ContextMemoryForecaster(Forecaster):
122
+ name = "ContextMemory"
123
+ family = "adaptive ensemble"
124
+ max_windows = 3
125
+
126
+ def quantiles(self, y, m, h, levels):
127
+ return fit_context_memory(y, m, h, levels).quantiles
@@ -0,0 +1,144 @@
1
+ """Forecast combinations selected by validation wholly inside the observed prefix.
2
+
3
+ No outer target is accepted by this API. Model selection compares completed
4
+ historical blocks, and each inner fit excludes blocks not completed at its query.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass
9
+ from functools import lru_cache
10
+ from itertools import combinations
11
+
12
+ import numpy as np
13
+
14
+ from ..forecasting import METHODS, gaussian_quantiles
15
+ from .context_memory import CONFIG, _scale, context_features
16
+
17
+ CANDIDATES = (
18
+ ("recency", 1., 1.), ("equal", 0., 1.),
19
+ *(("context", shrink, temp) for shrink in (0., .5, 1.) for temp in (.15, .5, 1.)),
20
+ *(("stack", penalty, 1.) for penalty in (.01, .1, 1., 10.)),
21
+ )
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class ValidatedFit:
26
+ quantiles: np.ndarray
27
+ weights: np.ndarray
28
+ selected: tuple[str, float, float]
29
+ candidates: tuple[dict, ...]
30
+ origins: tuple[int, ...]
31
+ validation_splits: tuple[dict, ...]
32
+
33
+
34
+ def convex_weights(errors, penalty):
35
+ """Convex squared-error stacking with shrinkage toward uniform allocation."""
36
+ a = np.asarray(errors, dtype=float)
37
+ if a.ndim != 2 or not len(a) or not np.isfinite(a).all() or penalty <= 0:
38
+ raise ValueError("Stacking requires finite error rows and positive regularization")
39
+ k = a.shape[1]
40
+ uniform = np.full(k, 1 / k)
41
+ gram = a.T @ a / len(a)
42
+
43
+ def objective(w):
44
+ return float(w @ gram @ w + penalty * np.sum((w - uniform) ** 2))
45
+
46
+ # Five experts permit exhaustive active-set solutions (31 nonempty faces).
47
+ # Each face has a positive-definite regularized quadratic; the best feasible
48
+ # face is the constrained optimum, without iterative solver stopping rules.
49
+ best, value = uniform, objective(uniform)
50
+ for size in range(1, k + 1):
51
+ for active in combinations(range(k), size):
52
+ ids = list(active)
53
+ matrix = gram[np.ix_(ids, ids)] + penalty * np.eye(size)
54
+ rhs = np.column_stack((penalty * uniform[ids], np.ones(size)))
55
+ try:
56
+ solution = np.linalg.solve(matrix, rhs)
57
+ except np.linalg.LinAlgError:
58
+ continue
59
+ x, direction = solution[:, 0], solution[:, 1]
60
+ x = x + (1 - x.sum()) * direction / direction.sum()
61
+ if not np.isfinite(x).all() or np.min(x) < -1e-10:
62
+ continue
63
+ weights = np.zeros(k)
64
+ weights[ids] = np.maximum(x, 0.)
65
+ weights /= weights.sum()
66
+ score = objective(weights)
67
+ if score < value:
68
+ best, value = weights, score
69
+ return best
70
+
71
+
72
+ def candidate_weights(candidate, features, losses, errors, query):
73
+ k = len(METHODS)
74
+ kind, shrink, temp = candidate
75
+ if not len(losses) or kind == "equal":
76
+ return np.full(k, 1 / k)
77
+ if kind == "stack":
78
+ weights = convex_weights(errors.reshape(-1, k), shrink)
79
+ else:
80
+ ages = np.arange(len(losses) - 1, -1, -1)
81
+ recency = np.exp2(-ages / CONFIG["half_life_origins"])
82
+ global_loss = np.average(losses, axis=0, weights=recency)
83
+ score = global_loss
84
+ if kind == "context":
85
+ distance = np.sqrt(np.mean((features - query) ** 2, axis=1))
86
+ bandwidth = max(float(np.median(distance)), CONFIG["kernel_bandwidth_floor"])
87
+ local = recency * np.exp(-.5 * (distance / bandwidth) ** 2)
88
+ score = (1 - shrink) * np.average(losses, axis=0, weights=local) + shrink * global_loss
89
+ weights = np.exp(np.clip(-(score - np.min(score)) / temp, -700, 0))
90
+ weights /= weights.sum()
91
+ return .95 * weights + .05 / k
92
+
93
+
94
+ @lru_cache(maxsize=16)
95
+ def memory(values, m, h):
96
+ y = np.asarray(values, dtype=float)
97
+ first, last = max(2 * m, 2 * h + 8, 24), len(y) - h
98
+ if first > last:
99
+ return (), np.empty((0, 4)), np.empty((0, len(METHODS))), np.empty((0, h, len(METHODS))), ()
100
+ origins = tuple(int(o) for o in np.unique(np.linspace(first, last, CONFIG["memory_origins"], dtype=int)))
101
+ features, losses, errors, paths = [], [], [], []
102
+ for origin in origins:
103
+ prefix, truth = y[:origin], y[origin:origin+h]
104
+ quantiles = np.array([gaussian_quantiles(*fn(prefix, m, h), (.1, .5, .9)) for _, _, fn in METHODS])
105
+ normalized_error = (quantiles[:, :, 1].T - truth[:, None]) / _scale(prefix, m)
106
+ features.append(context_features(prefix, m))
107
+ losses.append(np.mean(abs(normalized_error), axis=0))
108
+ errors.append(normalized_error)
109
+ paths.append(quantiles)
110
+ return origins, np.asarray(features), np.asarray(losses), np.asarray(errors), tuple(paths)
111
+
112
+
113
+ def temporal_splits(origins, horizon):
114
+ """Training outcomes must be fully observed when an inner forecast is issued."""
115
+ return tuple({"query": query, "train": tuple(i for i, origin in enumerate(origins) if origin+horizon <= query)}
116
+ for query in origins)
117
+
118
+
119
+ def fit_validated(y, m, h, *, stacking=True):
120
+ y = np.asarray(y, dtype=float)
121
+ if y.ndim != 1 or len(y) < 2 or not np.isfinite(y).all() or m < 1 or h < 1:
122
+ raise ValueError("Finite contiguous history, positive seasonality and horizon are required")
123
+ origins, features, losses, errors, _paths = memory(tuple(y), m, h)
124
+ candidates = CANDIDATES if stacking else tuple(c for c in CANDIDATES if c[0] != "stack")
125
+ splits = tuple(s for s in temporal_splits(origins, h) if len(s["train"]) >= 3)
126
+ scores = []
127
+ for candidate in candidates:
128
+ values = []
129
+ for split in splits:
130
+ j = origins.index(split["query"])
131
+ train = list(split["train"])
132
+ w = candidate_weights(candidate, features[train], losses[train], errors[train], features[j])
133
+ values.append(float(np.mean(abs(errors[j] @ w))))
134
+ scores.append({"configuration": candidate, "mean_validation_mae_scaled": float(np.mean(values)) if values else None,
135
+ "validation_blocks": len(values)})
136
+ if splits:
137
+ winner = min(range(len(candidates)), key=lambda i: (scores[i]["mean_validation_mae_scaled"], i))
138
+ else:
139
+ winner = 0 # explicit original recency-only fallback
140
+ selected = candidates[winner]
141
+ w = candidate_weights(selected, features, losses, errors, context_features(y, m))
142
+ experts = np.array([gaussian_quantiles(*fn(y, m, h), (.1, .5, .9)) for _, _, fn in METHODS])
143
+ combined = np.tensordot(w, experts, axes=(0, 0))
144
+ return ValidatedFit(combined, w, selected, tuple(scores), origins, splits)
@@ -0,0 +1,236 @@
1
+ """Optional time-series diagnostics delegated to named scientific implementations.
2
+
3
+ Results describe the supplied sequence. Retrospective use is distinct from
4
+ prefix-only forecasting features; statistical assumptions remain method-specific.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from . import (
9
+ autocorrelation,
10
+ causality,
11
+ changepoints,
12
+ distribution,
13
+ filters,
14
+ fractal,
15
+ nonlinear,
16
+ seasonality,
17
+ stationarity,
18
+ volatility,
19
+ )
20
+ from .autocorrelation import (
21
+ Correlogram,
22
+ PortmanteauTest,
23
+ acf,
24
+ autocorrelation_report,
25
+ bartlett_band,
26
+ box_pierce,
27
+ durbin_watson,
28
+ lag_plot_pairs,
29
+ ljung_box,
30
+ pacf,
31
+ )
32
+ from .causality import (
33
+ CointegrationResult,
34
+ CrossCorrelation,
35
+ GrangerResult,
36
+ causality_report,
37
+ cointegration,
38
+ cross_correlation,
39
+ granger_causality,
40
+ )
41
+ from .changepoints import (
42
+ ChangePoints,
43
+ CusumResult,
44
+ RegimeFit,
45
+ binseg,
46
+ changepoints_report,
47
+ cusum_stability,
48
+ markov_regimes,
49
+ pelt,
50
+ )
51
+ from .distribution import (
52
+ ComplexitySummary,
53
+ DistributionSummary,
54
+ catch22_features,
55
+ complexity,
56
+ distribution_report,
57
+ kde_curve,
58
+ qq_points,
59
+ summary,
60
+ )
61
+ from .filters import (
62
+ EMDResult,
63
+ FilterResult,
64
+ Scalogram,
65
+ baxter_king,
66
+ ceemdan,
67
+ christiano_fitzgerald,
68
+ cwt_scalogram,
69
+ emd,
70
+ filters_report,
71
+ hodrick_prescott,
72
+ )
73
+ from .fractal import (
74
+ FractalDimension,
75
+ HurstResult,
76
+ MultifractalSpectrum,
77
+ dcca_coefficient,
78
+ fractal_dimension,
79
+ fractal_report,
80
+ hurst,
81
+ mfdfa,
82
+ )
83
+ from .nonlinear import (
84
+ RQA,
85
+ ChaosMeasures,
86
+ chaos_measures,
87
+ iaaft_surrogate,
88
+ nonlinear_report,
89
+ recurrence_quantification,
90
+ time_delay_embed,
91
+ zero_one_test,
92
+ )
93
+ from .seasonality import (
94
+ Decomp,
95
+ SeasonalSubseries,
96
+ Spectrum,
97
+ mstl_decompose,
98
+ periodogram,
99
+ seasonal_strength,
100
+ seasonal_subseries,
101
+ seasonality_report,
102
+ stl_decompose,
103
+ welch,
104
+ )
105
+ from .stationarity import (
106
+ TestResult,
107
+ adf,
108
+ combined_verdict,
109
+ dfgls,
110
+ kpss,
111
+ ndiffs,
112
+ nsdiffs,
113
+ phillips_perron,
114
+ stationarity_report,
115
+ zivot_andrews,
116
+ )
117
+ from .volatility import (
118
+ ArchTest,
119
+ BoxCoxResult,
120
+ GarchFit,
121
+ arch_lm,
122
+ box_cox,
123
+ garch,
124
+ rolling_volatility,
125
+ volatility_report,
126
+ )
127
+
128
+ __all__ = [
129
+ "RQA",
130
+ # volatility
131
+ "ArchTest",
132
+ "BoxCoxResult",
133
+ # changepoints
134
+ "ChangePoints",
135
+ # nonlinear
136
+ "ChaosMeasures",
137
+ "CointegrationResult",
138
+ "ComplexitySummary",
139
+ # autocorrelation
140
+ "Correlogram",
141
+ # causality
142
+ "CrossCorrelation",
143
+ "CusumResult",
144
+ "Decomp",
145
+ # distribution
146
+ "DistributionSummary",
147
+ "EMDResult",
148
+ # filters
149
+ "FilterResult",
150
+ "FractalDimension",
151
+ "GarchFit",
152
+ "GrangerResult",
153
+ # fractal
154
+ "HurstResult",
155
+ "MultifractalSpectrum",
156
+ "PortmanteauTest",
157
+ "RegimeFit",
158
+ "Scalogram",
159
+ "SeasonalSubseries",
160
+ # seasonality (seasonal_strength lives here as the canonical home)
161
+ "Spectrum",
162
+ # stationarity
163
+ "TestResult",
164
+ "acf",
165
+ "adf",
166
+ "arch_lm",
167
+ "autocorrelation",
168
+ "autocorrelation_report",
169
+ "bartlett_band",
170
+ "baxter_king",
171
+ "binseg",
172
+ "box_cox",
173
+ "box_pierce",
174
+ "catch22_features",
175
+ "causality",
176
+ "causality_report",
177
+ "ceemdan",
178
+ "changepoints",
179
+ "changepoints_report",
180
+ "chaos_measures",
181
+ "christiano_fitzgerald",
182
+ "cointegration",
183
+ "combined_verdict",
184
+ "complexity",
185
+ "cross_correlation",
186
+ "cusum_stability",
187
+ "cwt_scalogram",
188
+ "dcca_coefficient",
189
+ "dfgls",
190
+ "distribution",
191
+ "distribution_report",
192
+ "durbin_watson",
193
+ "emd",
194
+ "filters",
195
+ "filters_report",
196
+ "fractal",
197
+ "fractal_dimension",
198
+ "fractal_report",
199
+ "garch",
200
+ "granger_causality",
201
+ "hodrick_prescott",
202
+ "hurst",
203
+ "iaaft_surrogate",
204
+ "kde_curve",
205
+ "kpss",
206
+ "lag_plot_pairs",
207
+ "ljung_box",
208
+ "markov_regimes",
209
+ "mfdfa",
210
+ "mstl_decompose",
211
+ "ndiffs",
212
+ "nonlinear",
213
+ "nonlinear_report",
214
+ "nsdiffs",
215
+ "pacf",
216
+ "pelt",
217
+ "periodogram",
218
+ "phillips_perron",
219
+ "qq_points",
220
+ "recurrence_quantification",
221
+ "rolling_volatility",
222
+ "seasonal_strength",
223
+ "seasonal_subseries",
224
+ "seasonality",
225
+ "seasonality_report",
226
+ "stationarity",
227
+ "stationarity_report",
228
+ "stl_decompose",
229
+ "summary",
230
+ "time_delay_embed",
231
+ "volatility",
232
+ "volatility_report",
233
+ "welch",
234
+ "zero_one_test",
235
+ "zivot_andrews",
236
+ ]