fix: remove a one-ULP dependency from a correlation threshold test
test_threshold_is_applied_before_rounding_under_ewma built a correlation of exactly 0.70 and asserted that the >= 0.70 breach check fires on it. The computed value came out as 0.7000000000000001 -- above the threshold by a single ULP, 1.1e-16. The weighted covariance behind it is a matrix product, so its last bit depends on the BLAS build and the CPU's vectorisation rather than on anything the test controls. That is why the suite passed on the 3.10 and 3.13 runners and failed on the 3.12 one in the same CI run, and why it passed on all four interpreters locally: the runners resolve different numpy builds. Both cases now sit 4e-5 either side of the threshold while still rounding to the same reported 0.7000. That is a stricter test of the property the name claims -- a value that rounds to 0.7000 must breach or not breach on its raw value, not its rounded one -- and the margin is ~11 orders of magnitude above the float noise. Swept the other 28 exact-boundary tests in the library: all are pure-Python arithmetic on exactly-representable values, so they are bit-identical on every machine. This was the only numpy-backed one. Verified on CPython 3.10.20 (numpy 2.2.6), 3.11.4, 3.12.13 and 3.13.14 (numpy 2.5.2): every CI step passes on every version.
This commit is contained in:
@@ -70,6 +70,13 @@ anything parsing either needs updating.
|
||||
up to 3.11 and exactly 1.0 from 3.12 on, and both tests silently lost the divergence they
|
||||
existed to detect. They now accumulate in an explicit loop, which stays naive on every
|
||||
version and matches how a backtest actually accumulates a P&L series.
|
||||
- `cross-strategy-correlation-monitoring`: a threshold test built a correlation of exactly
|
||||
0.70 and asserted that a `>= 0.70` check fires on it. The weighted covariance is a matrix
|
||||
product, so its last bit depends on the BLAS build and the CPU's vectorisation, and the
|
||||
fixture landed one ULP either side of the threshold depending on the machine. The two cases
|
||||
now sit 4e-5 apart on opposite sides of the threshold while still rounding to the same
|
||||
reported 0.7000, which tests the pre-rounding comparison more strictly and no longer
|
||||
depends on a single floating-point bit.
|
||||
|
||||
### Changed — library shape
|
||||
- Merged duplicates: `cross-strategy-correlation-monitoring` into
|
||||
|
||||
+13
-1
@@ -356,19 +356,31 @@ class TestEwmaWeighting(unittest.TestCase):
|
||||
self.assertEqual(equal_report.effective_observations, 5000.0)
|
||||
|
||||
def test_threshold_is_applied_before_rounding_under_ewma(self):
|
||||
# Both correlations below round to 0.7000 at the reported 4 decimal places,
|
||||
# but they sit on opposite sides of the 0.70 threshold. Comparing the raw
|
||||
# value must breach on one and not the other; comparing the rounded value
|
||||
# would breach on both.
|
||||
#
|
||||
# Deliberately NOT constructed at exactly 0.70. The weighted covariance is a
|
||||
# matrix product, so its last bit depends on the BLAS build and the CPU's
|
||||
# vectorisation: an exactly-0.70 fixture lands one ULP either side of the
|
||||
# threshold depending on the machine, which made this test flip between
|
||||
# otherwise identical CI runners.
|
||||
monitor = CrossStrategyCorrelationMonitor(
|
||||
ewma_span=30, high_correlation_threshold=0.70, min_observations=30
|
||||
)
|
||||
at = monitor.analyze_strategy_correlations(
|
||||
["A", "B"], ewma_paired_matrix(0.70, n_obs=150, span=30)
|
||||
["A", "B"], ewma_paired_matrix(0.70004, n_obs=150, span=30)
|
||||
)
|
||||
self.assertEqual(len(at.high_correlation_breaches), 1)
|
||||
self.assertEqual(at.high_correlation_breaches[0].correlation, 0.7)
|
||||
|
||||
# Just under: the pre-rounding comparison must not promote 0.69996 to 0.7000.
|
||||
near = monitor.analyze_strategy_correlations(
|
||||
["A", "B"], ewma_paired_matrix(0.69996, n_obs=150, span=30)
|
||||
)
|
||||
self.assertEqual(near.high_correlation_breaches, [])
|
||||
self.assertEqual(round(float(near.correlation_matrix[0, 1]), 4), 0.7)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
|
||||
Reference in New Issue
Block a user