violent-move watch: display-only warning line + owner heads-up (dark by default)
New violent_watch.py assesses each scan from the cached Forex Factory week events, the UTC clock and the report's own indicator states, and stamps SignalReport.watch_line post-hoc (telegram alerts, CLI, dashboard). A standalone heads-up goes to the owner on the fastest scanned timeframe when the level is "hot", once per UTC hour per trigger set, capped per day. Config block `violent_watch` (enabled False, alert_line, headsup, max_headsup_per_day, headsup_min_level); env VIOLENT_WATCH_ENABLED. Rule chosen from a 3-year bar-by-bar sweep (backtest/research/watch_rule_eval.py, recorded in sizing_campaign_2026-09.md): hot = high-impact USD release within 30 min (before or after) OR a hot clock slot (weekday 12-14 UTC, 01 UTC, Sunday 22-23 UTC) with at least one price-extreme reading (outside Bollinger bands, RSI <30/>=70, outside Keltner); ~8.6% of bars, next-bar odds 3-5x normal, ~4 hot hours/day. watch = clock slot alone or two price-extreme readings (~2x). Context readings (ADX rising, extreme volatility, transitioning, MACD acceleration) are phrases only - letting them raise the level flagged 27% of bars at ~2x and would have sent ~13 heads-ups/day (rejected). Direction sentence: DOWN when bearish readings dominate (70-78% on both TFs), UP on M5 only. Never a gate or exit: every open-trade protection tested lost money. Test-locked out of analyze_from_dataframes / engine / backtester. Module 30 (18 tests). Suite: 453 passed. Guide PDFs not rebuilt. Claude-Session: https://claude.ai/code/session_01RWV2yLt3YXHHGVYHSQU2EE
This commit is contained in:
@@ -22,10 +22,12 @@ if hasattr(sys.stderr, "reconfigure"):
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
|
||||
from agent_panel import attach_panel
|
||||
from app_config import get_app_config, violent_watch_enabled
|
||||
from config import PlatformConfig, Timeframe, SignalStrength, XAUUSD
|
||||
from market_outlook import OutlookResult, maybe_run_outlook
|
||||
from pair_signals import PAIR_PRODUCERS
|
||||
from signal_aggregator import SignalAggregator, SignalReport
|
||||
from violent_watch import attach_watch
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
@@ -160,6 +162,8 @@ def print_signal_report(report: SignalReport, detail: bool = False):
|
||||
if report.warnings:
|
||||
for w in report.warnings:
|
||||
print(f" {Colors.YELLOW}⚠{Colors.RESET} {w}")
|
||||
if report.watch_line:
|
||||
print(f" {Colors.YELLOW}🌪{Colors.RESET} {report.watch_line}")
|
||||
if report.event_description and report.event_risk != "clear":
|
||||
print(f" {Colors.YELLOW}📅{Colors.RESET} {report.event_description}")
|
||||
if report.news_description and report.news_description != "Neutral news sentiment":
|
||||
@@ -246,6 +250,7 @@ def report_to_dict(report: SignalReport) -> dict:
|
||||
"panel_created_at": report.panel_created_at,
|
||||
"panel_cache_status": report.panel_cache_status,
|
||||
"panel_payload_hash": report.panel_payload_hash,
|
||||
"watch_line": report.watch_line,
|
||||
"bullish_reasons": report.bullish_reasons,
|
||||
"bearish_reasons": report.bearish_reasons,
|
||||
"warnings": report.warnings,
|
||||
@@ -373,6 +378,12 @@ def run_live(args, config: PlatformConfig):
|
||||
if getattr(args, "panel", False):
|
||||
attach_panel(report, surface="cli", force=True)
|
||||
|
||||
# Display-only violent-move watch (dark by default; never touches
|
||||
# the signal, only report.watch_line).
|
||||
if violent_watch_enabled():
|
||||
attach_watch(report, config.primary_timeframe,
|
||||
get_app_config().violent_watch_settings)
|
||||
|
||||
outlook = None
|
||||
if getattr(args, "outlook", False):
|
||||
outlook = maybe_run_outlook(surface="cli", force=True)
|
||||
|
||||
Reference in New Issue
Block a user