Fix scoring math; add 10-min auto-scan A-grade alerts with news block

- engine: composite-score denominator now confidence-weighted, so the
  output actually spans -100..+100 (the prior formula put confidence
  in the numerator only, capping the realistic score around ±25-30
  and making STRONG_BUY ≥40 essentially unreachable).
- engine: ATR percentile uses iloc[-50:-1] to exclude the current bar
  from its own comparison (off-by-one in volatility regime).
- signal_aggregator: always blend primary score with MTF average. The
  prior code only blended on agreement, leaving the primary unblended
  on disagreement — backwards. Disagreement is exactly when the score
  should be pulled toward consensus.
- telegram_bot: JobQueue auto-scan every 10 min that pushes A/A+ to
  ALERT_CHAT_ID with a prominent News & Events block (sentiment +
  headline summary + event-risk + alignment hint). Per-bar dedup so
  persistent setups alert once per new candle, not every 10 min.
  Suppresses alerts when event_risk = "danger".
- telegram_bot: /myid returns chat ID for ALERT_CHAT_ID setup. Auto-scan
  silently disabled when ALERT_CHAT_ID is unset.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Harwinder
2026-05-06 12:50:30 -04:00
parent 3a17471c0e
commit 402d49e094
3 changed files with 235 additions and 17 deletions
+10 -9
View File
@@ -261,20 +261,21 @@ class SignalAggregator:
confidence = report.primary_confidence
# ── MTF adjustment ─────────────────────────────────────────
# Always blend primary with MTF average so the score is pulled toward
# consensus on disagreement (and barely moves on agreement, since the
# TFs already point the same way).
all_scores = list(report.mtf_scores.values())
if all_scores:
mtf_avg = sum(all_scores) / len(all_scores)
score = score * 0.6 + mtf_avg * 0.4
if report.mtf_agreement:
# All timeframes agree — boost confidence and blend scores
confidence = min(confidence + 15, 95)
all_scores = list(report.mtf_scores.values())
if all_scores:
mtf_avg = sum(all_scores) / len(all_scores)
score = score * 0.6 + mtf_avg * 0.4
else:
# Timeframes disagree — reduce confidence
confidence *= 0.7
if len(report.mtf_scores) >= 2:
scores = list(report.mtf_scores.values())
has_bull = any(s > 10 for s in scores)
has_bear = any(s < -10 for s in scores)
has_bull = any(s > 10 for s in report.mtf_scores.values())
has_bear = any(s < -10 for s in report.mtf_scores.values())
if has_bull and has_bear:
report.warnings.append("Timeframes CONFLICT — mixed signals across timeframes")
confidence *= 0.6