Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016DvdRZkyCy9NJpHYDdPqmS
47 lines
1.3 KiB
Python
47 lines
1.3 KiB
Python
"""Snapshot one persona's Alpaca account into the state DB (keyed by persona id), so the
|
|
dashboard and the next nightly run (via get_portfolio) see that account's holdings + PnL.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from loguru import logger
|
|
|
|
from execution.broker import Broker
|
|
from state import db
|
|
|
|
|
|
def _f(x, default=0.0) -> float:
|
|
try:
|
|
return float(x)
|
|
except (TypeError, ValueError):
|
|
return default
|
|
|
|
|
|
def reconcile(db_path, account: str, broker: Broker) -> dict:
|
|
acct = broker.get_account()
|
|
positions = broker.get_positions()
|
|
|
|
pos_list = [
|
|
{
|
|
"symbol": p.symbol,
|
|
"qty": _f(p.qty),
|
|
"avg_entry": _f(p.avg_entry_price),
|
|
"market_value": _f(p.market_value),
|
|
"unrealized_pl": _f(p.unrealized_pl),
|
|
}
|
|
for p in positions
|
|
]
|
|
|
|
con = db.connect(db_path)
|
|
db.record_snapshot(
|
|
con, account=account, equity=_f(acct.equity), cash=_f(acct.cash),
|
|
buying_power=_f(acct.buying_power), positions=pos_list,
|
|
)
|
|
for p in pos_list:
|
|
db.upsert_position(con, account=account, **p)
|
|
con.commit()
|
|
con.close()
|
|
|
|
logger.info("reconciled {}: equity=${:.2f} positions={}", account, _f(acct.equity), len(pos_list))
|
|
return {"account": account, "equity": _f(acct.equity), "positions": pos_list}
|