Drop over-progressed setups via live R:R; refresh trades on fetch
Deploy / lint (push) Successful in 5s
Deploy / test (push) Successful in 35s
Deploy / deploy (push) Successful in 25s

Answers "why does a too-far-progressed setup still show": setups are only
recalculated by the scheduled R:R scan and manual fetch; at creation
entry == current price (0% progress), so over-progression is a
between-scans drift effect and must be judged at read time.

- /trades now attaches current_price (latest close per ticker).
- Qualification drops setups whose R:R recomputed from the current price
  falls below min_rr — i.e. price already ran toward target (reward
  consumed) or through the stop. Reuses the existing min_rr threshold
  instead of a separate progress %; far cleaner (a 3:1 is already ~1:1
  by 33% progress). Skipped for historical setups (no current_price).
- Fix: useFetchSymbolData now invalidates the trades queries, so a fetch/
  recompute actually refreshes confidence/setups in the UI (was the cause
  of the stale 100% confidence lingering after recompute).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 14:02:10 +02:00
parent a32f09c8ba
commit da83f027e1
7 changed files with 97 additions and 4 deletions
+18
View File
@@ -56,6 +56,24 @@ class TestSetupQualifies:
def test_no_targets_fails_when_probability_required(self):
assert setup_qualifies(_setup(targets=[]), FULL_GATE) is False
def test_over_progressed_setup_fails_on_live_rr(self):
# long target 120, stop 95; price already at 117 → live R:R ≈ 0.14
s = _setup(direction="long", target=120.0, stop_loss=95.0, current_price=117.0)
assert setup_qualifies(s, FULL_GATE) is False
def test_fresh_setup_passes_live_rr(self):
# price near entry (100): live R:R ≈ 3.2, well above min
s = _setup(direction="long", target=120.0, stop_loss=95.0, current_price=101.0)
assert setup_qualifies(s, FULL_GATE) is True
def test_past_stop_fails_live_rr(self):
s = _setup(direction="long", target=120.0, stop_loss=95.0, current_price=94.0)
assert setup_qualifies(s, FULL_GATE) is False
def test_no_current_price_skips_live_check(self):
# Historical setups have no current_price → live check skipped
assert setup_qualifies(_setup(), FULL_GATE) is True
def test_conviction_filters_can_be_disabled(self):
relaxed = {
"min_rr": 2.0,