block_permutation_test¶
Defined in fynance.research
- block_permutation_test(strategy_returns, *, n_perm=1000, block=21, method='stationary', seed=0)[source]
Dependence-preserving analogue of
permutation_test.guards.permutation_testreruns aStrategyon i.i.d.-shuffled price paths – an appropriate null when the question is “does this strategy exploit any real structure”, but it also destroys genuine autocorrelation, which would bias the null toward rejecting a real, dependence-driven edge as noise.block_permutation_testinstead takes an already-computed strategy return series (no strategy rerun) and tests whether its mean is significantly positive against a null that preserves autocorrelation: the observed series is demeaned, then block-bootstrap resampled viaresample_paths(so within-block dependence survives), giving the distribution of the mean statistic expected under no drift. The p-value uses the same smoothed convention aspermutation_test:(#{null >= observed} + 1) / (n_perm + 1).- Parameters:
- strategy_returnsarray-like
Realized return series of the strategy under test, shape
(T,).- n_permint
Number of block-bootstrap replicates forming the null distribution.
- blockint
Block length (
'circular') or mean block length ('stationary'), forwarded toresample_paths.- method{‘circular’, ‘stationary’}
Resampling scheme, forwarded to
resample_paths.- seedint
Master seed, forwarded to
resample_paths(reproducible for a fixed seed).
- Returns:
- float
Smoothed p-value for the one-sided test “the observed mean return is larger than chance would produce, given the series’ own autocorrelation structure”. Low values indicate a genuine (not merely autocorrelation-driven) positive edge.
Examples
>>> import numpy as np >>> from fynance.research import block_permutation_test >>> rng = np.random.default_rng(0) >>> noise = rng.standard_normal(300) * 0.01 >>> p = block_permutation_test(noise, n_perm=200, block=10, seed=1) >>> 0.0 < p <= 1.0 True