Conviction campaign 2026-09-27 (FAILED, research knob kept) + plain-words alert wording

Owner question: can score and confidence be combined into one number that is
easier to understand and for the system to decide on?

Research (pre-registered, nothing ships to the signal path):
- signals.grading_mode: "pair" (default, the shipped two-floor rule, byte-
  identical: all five reference MD5s reproduce on both scripts), "min"
  (min(|score|, 0.6*conf)), "product" (|score|*conf/100); thresholds fixed from
  the control's corner points, no tuning. Helpers _final_signal_and_grade /
  _transitioning_boost / conviction / CONVICTION_THRESHOLDS in signal_aggregator;
  mirrored in K2 (GRADING_MODE_CODES, PF_conv_* packed from the live module);
  twin refuses other values; M15 OOS MD5 equal on both scripts for both modes.
- Verdict: FAILED on M5 and M15. K-MIN moves 43-54 trades for -1.2R / -2.9R
  (clauses a,b,e / a,b,d); K-PROD -29R on M15 (PF 1.29, W3 DD 28.9R), neutral
  on M5. H1/H4 product +11.9R / +17.0R on W3 from extra low-score trades
  (H1 PF 1.98 -> 1.75, DD doubles): hypothesis only.
- Code review (high) before the runs: 6 findings fixed, 1 recorded
  (engine_config_fingerprint omits the switch under "pair", so live rows keep
  their fingerprint).

Delivery (books untouched): alerts lead with the grade and print the two raw
numbers in words (main.plain_words: "Direction: strong buy · Reliability: good
· timeframes agree", cut-offs = the grade table's own) on Telegram, /status,
the CLI and the dashboard card (plain_words in the snapshot); "MTF" label
replaced by "Other timeframes"; guides updated. Suite 566 passed.

Evidence: backtest/research/conviction_campaign_2026-09-27.md
This commit is contained in:
Harwinder Sekhon
2026-09-27 14:54:36 -04:00
parent 4e0a083955
commit d81cdf845b
13 changed files with 808 additions and 59 deletions
+40
View File
@@ -105,6 +105,44 @@ def _fmt_price(price: float) -> str:
return f"{price:.2f}"
# ── Plain words for the two raw numbers (owner request 2026-09-27) ────
# The words sit on the grade table's own floors (CLAUDE.md §2: |score|
# 40 / 33 / 28 / 25 / 15, confidence 65 / 55 / 50 / 45), so they can never
# disagree with the printed grade. Display only: no gate reads them, and the
# numbers stay in --json, --detail and the dashboard meters.
def direction_words(score: float) -> str:
strength_of = abs(score)
side = "buy" if score > 0 else "sell" if score < 0 else ""
if strength_of >= 40:
strength = "very strong"
elif strength_of >= 33:
strength = "strong"
elif strength_of >= 25:
strength = "clear"
elif strength_of >= 15:
strength = "weak"
else:
return "no clear direction"
return f"{strength} {side}".strip()
def reliability_words(confidence: float) -> str:
if confidence >= 65:
return "high"
if confidence >= 55:
return "good"
if confidence >= 45:
return "fair"
return "low"
def plain_words(report: SignalReport) -> str:
"""One line a new trader can read instead of "Score +38.2 · Conf 62%"."""
agree = "timeframes agree" if report.mtf_agreement else "timeframes disagree"
return (f"Direction: {direction_words(report.final_score)} · "
f"Reliability: {reliability_words(report.final_confidence)} · {agree}")
def print_signal_report(report: SignalReport, detail: bool = False):
sc = signal_color(report.final_signal)
qc = quality_color(report.signal_quality)
@@ -117,6 +155,7 @@ def print_signal_report(report: SignalReport, detail: bool = False):
f"{qc}{report.signal_quality}{Colors.RESET} · "
f"{sc}{report.final_score:+.1f}{Colors.RESET} · "
f"{report.final_confidence:.0f}% · {mtf_tag}")
print(f" {plain_words(report)}")
print(f" {Colors.GRAY}{report.action_recommendation}{Colors.RESET}")
# ── 2. TRADE SETUP (if signal is actionable) ───────────────────
@@ -242,6 +281,7 @@ def report_to_dict(report: SignalReport) -> dict:
"score": round(report.final_score, 2),
"confidence": round(report.final_confidence, 2),
"quality": report.signal_quality,
"plain_words": plain_words(report),
"action": report.action_recommendation,
"market_regime": report.market_regime,
"volatility_regime": report.volatility_regime,