// where it is#
On /account/positions, the row-controls strip has two chips: 'export CSV' (operational format) and 'tax CSV' (1099-B-style). Both stream as downloads.
Tax mode is also reachable directly via the URL ?tax=1 — useful if you script downloads.
// columns#
opened_at—UTC ISO timestamp when the position was opened.
closed_at—currently 'open' for all rows because Sage doesn't yet have a closed-position store. When the close-tape lands (Sage backend roadmap), this becomes a real timestamp.
term—'short' if held ≤ 365 days, 'long' if > 365. Standard US long-term capital gains threshold.
venue—polymarket or kalshi.
market—the market's question text (Polymarket) or ticker (Kalshi).
side—yes or no.
cost_basis_usd—the position's size in USD at entry. This is the amount you put in.
proceeds_usd—sizeUsd × (markPrice / entryPrice) as a mark-to-market proxy. Caveat below.
realized_gain_loss_usd—proceeds_usd − cost_basis_usd.
// the MTM-proxy caveat#
Today's tax CSV uses mark-to-market as a proxy for proceeds because the order-fill record isn't in scope yet. That means closed-but-not-yet-paid positions show a 'proceeds' figure based on the latest mark price, not the actual fill you received.
For year-end filing, you'll want the real fills. Sage's roadmap (W520+) wires actual fills into this export; for now, the CSV is best treated as a draft to hand to your accountant alongside the venue's own statements.
// this is not tax advice#
Sage's tax CSV is a tool to help you organize your records — it's not tax preparation and it's not jurisdiction-specific. The output assumes US 1099-B norms for the short/long term split; if you file elsewhere, the columns are still useful but the term column may not match your local convention.
When in doubt, hand the CSV to a CPA. Sage staff can't and won't advise on tax positions.
// venue export#
Both Polymarket and Kalshi publish their own year-end activity reports. Always cross-reference Sage's CSV against the venue's report before filing — the venue's numbers are the canonical fills, Sage's are derived.
If you spot a mismatch, file an ops ticket with the row that disagrees. Most mismatches we see are because Sage hadn't synced a fill yet at the time of export; re-running the export after a few minutes usually resolves it.
