chart/tests/test_manual_lines.py
Chris Amow 8c2ef80966 Remove the 4h timeframe
It was never in the enabled timeframes, so it held zero bars and produced no
levels, but it still carried weight 8 in the scoring table and forced
bucket_start to special-case a wall-clock ET anchor whose entire purpose was
surviving DST transitions. That was the most intricate logic in session.py,
maintained for a timeframe nobody used.

Daily is now the only session-anchored bucket, which is a much easier rule to
state and to keep correct. The DST parametrised tests go with it; the Sunday
open and daily boundary cases remain.

Manual-line tests move to 1h, so the weight assertions drop from 8 to 4.

The plan document keeps its 4h examples — rewriting a dozen illustrative
sentences would churn more than it clarifies — but the timeframe-roles section
now records the removal so nothing reads as a spec to build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 00:43:47 -05:00

42 lines
1.4 KiB
Python

from app.analysis.levels import Side
from app.analysis.manual_lines import ManualLine, ManualLineStore
from app.analysis.confluence import cluster_levels
from app.analysis.levels import Level, LevelKind
from app.bars.models import Timeframe
def sample_line():
return ManualLine("ml_test", Timeframe.H1, Side.RESISTANCE, 100, 5000, -0.01, 200, 300, number=1)
def test_json_persistence_round_trip(tmp_path):
path = tmp_path / "manual_lines.json"
store = ManualLineStore(path)
store.add(sample_line())
loaded = ManualLineStore(path)
assert list(loaded.lines.values()) == [sample_line()]
loaded.update("ml_test", {"note": "major swing"})
assert ManualLineStore(path).lines["ml_test"].note == "major swing"
loaded.delete("ml_test")
assert ManualLineStore(path).lines == {}
def test_hourly_line_uses_absolute_time_on_one_minute_chart():
level = sample_line().to_level()
instant = 160
assert level.tf is Timeframe.H1
assert level.price_at(instant) == 4999.4
assert level.weight == 4
def test_manual_line_raises_existing_ma_cluster_score():
ma = Level(
"ma", LevelKind.MA, Timeframe.D1, Side.RESISTANCE, 12, 1, "1d SMA20",
100, 5000, 0, None, 0, 100, 100, False, False, 20,
)
before = cluster_levels([ma], 160, 4998, 2)[0]
after = cluster_levels([ma, sample_line().to_level()], 160, 4998, 2)[0]
assert before.score == 12
assert after.score == 16