feat: market regime, self-learning journal, AI investment committee
- regime.py: computed SPY/VIX/sector-momentum snapshot injected into every kickoff - journal.py: each agent sees its own past picks marked-to-market (learns from wins/losses) - committee.py: Chief-Risk-Officer LLM pass over the whole book — approve/reduce/veto per pick with reasons; memo lands in reports; executor enforces verdicts at open Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016DvdRZkyCy9NJpHYDdPqmS
This commit is contained in:
1 parent
6b1c461a80
commit
4beee3dc82
6 files changed
+323
-2
No files matched your search
@@ -0,0 +1,64 @@
|
||||
"""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)
|
||||
)
|
||||
Reference in new issue
Block a user