remove the AI market-outlook feature (delivery-side only; books byte-identical)
Owner decision 2026-09-15. Gone: market_outlook.py, the post-H1-scan Telegram
outlook DM, main.py --outlook, the outlooks table DDL/migration/writer in
signal_log.py, the market_outlook config block + MARKET_OUTLOOK_ENABLED, and
test Module 26. Last commit containing the feature: 2836024.
- app_config: "market_outlook" stays in _KNOWN_TOP as a TOLERATED, ignored
legacy key (oanda.account_id precedent) with one warning, so a live
config.json that still carries the block keeps booting.
- signal_log: existing DBs keep their orphan outlooks table and rows (no
DROP TABLE); fresh DBs never create it.
- tests: Module 26's 4-thread concurrent legacy-DB migration test (the
suite's only one) moved to Module 31; new test for the tolerated block.
519 -> 509 tests, 34 -> 33 modules, 0 failed.
- docs: CLAUDE.md usage/config/file-map lines and a dated state note.
Verification: W2 books (2024-09-05 -> 2026-09-05, $0.65, NumPy CPU, 0 cache
fallbacks) byte-identical before/after — M5 29120a1ee32979431d062f210d41a9d1
(781 / +146.07R / PF 1.52), M15 d185f099482a07f29502cb5a371a9bbf
(931 / +146.14R / PF 1.43).
This commit is contained in:
@@ -184,19 +184,6 @@ CREATE TABLE IF NOT EXISTS scan_outcomes (
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_scan_outcomes_tf_bar
|
||||
ON scan_outcomes (timeframe, bar_ts);
|
||||
CREATE TABLE IF NOT EXISTS outlooks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
logged_at TEXT NOT NULL,
|
||||
surface TEXT NOT NULL,
|
||||
bias TEXT,
|
||||
setup_forming TEXT,
|
||||
confidence REAL,
|
||||
watch TEXT,
|
||||
note TEXT,
|
||||
news_json TEXT,
|
||||
indicators_json TEXT,
|
||||
candles_json TEXT
|
||||
);
|
||||
"""
|
||||
|
||||
# Additive migration for columns introduced after the original schema.
|
||||
@@ -298,12 +285,6 @@ SCAN_LABEL_TIME_BUDGET = 2.0
|
||||
# often than a candle close. Explicit calls (batch script, tests) ignore it.
|
||||
SCAN_LABEL_MIN_INTERVAL = 60.0
|
||||
|
||||
_ADDITIVE_OUTLOOK_COLS = (
|
||||
("news_json", "TEXT"),
|
||||
("indicators_json", "TEXT"),
|
||||
("candles_json", "TEXT"),
|
||||
)
|
||||
|
||||
_SIGNAL_INSERT_COLS = (
|
||||
"logged_at", "source", "symbol", "timeframe", "signal", "score",
|
||||
"confidence", "quality", "action", "price", "spread", "market_regime",
|
||||
@@ -323,13 +304,6 @@ _INSERT = (
|
||||
+ ", ".join("?" for _ in _SIGNAL_INSERT_COLS) + ")"
|
||||
)
|
||||
|
||||
_OUTLOOK_INSERT = """
|
||||
INSERT INTO outlooks (
|
||||
logged_at, surface, bias, setup_forming, confidence, watch, note,
|
||||
news_json, indicators_json, candles_json
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
|
||||
def _finite(x: Any) -> Optional[float]:
|
||||
"""float(x) or None for non-numeric / non-finite values (NaN/inf —
|
||||
@@ -851,7 +825,6 @@ class SignalLogger:
|
||||
self._with_lock_retry(
|
||||
lambda: self._conn.executescript(_SCHEMA))
|
||||
self._with_lock_retry(self._migrate_signal_columns)
|
||||
self._with_lock_retry(self._migrate_outlook_columns)
|
||||
self._with_lock_retry(self._ensure_news_view)
|
||||
|
||||
def _ensure_news_view(self) -> None:
|
||||
@@ -917,21 +890,6 @@ class SignalLogger:
|
||||
" ON signals (timeframe, bar_ts)")
|
||||
self._conn.commit()
|
||||
|
||||
def _migrate_outlook_columns(self) -> None:
|
||||
"""Add snapshot columns to pre-existing outlook tables."""
|
||||
existing = {
|
||||
r[1] for r in self._conn.execute("PRAGMA table_info(outlooks)")
|
||||
}
|
||||
for name, col_type in _ADDITIVE_OUTLOOK_COLS:
|
||||
if name not in existing:
|
||||
try:
|
||||
self._conn.execute(
|
||||
f"ALTER TABLE outlooks ADD COLUMN {name} {col_type}")
|
||||
except sqlite3.OperationalError as exc:
|
||||
if "duplicate column name" not in str(exc).lower():
|
||||
raise
|
||||
self._conn.commit()
|
||||
|
||||
def log(
|
||||
self,
|
||||
report: Any,
|
||||
@@ -1536,33 +1494,6 @@ class SignalLogger:
|
||||
self._conn.commit()
|
||||
return reseeded
|
||||
|
||||
def log_outlook(self, outlook: Any, surface: str,
|
||||
payload: Any = None) -> int:
|
||||
"""Insert one advisory market outlook; returns its rowid."""
|
||||
payload = payload if isinstance(payload, dict) else {}
|
||||
technical = {
|
||||
key: payload.get(key)
|
||||
for key in ("indicators", "market_regime",
|
||||
"volatility_regime", "key_levels")
|
||||
if key in payload
|
||||
}
|
||||
row = (
|
||||
datetime.now(timezone.utc).isoformat(),
|
||||
surface,
|
||||
getattr(outlook, "bias", None),
|
||||
getattr(outlook, "setup_forming", None),
|
||||
_finite(getattr(outlook, "confidence", None)),
|
||||
getattr(outlook, "watch", None),
|
||||
getattr(outlook, "note", None),
|
||||
_dumps(payload.get("news")) if "news" in payload else None,
|
||||
_dumps(technical) if technical else None,
|
||||
_dumps(payload.get("candles")) if "candles" in payload else None,
|
||||
)
|
||||
with self._lock:
|
||||
cur = self._conn.execute(_OUTLOOK_INSERT, row)
|
||||
self._conn.commit()
|
||||
return int(cur.lastrowid)
|
||||
|
||||
def close(self) -> None:
|
||||
with self._lock:
|
||||
self._conn.close()
|
||||
@@ -1700,28 +1631,6 @@ def log_watch_update(report: Any, watch: Any) -> None:
|
||||
exc_info=True)
|
||||
|
||||
|
||||
def log_outlook(outlook: Any, surface: str = "live",
|
||||
payload: Any = None) -> None:
|
||||
"""Persist one advisory outlook when signal logging is enabled.
|
||||
|
||||
Outlook persistence is deliberately independent of a signal row: the
|
||||
feature runs on its own hourly cadence and must never affect a scan.
|
||||
"""
|
||||
try:
|
||||
if not app_config.signal_log_enabled():
|
||||
return
|
||||
path = app_config.signal_log_path()
|
||||
with _loggers_lock:
|
||||
lg = _loggers.get(path)
|
||||
if lg is None:
|
||||
lg = SignalLogger(path)
|
||||
_loggers[path] = lg
|
||||
lg.log_outlook(outlook, surface, payload=payload)
|
||||
except Exception:
|
||||
logger.warning("signal_log: failed to persist market outlook",
|
||||
exc_info=True)
|
||||
|
||||
|
||||
def reset_loggers_for_tests() -> None:
|
||||
"""Close and drop all cached loggers (test isolation)."""
|
||||
with _loggers_lock:
|
||||
|
||||
Reference in New Issue
Block a user