wealthfolio: add compute_position_qty for broker reconciliation
This commit is contained in:
parent
975c3b4bf7
commit
882415464e
2 changed files with 103 additions and 0 deletions
|
|
@ -315,6 +315,50 @@ class WealthfolioSink:
|
|||
total += amt
|
||||
return total
|
||||
|
||||
async def compute_position_qty(self, account_id: str) -> dict[str, Decimal]:
|
||||
"""Return per-symbol net position quantity (BUY/IN minus SELL/OUT) for
|
||||
one account. Skips cash activities and unknown activity types.
|
||||
|
||||
Used by the IBKR reconciliation step to compare against broker-reported
|
||||
OpenPositions.
|
||||
"""
|
||||
qty_by_symbol: dict[str, Decimal] = {}
|
||||
page = 1
|
||||
while True:
|
||||
resp = await self._request(
|
||||
"POST", _ACTIVITIES_SEARCH,
|
||||
json={"accountIds": [account_id], "page": page, "pageSize": 500},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
payload = resp.json()
|
||||
activities = payload.get("activities", []) if isinstance(payload, dict) else []
|
||||
if not activities:
|
||||
break
|
||||
for act in activities:
|
||||
if not isinstance(act, dict):
|
||||
continue
|
||||
symbol = act.get("symbol") or ""
|
||||
if not symbol or symbol.startswith("$CASH"):
|
||||
continue
|
||||
act_type = act.get("activityType") or ""
|
||||
sign: int
|
||||
if act_type in {"BUY", "ADD_HOLDING", "TRANSFER_IN"}:
|
||||
sign = 1
|
||||
elif act_type in {"SELL", "REMOVE_HOLDING", "TRANSFER_OUT"}:
|
||||
sign = -1
|
||||
else:
|
||||
continue
|
||||
try:
|
||||
qty = Decimal(str(act.get("quantity") or 0))
|
||||
except Exception:
|
||||
continue
|
||||
qty_by_symbol[symbol] = qty_by_symbol.get(symbol, Decimal(0)) + sign * qty
|
||||
total_pages = int(payload.get("totalPages") or 1) if isinstance(payload, dict) else 1
|
||||
if page >= total_pages:
|
||||
break
|
||||
page += 1
|
||||
return qty_by_symbol
|
||||
|
||||
# -- manual holdings snapshots --
|
||||
|
||||
async def push_manual_snapshots(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue