portfolio-mark
You hand over a position CSV. The skill marks every line to current fair value, computes book value and (if cost basis is in the input) unrealized P&L, and flags any mark where confidence is medium or low so the operator can override before the number lands in a report.
This is the "what is this book worth right now" workflow. Pricing services do it; this skill does the same thing without the seat fee and with the per-position confidence rating that internal pricing desks usually leave implicit.
When to invoke
- Operator says "mark this book" or "what's this portfolio worth right now" or hands over a CSV asking for current value
- A risk team needs intraday marks for a Greek aggregation or var run
- An ops team is generating an EOD statement and wants to flag thin names before publishing the NAV
- A PM is wiring up a live dashboard and needs a streaming mark per symbol
Modes
Delayed mode (default)
REST snapshot per position. Walks the 4-step fallback chain
(snapshot.ticker.lastTrade.p → min.c → day.c → prevDay.c) via
lib/quant_garage/snapshot.py::resolve_price and emits the timestamp of
whichever field won. Works on any paid Stocks plan; on Free Basic the
rate limit caps batch size to ~5 positions per minute but the
methodology is identical.
Use this for end-of-day reporting, weekly statements, and any context where a 15-minute lag on the underlying is acceptable. Cheaper operationally; no socket to manage; one report per run.
Live mode
WebSocket subscribes to one or more channels for every position.
Listens for --listen seconds (default 30), accumulates the most
recent mark per symbol, and emits the same marked-positions table
plus an optional "live tape" trailer showing the last few ticks per
symbol.
Live mode reads from the business cluster
(wss://business.polygon.io/stocks) and prefers, in order:
T.{ticker}(tick trades; requires Stocks Advanced + signed real-time agreement)AM.{ticker}(per-minute aggregates; available on Stocks Business without the real-time addendum)FMV.{ticker}(Business-tier Fair Market Value stream)
If T.{ticker} returns not authorized, the skill resubscribes to
AM.{ticker} automatically and notes the downgrade in the rendered
output. Quote channel Q.{ticker} is subscribed in parallel so bid/ask
flow from the stream without a REST round-trip. See references/live-vs-delayed.md
for the tier matrix and which channels each plan actually delivers
(the published Massive docs and the lived entitlement behavior diverge,
see notes there).
What you need
- A position CSV with at minimum
ticker,shares. Optional columns:cost_basis(per-share, for P&L),as_of_date(informational). MASSIVE_API_KEYexported. Delayed mode runs on Stocks Starter or higher (Stocks Basic works with rate-limit pain). Live mode needs Stocks Advanced forT.{ticker}ticks, or Stocks Business for theAM.{ticker}andFMV.{ticker}fallback channels.
What you get back
Two output layers from one analysis.
Layer 1: canonical JSON matching output-schema.json.
Per-position fields: mark, mark_source (which step in the fallback
chain won), confidence (high/medium/low), as_of timestamp, bid/ask if
available, spread in basis points, and (if cost basis given) unrealized
P&L. Per-flagged-mark fields: reason codes, detail text, source
endpoint. UIs and downstream agents consume this.
Layer 2: rendered hybrid output. A marked-positions table at the
top, a FLAGGED exception block at the bottom for any mark that wasn't
high-confidence. Optional "Live tape" trailer in live mode. See
references/rendering.md for the format
rules. Claude Code users read this.
How it works (delayed mode)
- Read every row of the CSV. Group by symbol; warn on duplicates but keep them separate (different lots).
- For each unique symbol, GET the snapshot endpoint. Walk the
fallback chain per
references/snapshot-fallback-chain.mdand record which step produced the mark. - Compute confidence per
references/confidence-scoring.md: recency of the chosen mark, bid-ask spread in bps, and average daily volume. High = top-decile ADV and last trade within 60s and spread <10bps; Medium = mid ADV and trade within 5min and spread 10-50bps; Low = anything thinner or staler. - Compute book value (sum of
shares * mark). If cost basis is in the input, compute unrealized P&L perreferences/book-value-and-pnl.md. - Emit JSON and rendered markdown. Anything below
highconfidence appears in the FLAGGED block.
How it works (live mode)
- Open one WebSocket to the business cluster.
- Auth, then subscribe to the preferred channel for every symbol
in the book. If
T.{ticker}returnsnot authorized, resubscribe toAM.{ticker}and note the downgrade. - Listen for
--listenseconds. Maintain per-symbol state: last mark, last update timestamp, trade count, recent ticks for the tape. Seereferences/websocket-mark-updates.mdfor the message-handling pattern (move work off the receive thread, resubscribe on reconnect, backpressure-aware drain loop). - On disconnect within the listen window, resubscribe to the full
set per the
massive-websocketsfoundation. Log the gap and continue. - At the end of the window, emit the same marked-positions table.
For symbols that received zero ticks during the window, fall back
to a one-shot REST snapshot (with
mark_source: "snapshot.*"so the operator sees which symbols never streamed).
Foundations used
massive-api-patternsfor REST auth, rate limiting, and the snapshot fallback chainmassive-websocketsfor the live socket flow (auth, subscribe, reconnect, backpressure)
This is the first skill in the suite that exercises the
massive-websockets foundation end-to-end. Any gotchas discovered
during the build are added to that foundation's SKILL.md.
Endpoints used
Delayed mode:
GET /v2/snapshot/locale/us/markets/stocks/tickers/{ticker}: mark, bid/ask, recent OHLC. The single REST call per symbol.GET /v2/aggs/ticker/{ticker}/range/1/day/{from}/{to}: ~22 sessions of daily aggregates for the 30-day ADV bucketing in confidence scoring. Cached per ticker per run.
Live mode (in addition to the REST snapshot for fallback):
wss://business.polygon.io/stockschannels:T.{ticker},AM.{ticker},FMV.{ticker}(subscribe-time fallback in that order), plusQ.{ticker}for bid/ask.
Doesn't handle (yet)
- Options OCC marks (the skill is equity-only for v1; options chains
use a different snapshot endpoint and a different live channel under
wss://socket.polygon.io/options. Extending to options is a clean follow-up; the fallback chain and confidence model carry over.) - FX-denominated positions. The mark is in USD; non-USD positions need an FX overlay outside the scope of v1.
- Long/short with separate margin treatment. The skill flips the sign
on
unrealized_pnl_usdfor negative-share positions but doesn't compute margin requirements. - Multi-account roll-up. One CSV in, one report out.
Add these in a PR if you need them. The patterns are clean extensions of the existing chain + confidence logic.