Dev
Your Coinbase 1099-DA Is Not Your Tax Return: Reconciling Proceeds and Cost Basis in Python
Dev.toUnited States · NORTH AMERICA
If you trade on Coinbase, tax season often starts with a download: a gain/loss PDF, a raw transaction CSV, and maybe Form 1099-DA. Those files are useful. They are also incomplete in ways that bite pe...
If you trade on Coinbase, tax season often starts with a download: a gain/loss PDF, a raw transaction CSV, and maybe Form 1099-DA. Those files are useful. They are also incomplete in ways that bite people who treat "proceeds on the form" as "profit I owe tax on."
This post is a developer-oriented walkthrough of what those files actually contain, where the gaps are, and a small Python sketch you can use to sanity-check a CSV before you trust it. For the full download path and form-by-form detail, see NutshellCrypto's guide to the Coinbase tax report.
What you can download
From Coinbase Taxes → Documents (sometimes labeled View Documents / Custom Reports) you typically get:
- Gain/loss report — Coinbase's own short- and long-term math for Coinbase.com trades where it knows your basis.
- Raw transaction history (CSV) — a ledger you can import into software or parse yourself.
- IRS forms when eligible — for recent years that includes Form 1099-DA (digital asset sales/exchanges), plus 1099-MISC for certain income, and others for futures or dividends when they apply.
Coinbase Taxes covers Coinbase.com activity. It does not include Coinbase Wallet, old Coinbase Pro (statements may still exist separately), other exchanges, or DEXes.
The important gap: transferred-in basis
For tax year 2025, Coinbase has said Form 1099-DA generally reports proceeds for qualifying sales, with cost basis treated as noncovered. You still compute basis yourself. Basis reporting for certain covered assets phases in for later years under broker rules — but transferred-in coins remain the classic trap.
Example: you buy BTC on Exchange A, move it to Coinbase, then sell. Coinbase may show proceeds on 1099-DA without your original purchase price. If you treat proceeds as taxable gain, you overstate the tax.
Wallet-to-wallet transfers themselves are usually not a sale; basis still matters when you dispose later. Keep a personal ledger (or tax software import) for every inbound transfer with date, quantity, and cost.
A tiny reconciliation sketch
Assume you exported a simplified CSV with columns like timestamp, type, asset, quantity, proceeds_usd, cost_basis_usd (names vary by year/export — inspect your header row).
import csv
from collections import defaultdict
from decimal import Decimal
def d(x: str) -> Decimal:
return Decimal(x.replace(",", "") or "0")
def summarize(path: str) -> dict:
by_asset = defaultdict(lambda: {"proceeds": Decimal(0), "basis": Decimal(0), "missing_basis": 0})
with open(path, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
if row.get("type", "").lower() not in {"sell", "convert", "trade"}:
continue
asset = row.get("asset") or row.get("asset_sold") or "?"
proceeds = d(row.get("proceeds_usd") or row.get("total") or "0")
basis_raw = row.get("cost_basis_usd") or row.get("cost_basis") or ""
basis = d(basis_raw) if basis_raw.strip() else None
by_asset[asset]["proceeds"] += proceeds
if basis is None:
by_asset[asset]["missing_basis"] += 1
else:
by_asset[asset]["basis"] += basis
return by_asset
for asset, s in summarize("coinbase_transactions.csv").items():
gain = s["proceeds"] - s["basis"] if s["missing_basis"] == 0 else None
print(asset, "proceeds=", s["proceeds"], "basis=", s["basis"],
"rows_missing_basis=", s["missing_basis"], "naive_gain=", gain)
What to look for:
- Rows with blank basis — usually transferred-in lots or noncovered sales.
- Totals that match 1099-DA proceeds but not your own gain/loss math.
- Activity you know happened on Wallet / another venue that never appears in this file.
Do not invent basis. Pull it from the originating exchange export or your own records, then merge by lot (FIFO/HIFO/LIFO — use the method you set and keep consistent).
Workflow that works for engineers
- Download Documents for the year: 1099-DA (and any 1099-MISC/B/DIV), gain/loss report, raw CSV.
- Parse the CSV; flag missing-basis disposals.
- Merge external lot history for inbound transfers.
- Enter or import into Form 8949 / Schedule D (or tax software); report rewards income even below a 1099-MISC threshold when required.
- Keep the CSVs and PDFs with your records.
Canada note: there is no Coinbase "slip" like a T-slip for most crypto; you still track dispositions for the CRA yourself. Details and US form walkthroughs live in the full Coinbase tax report guide.
Takeaways
- Coinbase documents are a starting point, not a finished return.
- For recent 1099-DA years, proceeds ≠ profit when basis is missing or noncovered.
- Coinbase Taxes excludes Wallet / Pro / other platforms — reconcile those ledgers separately.
- Automate a CSV pass that counts blank-basis sales before you file.
- Income below a form threshold can still be taxable.
Read the full guide on NutshellCrypto for where to click in Taxes → Documents, which IRS forms Coinbase issues, common mistakes, and a short Canada section.
This is educational content, not tax or financial advice. Rules change by year and jurisdiction; check official IRS/CRA guidance or a qualified professional for your situation.
This post was written with AI assistance.