variance-test 0.1.0__tar.gz
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.
- variance_test-0.1.0/LICENSE +21 -0
- variance_test-0.1.0/PKG-INFO +417 -0
- variance_test-0.1.0/README.md +374 -0
- variance_test-0.1.0/pyproject.toml +40 -0
- variance_test-0.1.0/setup.cfg +4 -0
- variance_test-0.1.0/src/variance_test/__init__.py +32 -0
- variance_test-0.1.0/src/variance_test/battery.py +445 -0
- variance_test-0.1.0/src/variance_test/core.py +291 -0
- variance_test-0.1.0/src/variance_test/data.py +80 -0
- variance_test-0.1.0/src/variance_test/models.py +101 -0
- variance_test-0.1.0/src/variance_test/price_paths.py +268 -0
- variance_test-0.1.0/src/variance_test/rolling.py +208 -0
- variance_test-0.1.0/src/variance_test/simulation.py +315 -0
- variance_test-0.1.0/src/variance_test/visuals.py +166 -0
- variance_test-0.1.0/src/variance_test.egg-info/PKG-INFO +417 -0
- variance_test-0.1.0/src/variance_test.egg-info/SOURCES.txt +26 -0
- variance_test-0.1.0/src/variance_test.egg-info/dependency_links.txt +1 -0
- variance_test-0.1.0/src/variance_test.egg-info/requires.txt +4 -0
- variance_test-0.1.0/src/variance_test.egg-info/top_level.txt +1 -0
- variance_test-0.1.0/tests/test_battery.py +318 -0
- variance_test-0.1.0/tests/test_build_metadata.py +34 -0
- variance_test-0.1.0/tests/test_data_normalization.py +67 -0
- variance_test-0.1.0/tests/test_models.py +103 -0
- variance_test-0.1.0/tests/test_package_imports.py +31 -0
- variance_test-0.1.0/tests/test_public_api.py +78 -0
- variance_test-0.1.0/tests/test_rolling.py +258 -0
- variance_test-0.1.0/tests/test_simulation_compat.py +63 -0
- variance_test-0.1.0/tests/test_vrt_hardening.py +85 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 LautaroParada
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: variance-test
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Variance Ratio Test utilities for stochastic price processes.
|
|
5
|
+
Author: SeraFlow
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2020 LautaroParada
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/LautaroParada/variance-test
|
|
29
|
+
Project-URL: Repository, https://github.com/LautaroParada/variance-test
|
|
30
|
+
Classifier: Programming Language :: Python :: 3
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Operating System :: OS Independent
|
|
35
|
+
Requires-Python: >=3.11
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
License-File: LICENSE
|
|
38
|
+
Requires-Dist: numpy
|
|
39
|
+
Requires-Dist: scipy
|
|
40
|
+
Requires-Dist: matplotlib
|
|
41
|
+
Requires-Dist: statsmodels
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# variance-test
|
|
45
|
+
|
|
46
|
+
[](https://pypi.org/project/variance-test/)
|
|
47
|
+
[](https://pypi.org/project/variance-test/)
|
|
48
|
+
[](https://github.com/LautaroParada/variance-test/actions/workflows/ci.yml)
|
|
49
|
+
[](https://github.com/LautaroParada/variance-test/blob/master/LICENSE)
|
|
50
|
+
|
|
51
|
+
Testing whether a return series is compatible with a random walk usually means stitching together a variance ratio implementation, a Ljung-Box call, an ARCH-LM check, a runs test, and some ad-hoc glue code to normalize inputs and interpret results. Then you repeat it for rolling windows. Then you do it again for the next asset.
|
|
52
|
+
|
|
53
|
+
`variance-test` replaces that workflow with a single structured call.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from variance_test import BatteryConfig, run_weak_form_battery
|
|
57
|
+
|
|
58
|
+
outcome = run_weak_form_battery(returns, config=BatteryConfig(input_kind="returns"))
|
|
59
|
+
|
|
60
|
+
print(outcome.multiple_testing["battery_summary"])
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
One call. Structured output. Mean dependence, sign dependence, volatility dependence, and multiple testing correction included.
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install variance-test
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For development:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install -e .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick start
|
|
78
|
+
|
|
79
|
+
### Variance ratio test only
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import numpy as np
|
|
83
|
+
from variance_test import EMH
|
|
84
|
+
|
|
85
|
+
rng = np.random.default_rng(42)
|
|
86
|
+
returns = rng.normal(0.0, 0.01, size=2000)
|
|
87
|
+
|
|
88
|
+
emh = EMH()
|
|
89
|
+
z_score, p_value = emh.vrt(
|
|
90
|
+
X=returns,
|
|
91
|
+
q=4,
|
|
92
|
+
input_kind="returns",
|
|
93
|
+
heteroskedastic=True,
|
|
94
|
+
centered=True,
|
|
95
|
+
unbiased=True,
|
|
96
|
+
annualize=False,
|
|
97
|
+
alternative="two-sided",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
print("z_score:", z_score)
|
|
101
|
+
print("p_value:", p_value)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Full weak-form battery
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import numpy as np
|
|
108
|
+
from variance_test import BatteryConfig, run_weak_form_battery
|
|
109
|
+
|
|
110
|
+
rng = np.random.default_rng(42)
|
|
111
|
+
returns = rng.normal(0.0, 0.01, size=2000)
|
|
112
|
+
|
|
113
|
+
config = BatteryConfig(
|
|
114
|
+
input_kind="returns",
|
|
115
|
+
alpha=0.05,
|
|
116
|
+
q_list=(2, 4, 8),
|
|
117
|
+
ljung_box_lags=(5, 10, 20),
|
|
118
|
+
runs_test=True,
|
|
119
|
+
arch_lm_lags=5,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
outcome = run_weak_form_battery(returns, config=config)
|
|
123
|
+
|
|
124
|
+
# Holm-corrected VR family decision
|
|
125
|
+
print("VR family rejects:", outcome.tests["variance_ratio_holm"].reject_null)
|
|
126
|
+
|
|
127
|
+
# Full battery summary
|
|
128
|
+
print(outcome.multiple_testing["battery_summary"])
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Battery with rolling windows
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import numpy as np
|
|
135
|
+
from variance_test import BatteryConfig, run_weak_form_battery
|
|
136
|
+
|
|
137
|
+
rng = np.random.default_rng(123)
|
|
138
|
+
returns = rng.normal(0.0, 0.01, size=1500)
|
|
139
|
+
|
|
140
|
+
config = BatteryConfig(
|
|
141
|
+
input_kind="returns",
|
|
142
|
+
q_list=(2, 4),
|
|
143
|
+
ljung_box_lags=(5, 10),
|
|
144
|
+
runs_test=True,
|
|
145
|
+
arch_lm_lags=5,
|
|
146
|
+
rolling_window=120,
|
|
147
|
+
rolling_step=20,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
outcome = run_weak_form_battery(returns, config=config)
|
|
151
|
+
|
|
152
|
+
print("n_windows:", outcome.rolling["n_windows"])
|
|
153
|
+
print("first_vr_windows:", outcome.rolling["tests"]["variance_ratio_q2"][:2])
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Empirical application
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import numpy as np
|
|
160
|
+
from variance_test import EMH, BatteryConfig, run_weak_form_battery
|
|
161
|
+
|
|
162
|
+
# Replace with your own data source
|
|
163
|
+
prices = np.array([100.0, 101.5, 100.8, 102.2, 103.1, 101.9, ...])
|
|
164
|
+
log_prices = np.log(prices)
|
|
165
|
+
|
|
166
|
+
# Single test
|
|
167
|
+
emh = EMH()
|
|
168
|
+
z, p = emh.vrt(X=log_prices, q=5, input_kind="log_prices", heteroskedastic=True)
|
|
169
|
+
print(f"VR test: z={z:.4f}, p={p:.4f}")
|
|
170
|
+
|
|
171
|
+
# Full battery on returns
|
|
172
|
+
returns = np.diff(log_prices)
|
|
173
|
+
config = BatteryConfig(
|
|
174
|
+
input_kind="returns",
|
|
175
|
+
q_list=(2, 4, 8, 16),
|
|
176
|
+
ljung_box_lags=(5, 10, 20),
|
|
177
|
+
rolling_window=252,
|
|
178
|
+
rolling_step=21,
|
|
179
|
+
)
|
|
180
|
+
outcome = run_weak_form_battery(returns, config=config)
|
|
181
|
+
print(outcome.multiple_testing["battery_summary"])
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## What the battery includes
|
|
185
|
+
|
|
186
|
+
| Test | Diagnostic target | Rolling support |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| Variance ratio multi-q | Mean dependence at multiple horizons | Yes |
|
|
189
|
+
| Holm-Bonferroni correction | Family-wise error control for VR tests | No |
|
|
190
|
+
| Ljung-Box on returns | Serial dependence in returns | Yes |
|
|
191
|
+
| Ljung-Box on squared returns | Serial dependence in volatility | Yes |
|
|
192
|
+
| Runs test on signs | Non-random sign patterns | No |
|
|
193
|
+
| ARCH LM | Conditional heteroskedasticity | No |
|
|
194
|
+
|
|
195
|
+
The battery output classifies rejections into three categories: **mean dependence**, **sign dependence**, and **volatility dependence**. The summary field aggregates these into a single `weak_form_evidence_against_null` flag.
|
|
196
|
+
|
|
197
|
+
## Input formats
|
|
198
|
+
|
|
199
|
+
The package accepts two input modes:
|
|
200
|
+
|
|
201
|
+
* `input_kind="returns"` for one-period log-returns
|
|
202
|
+
* `input_kind="log_prices"` for cumulative log-price series
|
|
203
|
+
|
|
204
|
+
Both modes produce identical test statistics for equivalent data. This is tested and enforced in the test suite.
|
|
205
|
+
|
|
206
|
+
If you have raw prices:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
import numpy as np
|
|
210
|
+
|
|
211
|
+
prices = np.array([100.0, 101.5, 100.8, 102.2])
|
|
212
|
+
log_prices = np.log(prices)
|
|
213
|
+
returns = np.diff(log_prices)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Main interfaces
|
|
217
|
+
|
|
218
|
+
### `EMH().vrt(...)`
|
|
219
|
+
|
|
220
|
+
Low-level variance ratio test.
|
|
221
|
+
|
|
222
|
+
| Parameter | Description |
|
|
223
|
+
|---|---|
|
|
224
|
+
| `X` | 1-D input series |
|
|
225
|
+
| `q` | Aggregation horizon |
|
|
226
|
+
| `input_kind` | `"returns"` or `"log_prices"` |
|
|
227
|
+
| `heteroskedastic` | Use heteroskedastic asymptotic variance (Lo & MacKinlay Z2) |
|
|
228
|
+
| `centered` | Centered statistic |
|
|
229
|
+
| `unbiased` | Unbiased variance/autocovariance estimators |
|
|
230
|
+
| `annualize` | Scaling flag for intermediate volatility estimators |
|
|
231
|
+
| `alternative` | `"two-sided"`, `"greater"`, or `"less"` |
|
|
232
|
+
|
|
233
|
+
Returns `(z_score, p_value)`.
|
|
234
|
+
|
|
235
|
+
### `normalize_series(...)`
|
|
236
|
+
|
|
237
|
+
Shared normalization used internally. Exposed for users who want direct access to the canonical representation.
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from variance_test import normalize_series
|
|
241
|
+
|
|
242
|
+
ns = normalize_series([0.01, -0.02, 0.015], input_kind="returns")
|
|
243
|
+
# ns.log_prices, ns.returns, ns.squared_returns, ns.signs, ns.n_returns
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### `run_weak_form_battery(...)`
|
|
247
|
+
|
|
248
|
+
Full diagnostic pass. Returns a `BatteryOutcome` with:
|
|
249
|
+
|
|
250
|
+
* `tests` -- individual `TestOutcome` objects per test
|
|
251
|
+
* `multiple_testing` -- Holm summary and battery summary
|
|
252
|
+
* `rolling` -- rolling-window results (when configured)
|
|
253
|
+
* `warnings` -- non-computable test warnings
|
|
254
|
+
|
|
255
|
+
## How to read the results
|
|
256
|
+
|
|
257
|
+
**Variance ratio:** `VR(q) > 1` suggests positive serial dependence. `VR(q) < 1` suggests mean reversion. `VR(q) ≈ 1` is compatible with the random walk null.
|
|
258
|
+
|
|
259
|
+
**p-values:** Low p-value means the data is less compatible with the null hypothesis.
|
|
260
|
+
|
|
261
|
+
**Battery summary:** The battery provides statistical evidence against compatibility with weak-form efficiency under its test design. It does not constitute proof of market inefficiency. A rejection means the series shows detectable structure under the selected diagnostics.
|
|
262
|
+
|
|
263
|
+
## Implementation details
|
|
264
|
+
|
|
265
|
+
### Variance ratio estimator
|
|
266
|
+
|
|
267
|
+
The implementation uses **overlapping q-period increments** for the q-period variance estimator:
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
σ²_a(q) = (1 / ((n_q - 1) · q)) · Σ (X_{t} - X_{t-q} - q·μ̂)²
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
where the sum runs over all overlapping windows `t = q, q+1, ..., T`, and `μ̂ = (X_T - X_0) / T`.
|
|
274
|
+
|
|
275
|
+
The one-period variance estimator uses standard first differences:
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
σ²_b = (1 / (n₁ - 1)) · Σ (X_{t} - X_{t-1} - μ̂)²
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The centered ratio is `M_r(q) = (σ²_a / σ²_b) - 1`.
|
|
282
|
+
|
|
283
|
+
Under the **homoskedastic null** (Lo & MacKinlay Z1), the asymptotic variance is `2(2q-1)(q-1) / (3q)`.
|
|
284
|
+
|
|
285
|
+
Under the **heteroskedastic null** (Lo & MacKinlay Z2), the asymptotic variance uses the `δ̂(j)` estimator:
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
δ̂(j) = (nq · Σ (ΔX_{t} - μ̂)² · (ΔX_{t-j} - μ̂)²) / (Σ (ΔX_{t} - μ̂)²)²
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
with weights `(2(q-j)/q)²` for `j = 1, ..., q-1`.
|
|
292
|
+
|
|
293
|
+
Edge cases where `q < 2`, sample sizes are insufficient, or variance estimates are non-positive raise explicit `ValueError` exceptions instead of producing silent NaN or incorrect results.
|
|
294
|
+
|
|
295
|
+
### References
|
|
296
|
+
|
|
297
|
+
* Lo, A.W. and MacKinlay, A.C. "Stock Market Prices Do Not Follow Random Walks: Evidence from a Simple Specification Test." *Review of Financial Studies*, 1(1), 1988.
|
|
298
|
+
* Lo, A.W. and MacKinlay, A.C. "The Size and Power of the Variance Ratio Test in Finite Samples: A Monte Carlo Investigation." *Journal of Econometrics*, 40(2), 1989.
|
|
299
|
+
|
|
300
|
+
## Correctness and testing
|
|
301
|
+
|
|
302
|
+
The implementation was [audited for statistical correctness](AUDIT.md). Three issues were identified and resolved:
|
|
303
|
+
|
|
304
|
+
1. **σ²_a estimator ignoring q-aggregation** (severity: high) -- the original loop computed first differences regardless of `q`. Fixed with overlapping q-period differences using `X[t] - X[t-q]`.
|
|
305
|
+
2. **Division by zero in unbiased σ²_b adjustment** (severity: medium) -- when `len(X) == q`, the denominator `m` collapsed to zero. Fixed with explicit validation that degrees of freedom are positive before division.
|
|
306
|
+
3. **v̂ degenerate for q < 3** (severity: medium) -- for `q = 1` or `q = 2`, the summation range in the heteroskedastic estimator was empty, producing `v̂ = 0` and a subsequent division by zero. Fixed with an explicit guard requiring `q ≥ 2` and `v̂ > 0`.
|
|
307
|
+
|
|
308
|
+
The package is covered by an automated test suite that validates calibration, detection, edge cases, rolling-window behavior, and input-mode equivalence. Key coverage includes:
|
|
309
|
+
|
|
310
|
+
* IID Gaussian non-rejection at α=0.01 for the selected battery components covered by the test suite (`variance_ratio_holm`, `ljung_box_returns`, `runs_test_signs`, `arch_lm`)
|
|
311
|
+
* AR(1) detection of serial dependence with VR family and Ljung-Box rejection
|
|
312
|
+
* ARCH-like data detection of volatility clustering via Ljung-Box squared returns and ARCH LM
|
|
313
|
+
* Alternating sign rejection via runs test
|
|
314
|
+
* Exact equivalence between `returns` and `log_prices` input modes for all comparable test outcomes
|
|
315
|
+
* p-value/reject_null consistency enforcement in all TestOutcome instances
|
|
316
|
+
* Rolling window index monotonicity, count formulas, and non-computable window handling
|
|
317
|
+
* Edge cases: all-zero returns, insufficient samples, incompatible lag/horizon combinations
|
|
318
|
+
|
|
319
|
+
CI runs on Python 3.11 and 3.12 on every push and pull request.
|
|
320
|
+
|
|
321
|
+
## Simulation support
|
|
322
|
+
|
|
323
|
+
The package includes simulation utilities for synthetic experimentation.
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
from variance_test import SimulationConfig, run_simulation
|
|
327
|
+
|
|
328
|
+
config = SimulationConfig(
|
|
329
|
+
num_series=5,
|
|
330
|
+
horizon=200,
|
|
331
|
+
initial_price=100.0,
|
|
332
|
+
mu=0.05,
|
|
333
|
+
sigma=0.2,
|
|
334
|
+
aggregation_horizon=2,
|
|
335
|
+
heteroskedastic=False,
|
|
336
|
+
seed=42,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
results = run_simulation(config)
|
|
340
|
+
print(f"Mean z-score: {results.z_scores.mean():.4f}")
|
|
341
|
+
print(f"Mean p-value: {results.p_values.mean():.4f}")
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Included stochastic processes: Geometric Brownian Motion, Merton Jump Diffusion, Heston Stochastic Volatility, Vasicek, Cox-Ingersoll-Ross, Ornstein-Uhlenbeck.
|
|
345
|
+
|
|
346
|
+
CLI:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
python -m variance_test.simulation --series 10 --horizon 100 --aggregation 3 --seed 42 --no-plot
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Package architecture
|
|
353
|
+
|
|
354
|
+
```mermaid
|
|
355
|
+
flowchart TD
|
|
356
|
+
A[User input series] --> B{input_kind}
|
|
357
|
+
B -->|returns| C[normalize_series]
|
|
358
|
+
B -->|log_prices| C
|
|
359
|
+
|
|
360
|
+
C --> D[EMH.vrt]
|
|
361
|
+
C --> E[run_weak_form_battery]
|
|
362
|
+
|
|
363
|
+
E --> F[Variance ratio family]
|
|
364
|
+
E --> G[Holm summary]
|
|
365
|
+
E --> H[Ljung-Box returns]
|
|
366
|
+
E --> I[Ljung-Box squared returns]
|
|
367
|
+
E --> J[Runs test on signs]
|
|
368
|
+
E --> K[ARCH LM]
|
|
369
|
+
E --> L[Rolling results for supported tests]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Public API
|
|
373
|
+
|
|
374
|
+
```mermaid
|
|
375
|
+
flowchart LR
|
|
376
|
+
A[variance_test] --> B[EMH]
|
|
377
|
+
A --> C[normalize_series]
|
|
378
|
+
A --> D[run_weak_form_battery]
|
|
379
|
+
A --> E[SimulationConfig]
|
|
380
|
+
A --> F[run_simulation]
|
|
381
|
+
A --> G[PricePaths]
|
|
382
|
+
A --> H[VRTVisuals]
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Examples
|
|
386
|
+
|
|
387
|
+
### Offline examples (self-contained, no external dependencies)
|
|
388
|
+
|
|
389
|
+
* `examples/basic_battery.py` -- full-sample battery
|
|
390
|
+
* `examples/rolling_battery.py` -- rolling-window battery
|
|
391
|
+
* `examples/variance_ratio_only.py` -- standalone VRT
|
|
392
|
+
|
|
393
|
+
### External-data example (requires API credentials)
|
|
394
|
+
|
|
395
|
+
* `examples/empirical_application.py` -- empirical VRT on market data via [EOD Historical Data](https://eodhistoricaldata.com/). Requires `eod` package and `API_EOD` environment variable.
|
|
396
|
+
|
|
397
|
+
## Citation
|
|
398
|
+
|
|
399
|
+
### BibTeX
|
|
400
|
+
|
|
401
|
+
```bibtex
|
|
402
|
+
@software{parada_variance_test_2026,
|
|
403
|
+
title = {variance-test},
|
|
404
|
+
author = {Parada, Lautaro},
|
|
405
|
+
year = {2026},
|
|
406
|
+
url = {https://github.com/LautaroParada/variance-test},
|
|
407
|
+
note = {Python package for variance ratio testing and weak-form efficiency diagnostics}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Plain text
|
|
412
|
+
|
|
413
|
+
Parada, Lautaro. `variance-test`. Python package for variance ratio testing and weak-form efficiency diagnostics. GitHub repository: [https://github.com/LautaroParada/variance-test](https://github.com/LautaroParada/variance-test)
|
|
414
|
+
|
|
415
|
+
## License
|
|
416
|
+
|
|
417
|
+
MIT. See [LICENSE](LICENSE).
|