agent_panel: harden evidence and track outcomes

This commit is contained in:
root
2026-08-23 12:57:05 -04:00
parent a87ed7ba63
commit 83ffd290ca
7 changed files with 1313 additions and 159 deletions
+80 -1
View File
@@ -56,8 +56,12 @@ class TradeSetup:
risk_pips: float
reward_pips: float
pip_value: float
# Entry archetype ("GENERIC", "XAU_PB") — selects trail params.
# Entry archetype — selects trail params and explains the setup to
# advisory consumers. setup_pattern is populated only by XAU_CP.
strategy: str = "GENERIC"
setup_pattern: Optional[str] = None
# Strategy cost assumption, not a broker/data-provider quote.
round_trip_cost: Optional[float] = None
# Trailing exit params stamped from the PRODUCING config, so per-TF
# factory overrides (e.g. M15 arm 0.70, M5 dist 0.85) reach every
# consumer. None = legacy/unstamped setup — formatters fall back to
@@ -97,6 +101,9 @@ class SignalReport:
panel_confidence: float = 0.0
panel_rationale: str = ""
panel_takes: List[Dict] = field(default_factory=list)
panel_created_at: str = ""
panel_cache_status: str = ""
panel_payload_hash: str = ""
final_signal: SignalStrength = SignalStrength.NEUTRAL
final_score: float = 0.0
@@ -655,6 +662,7 @@ class SignalAggregator:
reward_pips=1.5 * sl_dist / pip_value,
pip_value=pip_value,
strategy="XAU_PB",
round_trip_cost=self.config.signals.round_trip_cost,
trail_arm_r=self.config.signals.pb_trail_arm_r,
trail_dist_r=self.config.signals.pb_trail_dist_r,
)
@@ -792,6 +800,8 @@ class SignalAggregator:
reward_pips=height / pip_value,
pip_value=pip_value,
strategy="XAU_CP",
setup_pattern=pat["pattern"],
round_trip_cost=self.config.signals.round_trip_cost,
trail_arm_r=self.config.signals.trail_arm_r,
trail_dist_r=self.config.signals.trail_dist_r,
)
@@ -807,8 +817,74 @@ class SignalAggregator:
f"height {height / atr:.1f} ATR")
target = report.bullish_reasons if is_buy else report.bearish_reasons
target.insert(0, marker)
self._clean_accepted_cp_warnings(report)
_reject("accepted")
@staticmethod
def _clean_accepted_cp_warnings(report: SignalReport) -> None:
"""Drop superseded composite-path warnings after XAU_CP accepts.
This is metadata-only. Pattern detection, gates, confidence,
exhaustion state, setup geometry, and signal selection are already
final when this runs.
"""
stale_prefixes = (
"SPREAD GATE:",
"EXHAUSTION BLOCK",
"EXHAUSTED TREND FILTER:",
"MTF OPPOSITION:",
"SELL FILTER: quality",
"SELL FILTER: volatility",
"SELL FILTER: regime",
"SELL FILTER: ",
"M5 FILTER: |score|",
"M5 FILTER: no MTF agreement",
"M5 FILTER: no confirmation TF",
"M5 FILTER: SELL quality",
"M5 FILTER: SELL blocked",
)
extension_prefixes = (
"TREND EXHAUSTION",
"NO PULLBACK",
"FAR FROM EMA200",
"Extended — RSI",
"Weak pullback",
)
filtered: List[str] = []
for warning in report.warnings:
if warning.startswith(stale_prefixes):
continue
if (warning.startswith("REGIME FILTER: '")
and warning.endswith("blocked for XAU")):
continue
if (warning.startswith("M5 FILTER: '")
and "volatility" in warning):
continue
filtered.append(warning)
extension_items = [
(index, warning)
for index, warning in enumerate(filtered)
if warning.startswith(extension_prefixes)
]
if not extension_items:
report.warnings[:] = filtered
return
first_index = extension_items[0][0]
priority = {prefix: rank for rank, prefix in enumerate(extension_prefixes)}
strongest = min(
(warning for _, warning in extension_items),
key=lambda warning: next(
rank for prefix, rank in priority.items()
if warning.startswith(prefix)),
)
kept = [
warning for warning in filtered
if not warning.startswith(extension_prefixes)
]
kept.insert(first_index, strongest)
report.warnings[:] = kept
# ── Public: bar-replayable entry point ─────────────────────────
def analyze_from_dataframes(
@@ -1195,6 +1271,8 @@ class SignalAggregator:
risk_pips=round(sl_distance / pip_value, 1),
reward_pips=round(tp_distance / pip_value, 1),
pip_value=pip_value,
strategy="XAU_ATR",
round_trip_cost=self.config.signals.round_trip_cost,
trail_arm_r=self.config.signals.trail_arm_r,
trail_dist_r=self.config.signals.trail_dist_r,
)
@@ -1609,6 +1687,7 @@ class SignalAggregator:
risk_pips=risk_pips,
reward_pips=reward_pips,
pip_value=pip_value,
round_trip_cost=self.config.signals.round_trip_cost,
trail_arm_r=self.config.signals.trail_arm_r,
trail_dist_r=self.config.signals.trail_dist_r,
)