"""Self-learning trade journal — each agent sees its own past picks AND how they worked out before researching tonight. Losses and wins become explicit lessons instead of being forgotten. Joins past theses with their execution price (orders table) and marks each to market via the current price. Compact text block injected into the agent's kickoff. """ from __future__ import annotations from loguru import logger from config.settings import get_settings from state import db as statedb from tools.market_data import latest_price _MAX_ROWS = 10 def lessons_for(persona_id: str) -> str: """Past-pick scorecard for one agent. Empty string if no history/DB yet.""" s = get_settings() if not s.db_path.exists(): return "" try: con = statedb.connect(s.db_path) rows = con.execute( """ SELECT t.trade_date, t.ticker, t.direction, t.conviction, t.thesis, o.est_price, o.status FROM theses t LEFT JOIN orders o ON o.trade_date = t.trade_date AND o.agent = t.agent AND o.ticker = t.ticker WHERE t.agent = ? ORDER BY t.trade_date DESC, t.conviction DESC LIMIT ? """, (persona_id, _MAX_ROWS), ).fetchall() con.close() except Exception as e: logger.warning("journal query failed for {}: {}", persona_id, e) return "" if not rows: return "" lines = [] for r in rows: entry = r["est_price"] outcome = "not executed" if entry: px = latest_price(r["ticker"]) if px: chg = (px / entry - 1) * 100 if (r["direction"] or "long") == "short": chg = -chg outcome = f"{chg:+.1f}% since {r['trade_date']} (entry ~{entry:.2f})" lines.append( f"- {r['trade_date']} {r['ticker']} {r['direction']} conv={r['conviction']}: {outcome}" f" | thesis was: {(r['thesis'] or '')[:100]}" ) return ( "YOUR TRACK RECORD (mark-to-market of your past picks — learn from it; double down on " "what worked, avoid repeating what failed):\n" + "\n".join(lines) )