Files
trading-agent/tools/portfolio.py
T

57 lines
1.9 KiB
Python

"""get_portfolio — persona-scoped. Each agent sees ONLY its own paper account's holdings
(written by execution/reconcile.py, keyed by persona id), so picks build on that book.
Built per-persona via make_get_portfolio() in tools/build_toolset.
"""
from __future__ import annotations
import json
from langchain_core.tools import tool
from config.settings import get_settings
from state import db as statedb
def make_get_portfolio(account: str):
"""Return a get_portfolio tool bound to one account (persona id)."""
@tool
def get_portfolio() -> str:
"""Return YOUR current paper-account holdings, unrealized PnL, and cash.
Use this BEFORE proposing trades so you account for what you already own.
"""
path = get_settings().db_path
if not path.exists():
return "No portfolio data yet (fresh account, no trades recorded)."
try:
con = statedb.connect(path)
snap = statedb.latest_snapshot(con, account or None)
con.close()
except Exception as e:
return f"No portfolio data yet ({e})."
if snap is None:
return "No holdings yet (fresh account, all cash)."
lines = [
f"As of {snap['ts']}: equity=${snap['equity']:,.2f}, "
f"cash=${snap['cash']:,.2f}, buying_power=${snap['buying_power']:,.2f}"
]
try:
positions = json.loads(snap["positions_json"] or "[]")
except Exception:
positions = []
if not positions:
lines.append("Holdings: none (all cash).")
else:
lines.append("Holdings:")
for p in positions:
lines.append(
f" {p.get('symbol')}: {p.get('qty')} @ {p.get('avg_entry')} "
f"-> mv={p.get('market_value')}, unrealized_pl={p.get('unrealized_pl')}"
)
return "\n".join(lines)
return get_portfolio