Isolate legacy range-grid features
This commit is contained in:
@@ -759,22 +759,76 @@ def test_window_setups_too_short_returns_empty():
|
||||
|
||||
|
||||
def test_sr_research_variant_is_explicit_and_validated(monkeypatch):
|
||||
monkeypatch.setenv("BACKTEST_SR_VARIANT", "production_control")
|
||||
assert bt._sr_research_variant() == "production_control"
|
||||
for variant in (
|
||||
"production_control",
|
||||
"legacy_range_grid_touch",
|
||||
"legacy_range_grid_neutral",
|
||||
):
|
||||
monkeypatch.setenv("BACKTEST_SR_VARIANT", variant)
|
||||
assert bt._sr_research_variant() == variant
|
||||
monkeypatch.setenv("BACKTEST_SR_VARIANT", "not-a-variant")
|
||||
with pytest.raises(ValueError, match="Unknown BACKTEST_SR_VARIANT"):
|
||||
bt._sr_research_variant()
|
||||
|
||||
|
||||
def test_geometry_neutral_strength_is_enforced_after_zone_clustering():
|
||||
@pytest.mark.parametrize(
|
||||
("variant", "neutral_strength"),
|
||||
[
|
||||
("legacy_range_grid_touch", False),
|
||||
("legacy_range_grid_neutral", True),
|
||||
],
|
||||
)
|
||||
def test_window_setups_routes_explicit_range_grid(
|
||||
monkeypatch,
|
||||
variant,
|
||||
neutral_strength,
|
||||
):
|
||||
captured = {}
|
||||
|
||||
def fake_detector(*args, **kwargs):
|
||||
captured.update(kwargs)
|
||||
return []
|
||||
|
||||
monkeypatch.setenv("BACKTEST_SR_VARIANT", variant)
|
||||
monkeypatch.setattr(bt, "detect_sr_levels_legacy", fake_detector)
|
||||
records = [
|
||||
SimpleNamespace(
|
||||
date=date(2024, 1, 1) + timedelta(days=i),
|
||||
open=100.0,
|
||||
high=101.0,
|
||||
low=99.0,
|
||||
close=100.0,
|
||||
volume=1_000_000,
|
||||
)
|
||||
for i in range(bt.MIN_LOOKBACK)
|
||||
]
|
||||
assert bt._window_setups(records, {}, {}) == []
|
||||
assert captured == {
|
||||
"include_pivots": False,
|
||||
"neutral_strength": neutral_strength,
|
||||
"explicit_range_grid": True,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"variant",
|
||||
["legacy_geometry_neutral", "legacy_range_grid_neutral"],
|
||||
)
|
||||
def test_neutral_strength_is_enforced_after_zone_clustering(variant):
|
||||
levels = [
|
||||
SimpleNamespace(strength=100),
|
||||
SimpleNamespace(strength=75),
|
||||
]
|
||||
result = bt._apply_zone_strength_variant(levels, "legacy_geometry_neutral")
|
||||
result = bt._apply_zone_strength_variant(levels, variant)
|
||||
assert [level.strength for level in result] == [50, 50]
|
||||
|
||||
|
||||
def test_touch_strength_survives_post_cluster_research_hook():
|
||||
levels = [SimpleNamespace(strength=82), SimpleNamespace(strength=37)]
|
||||
result = bt._apply_zone_strength_variant(levels, "legacy_range_grid_touch")
|
||||
assert [level.strength for level in result] == [82, 37]
|
||||
|
||||
|
||||
def test_backtest_entry_bounds_validate_dates(monkeypatch):
|
||||
monkeypatch.setenv("BACKTEST_ENTRY_START", "2024-07-01")
|
||||
monkeypatch.setenv("BACKTEST_ENTRY_END", "2024-12-31")
|
||||
|
||||
@@ -6,6 +6,8 @@ from app.services.sr_service import (
|
||||
MAX_LEVELS,
|
||||
_bar_respect_weight,
|
||||
_cap_levels,
|
||||
_legacy_range_grid_nodes,
|
||||
_legacy_volume_profile_nodes,
|
||||
_merge_levels,
|
||||
_round_number_candidates,
|
||||
_strength_from_respects,
|
||||
@@ -267,3 +269,65 @@ class TestDetectSrLevels:
|
||||
assert pivots and traffic
|
||||
assert all(level["sources"] == ["pivot_point"] for level in pivots)
|
||||
assert all(level["sources"] == ["volume_profile"] for level in traffic)
|
||||
|
||||
def test_legacy_profile_union_matches_explicit_range_grid(self):
|
||||
highs, lows, closes, volumes = _make_series(n=500)
|
||||
deployed = _legacy_volume_profile_nodes(highs, lows, closes, volumes)
|
||||
explicit = _legacy_range_grid_nodes(highs, lows, closes)
|
||||
assert sorted(deployed) == explicit
|
||||
assert len(explicit) == 20
|
||||
|
||||
def test_explicit_range_grid_is_volume_independent(self):
|
||||
highs, lows, closes, volumes = _make_series(n=500)
|
||||
shifted_volumes = [volume * (i + 1) for i, volume in enumerate(volumes)]
|
||||
baseline = detect_sr_levels_legacy(
|
||||
highs,
|
||||
lows,
|
||||
closes,
|
||||
volumes,
|
||||
include_pivots=False,
|
||||
explicit_range_grid=True,
|
||||
)
|
||||
shifted = detect_sr_levels_legacy(
|
||||
highs,
|
||||
lows,
|
||||
closes,
|
||||
shifted_volumes,
|
||||
include_pivots=False,
|
||||
explicit_range_grid=True,
|
||||
)
|
||||
assert shifted == baseline
|
||||
|
||||
def test_explicit_range_grid_neutral_changes_only_strength(self):
|
||||
highs, lows, closes, volumes = _make_series(n=500)
|
||||
touch = detect_sr_levels_legacy(
|
||||
highs,
|
||||
lows,
|
||||
closes,
|
||||
volumes,
|
||||
include_pivots=False,
|
||||
explicit_range_grid=True,
|
||||
)
|
||||
neutral = detect_sr_levels_legacy(
|
||||
highs,
|
||||
lows,
|
||||
closes,
|
||||
volumes,
|
||||
include_pivots=False,
|
||||
neutral_strength=True,
|
||||
explicit_range_grid=True,
|
||||
)
|
||||
touch_by_price = {level["price_level"]: level for level in touch}
|
||||
neutral_by_price = {level["price_level"]: level for level in neutral}
|
||||
assert neutral_by_price.keys() == touch_by_price.keys()
|
||||
for price, neutral_level in neutral_by_price.items():
|
||||
assert neutral_level["strength"] == 50
|
||||
assert {
|
||||
key: value
|
||||
for key, value in neutral_level.items()
|
||||
if key != "strength"
|
||||
} == {
|
||||
key: value
|
||||
for key, value in touch_by_price[price].items()
|
||||
if key != "strength"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user