From df10d1291f97df75a935eb318fc646160ad72b2b Mon Sep 17 00:00:00 2001 From: I Luk Kim Date: Wed, 22 Apr 2026 20:07:31 -0700 Subject: [PATCH] Fix cross-session avg_entry_price contamination in positions view Parking positions now use parking_state.avg_price instead of Alpaca's blended avg_entry_price, which gets polluted when multiple sessions share one broker account. Co-Authored-By: Claude Sonnet 4.6 --- apps/web/routers/paper_trading.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/web/routers/paper_trading.py b/apps/web/routers/paper_trading.py index 7c976ff..13ce5f5 100644 --- a/apps/web/routers/paper_trading.py +++ b/apps/web/routers/paper_trading.py @@ -314,13 +314,19 @@ def get_positions(session_id: str) -> dict[str, Any]: is_parking = parking_symbol and p.symbol == parking_symbol if ss is None and not is_parking: continue # Only show positions tracked by this session - # Use locally-recorded entry price/qty for strategy positions to avoid - # orphaned-share contamination of Alpaca's blended avg_entry_price. + # Use locally-recorded entry price/qty to avoid cross-session contamination + # of Alpaca's blended avg_entry_price (multiple sessions share one broker account). ot = open_trades.get(p.symbol) if not is_parking else None - qty = float(ot["shares"]) if ot and ot.get("shares") else float(p.qty) - entry = float(ot["entry_price"]) if ot and ot.get("entry_price") else ( - float(p.avg_entry_price) if p.avg_entry_price else 0.0 - ) + if is_parking and parking_state: + qty = float(parking_state.get("qty") or p.qty) + entry = float(parking_state["avg_price"]) if parking_state.get("avg_price") else ( + float(p.avg_entry_price) if p.avg_entry_price else 0.0 + ) + else: + qty = float(ot["shares"]) if ot and ot.get("shares") else float(p.qty) + entry = float(ot["entry_price"]) if ot and ot.get("entry_price") else ( + float(p.avg_entry_price) if p.avg_entry_price else 0.0 + ) cur_price = float(p.current_price) if p.current_price else None pnl = (cur_price - entry) * qty if cur_price and entry and qty else float(p.unrealized_pl) pnl_pct = pnl / (entry * qty) * 100 if entry and qty else 0.0