Add multi-factor conviction gate to activation
Make "qualified" mean an edge candidate, not just R:R + confidence. The gate now also requires (all admin-configurable, defaults on): - high conviction: recommended_action LONG_HIGH / SHORT_HIGH only - clean read: risk_level Low (no contradicting signals) - probable primary target: best target probability >= min (default 60) - Shared predicate: app/services/qualification.py + frontend/src/lib/qualification.ts (mirrored) - Activation config extended (min_target_probability, require_high_conviction, exclude_conflicts) with bool-aware get/update + validation - /trades/performance switched to ?qualified_only=true, applying the full gate server-side; confidence breakdown stays unfiltered - Dashboard "Qualified", Signals "Qualified only" toggle, and Track Record all use the one gate; Admin gains the new controls Sentiment provider runtime config (prior change) included. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
"""Shared definition of a 'qualified' (actionable) trade setup.
|
||||
|
||||
A single predicate, driven by the admin activation config, used by the
|
||||
performance stats (server) and mirrored on the frontend. Beyond raw R:R and
|
||||
confidence, an actionable setup must show genuine conviction: a high-conviction
|
||||
recommended action, a clean (conflict-free) read, and a probable primary target.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
HIGH_CONVICTION_ACTIONS = {"LONG_HIGH", "SHORT_HIGH"}
|
||||
|
||||
|
||||
def best_target_probability(setup: Any) -> float:
|
||||
"""Highest probability among a setup's targets, 0 if none."""
|
||||
targets = getattr(setup, "targets", None) or []
|
||||
probs = [float(t.get("probability", 0.0)) for t in targets if isinstance(t, dict)]
|
||||
return max(probs, default=0.0)
|
||||
|
||||
|
||||
def setup_qualifies(setup: Any, config: dict) -> bool:
|
||||
"""Whether a setup clears the activation gate.
|
||||
|
||||
``setup`` is duck-typed: any object exposing rr_ratio, confidence_score,
|
||||
recommended_action, risk_level and a ``targets`` list of dicts.
|
||||
"""
|
||||
if setup.rr_ratio < config["min_rr"]:
|
||||
return False
|
||||
if (setup.confidence_score or 0.0) < config["min_confidence"]:
|
||||
return False
|
||||
if config.get("require_high_conviction"):
|
||||
if (setup.recommended_action or "") not in HIGH_CONVICTION_ACTIONS:
|
||||
return False
|
||||
if config.get("exclude_conflicts"):
|
||||
if (setup.risk_level or "") != "Low":
|
||||
return False
|
||||
min_tp = float(config.get("min_target_probability", 0.0))
|
||||
if min_tp > 0 and best_target_probability(setup) < min_tp:
|
||||
return False
|
||||
return True
|
||||
Reference in New Issue
Block a user