agent_panel: harden evidence and track outcomes
This commit is contained in:
+80
-1
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user