# Feature: dual-pipeline-signal-engine, Property: Fibonacci retracement bounds """Property-based tests for the Fibonacci retracement formula. Feature: dual-pipeline-signal-engine Tests the Fibonacci retracement bounds property from the design specification: for all retracement ratios r in [0, 1] and all swing high SH > swing low SL > 0, the retracement level L(r) = SH - r * (SH - SL) must lie within [SL, SH]. Requirements: 2.1, 17.1 """ from __future__ import annotations from hypothesis import given, settings from hypothesis import strategies as st # --------------------------------------------------------------------------- # Property: Fibonacci retracement bounds # Validates: Requirements 2.1, 17.1 # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # Hypothesis strategies # --------------------------------------------------------------------------- # Retracement ratio in [0, 1] _ratio = st.floats(min_value=0.0, max_value=1.0, allow_nan=False, allow_infinity=False) # Positive floats for swing high / swing low _positive_float = st.floats( min_value=1e-8, max_value=1e8, allow_nan=False, allow_infinity=False, ) @st.composite def _swing_pair(draw: st.DrawFn) -> tuple[float, float]: """Generate (SH, SL) where SH > SL > 0.""" a = draw(_positive_float) b = draw(_positive_float) sh = max(a, b) sl = min(a, b) # Ensure strict inequality SH > SL if sh == sl: sh = sl + 1e-8 return sh, sl # --------------------------------------------------------------------------- # Property test # --------------------------------------------------------------------------- @given(r=_ratio, swing=_swing_pair()) @settings(max_examples=100) def test_fibonacci_retracement_within_bounds(r: float, swing: tuple[float, float]) -> None: """**Validates: Requirements 2.1, 17.1** For all r in [0, 1] and all SH > SL > 0, the Fibonacci retracement level L(r) = SH - r * (SH - SL) SHALL be in [SL, SH]. This is a pure mathematical property — no evaluator class needed. """ sh, sl = swing # Compute the retracement level level = sh - r * (sh - sl) assert sl <= level <= sh, ( f"Fibonacci level {level} out of bounds [SL={sl}, SH={sh}] " f"for r={r}.\n" f" L(r) = {sh} - {r} * ({sh} - {sl}) = {level}" )