Quant review 2026-09-26: alert cooldown, plain-language alerts, M15 grade-A SELL block, 1R printed targets, panel/breach fixes
Live signals.db review (2026-09-04 → 09-25, 100 unique setups replayed on the scans' stored candles): the stop-hunt claim is refuted (71% of stop-outs ran ≥ 1R past the stop, the same as the books' 70–72%); −25.1R of the −37.8R raw live book were consecutive-bar re-entries the backtester's 5-bar cooldown never takes; the cooldown view sits at the 3rd–5th percentile of the books' three-week windows. Delivery (book-neutral): - telegram_bot: 5-bar alert cooldown per timeframe (_ALERT_COOLDOWN_BARS = backtest.cooldown_bars); setup block prints the trail first as the tested exit, TP1/TP2 as guides with their R, "Planned TP1 RR", and one validated-book line per setup class (agent_panel_base_rates.json); the informational 100-pip TP line is removed (owner request). - AI block rewritten for a new trader: "AI check: the odds look better than / worse than / about usual", the chance "in 100" against the usual odds, one reason for and one against, no verdict word or confidence figure; rendered whenever the verdict carries a probability. agent_panel: persona prompts ban trading jargon (PANEL_PROMPT_VERSION v2.1-2026-09-26); the macro-source verdict now carries its persona's p_win (every live v2 row had panel_probability NULL). Dashboard and guides mirror the wording. - telegram_bot: level-breach rescans skip the settlement-pause window (the 20:45 M15 bar was re-logged at 22:01/22:06/22:11 every evening). Signal (pre-registered rule-1 campaign, CUDA twin paired with gpu_backtest.py): - M15 grade-A SELLs blocked (sell_min_quality ["A+","B"], M15 override 6): W2 813/+154.15R PF 1.53 vs 931/+146.14R PF 1.43, OOS +68.5 vs +60.67, W3 max DD 20.9 vs 19.3R. PASSED a–f. - Printed target 1 floored at 1R in every generator (signals.tp_print_floor_rr), applied AFTER the min-RR and spread gates so no trade changes; mirrored in cuda_signal_kernels.py K2. Label-only re-pin of all four timeframes (only tp1/rr_planned columns move). A floor applied before the gate cost −24.6R and was rejected. - FAILED: M15 min_rr_ratio 1.0 (trade-identical, −2.0R). Owner's call: M5 tp_floor_rr 1.0 (+48.9R W2, max DD 10.1 → 15.9R), not shipped. New pins: M5 W2 e599c8a8…, M15 W2 5b65ecf6…, M15 OOS 09b8a8e7…, H1 W3 a44fd19b…, H4 W3 f3587bae…; twin and reference MD5s equal on every window. Base-rate table rebuilt from the new pins. Suite 558 passed. Evidence: backtest/research/rr_and_sell_campaign_2026-09-26.md (plus the 2026-09-18 loss-anatomy and wrong-direction reports it builds on). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+20
-5
@@ -126,7 +126,7 @@ VERDICT_SOURCES = ("mean", "macro", "chair")
|
||||
#: Logged with every verdict and folded into the payload hash. Bump on
|
||||
#: ANY prompt or context-schema change so the scorecard can split eras
|
||||
#: (analyze_signal_log splits by panel_prompt_version).
|
||||
PANEL_PROMPT_VERSION = "v2-2026-09-17"
|
||||
PANEL_PROMPT_VERSION = "v2.1-2026-09-26" # v2.1: beginner wording rules in _TAKE_CONTRACT
|
||||
|
||||
#: Symmetric probability bands (percent). A persona's stance and the
|
||||
#: mean verdict are DERIVED from p_win with the same thresholds, so
|
||||
@@ -216,7 +216,14 @@ Write everything in plain everyday English for someone who has never
|
||||
traded: short simple sentences, no trading jargon, no acronyms, no
|
||||
abbreviations. Say "profit versus loss", not "RR"; "the 4-hour chart",
|
||||
not "H4"; describe what an indicator MEANS ("the price has climbed
|
||||
unusually fast"), never its name or number.
|
||||
unusually fast"), never its name or number. Never use these words:
|
||||
"priced in", "bullish", "bearish", "hawkish", "dovish", "macro",
|
||||
"sentiment", "momentum", "volatility", "resistance", "support level",
|
||||
"breakout", "pullback", "basis points", "yields". Say instead: "the
|
||||
price already moved on that news", "news that is good for gold",
|
||||
"news that is bad for gold", "higher interest rates", "the price
|
||||
fell fast", "the price bounced". Each sentence must make sense to a
|
||||
reader who does not know what gold or interest rates usually do.
|
||||
Reply with ONLY JSON:
|
||||
{"p_win": <0-100>, "reason_for": "<max 12 words>",
|
||||
"reason_against": "<max 12 words>", "note": "<max 15 words>"}
|
||||
@@ -250,8 +257,8 @@ gold this way"; the payload's gold_influence already did that scoring.
|
||||
Example: brief direction SELL, price already fell 5 ATR in 4 hours, every
|
||||
bearish headline published before move_started_at, base_rate.win_rate 58
|
||||
-> {"p_win": 55, "reason_for": "Recent news still leans against gold.",
|
||||
"reason_against": "That news is older than the drop, so it is priced in.",
|
||||
"note": "The bad news is already in the price; expect the usual odds."}
|
||||
"reason_against": "That news came before the drop; the price already moved on it.",
|
||||
"note": "The price already moved on the bad news; expect the usual odds."}
|
||||
Example: brief direction BUY, a high-impact release came out 20 minutes
|
||||
ago with a surprise the code marked bullish for gold, base_rate.win_rate 60
|
||||
-> {"p_win": 68, "reason_for": "A fresh surprise in the data favours gold.",
|
||||
@@ -1244,11 +1251,19 @@ def run_panel(report: "SignalReport",
|
||||
if verdict_source == "macro":
|
||||
macro = next((t for t in takes if t.persona == "macro"), None)
|
||||
if macro is not None:
|
||||
# The macro persona's own p_win is the verdict's probability
|
||||
# (2026-09-26 signals.db review: every v2 row logged under
|
||||
# verdict_source="macro" had panel_probability NULL — the
|
||||
# verdict carried none, _write_fields wrote 0.0 and the logger
|
||||
# dropped the falsy value — so the 100/300-outcome evaluation
|
||||
# would have had no live probabilities to score).
|
||||
return _finish(PanelVerdict(
|
||||
verdict=_STANCE_TO_VERDICT[macro.stance],
|
||||
confidence=macro.confidence, rationale=macro.note[:240],
|
||||
takes=takes, created_ts=time.time(),
|
||||
payload_hash=payload_hash, source="macro"))
|
||||
payload_hash=payload_hash, source="macro",
|
||||
probability=(round(float(macro.p_win), 1)
|
||||
if macro.p_win is not None else None)))
|
||||
# Macro take missing (timed out / invalid) — fall back to the chair.
|
||||
# Quorum guards the CHAIR only: it weighs several voices, so one lone
|
||||
# take is not worth a synthesizer request. The macro path above needs
|
||||
|
||||
Reference in New Issue
Block a user