Trades CSV format

The import file is comma-delimited CSV with RFC 4180 quoting. Uploaded files are decoded for you — UTF-8, UTF-16, or cp1252, with or without a byte-order mark — so a spreadsheet's "Unicode Text" save works as well as a plain one. Export and re-import round-trip losslessly.

If you just want to get a file in, start with Trades and CSV import. This page is the reference you come back to when a row won't take.

This is the format for holdings-tracked accounts. Balance-tracked accounts have their own, much shorter one — Balances CSV format.

The header row

The first line must be exactly this, all fifteen columns, in this order:

date,account,symbol,type,side,quantity,price,fees,amount,note,underlying,expiry,strike,right,seq

Nothing else is accepted — not a subset, not a reordering, not your broker's own header. If you'd rather not type it, use Download template in the import dialog: it gives you the header plus two example rows.

Columns

Column Required What it holds
date yes YYYY-MM-DD.
account yes Account name, matched case-insensitively against your non-archived accounts. An unmatched name is a row error — import never creates accounts.
symbol depends Ticker or symbol, as-is. Leave it blank for a pure cash row — allowed only when side is transfer, interest, or fee. Required for buy, sell, dividend, and split.
type no equity, etf, fund, crypto, or option. Blank means equity.
side yes buy, sell, dividend, interest, fee, split, or transfer.
quantity yes Plain decimal. For a split, the shares added. For an option, contracts.
price depends Required for every side except split, where it must be blank. For an option this is the per-share price — the 100× contract multiplier is applied separately.
fees no Plain decimal. Blank means 0.
amount depends Signed cash impact. See Leaving amount blank below.
note no Free text. Quote it if it contains a comma, a quote, or a newline.
underlying, expiry, strike, right depends Required together, and only when type is option; blank otherwise. expiry is YYYY-MM-DD; right is call or put.
seq no Integer. Left blank, the importer assigns one so that otherwise-identical rows (two same-day margin-interest charges, say) each get their own id. Set it explicitly to pin a row to a specific id.

Formats

These are strict, because a silently misread number is worse than a rejected row.

  • Dates are YYYY-MM-DD, zero-padded, hyphens only — and must be real calendar dates. 2024-02-30 is rejected. The same rule applies to expiry.
  • Numbers are plain decimals: an optional leading -, digits, an optional . and more digits. No thousands separators, no currency symbols, no percent signs, no scientific notation, no leading +, no bare .5, no trailing 1.. This covers quantity, price, fees, amount, and strike.
  • seq is a whole number.
  • Enum values are lower-case and exact. Buy, BUY, and ETF are all errors; write buy and etf.
  • Whitespace around a value is trimmed everywhere except in note, which is taken exactly as written.
  • Symbols are stored as you write them. Only your manual entries are uppercased for you; the CSV path is not, so pick one spelling and keep it.

Leaving amount blank

amount is the row's signed cash impact, so an account's net cash flow is exactly the sum of its amount column. Left blank, it is computed for you — multiplier is 100 for an option row and 1 otherwise:

side Blank amount becomes
buy -(quantity × price × multiplier + fees)
sell quantity × price × multiplier − fees
fee -fees
split 0
dividend Row error — must carry an explicit, positive amount.
interest Row error — must carry an explicit, non-zero amount.
transfer Row error — must carry an explicit amount.

Write the amount yourself and it is used as-is, with three sanity checks that apply either way: a dividend must be greater than zero, an interest row must not be zero, and a split must be exactly zero.

Cash rows

Leave symbol blank for activity that only moves cash. Don't invent a placeholder ticker — a symbol on any row becomes a tracked instrument and gets a price fetched for it every day.

side What it's for
transfer A deposit, a withdrawal, or a journal between accounts.
interest Signed: negative is margin interest charged, positive is interest earned.
fee An account-level fee that isn't attached to a holding.

For an account whose history you're only importing part of, record the starting cash as a transfer row dated before the first trade. Cash rows are not decoration: a holdings account's value is its open positions plus its cash, and a negative cash balance shows up as a margin debit that reduces the account's value. See Portfolio and cash.

Options and splits

An option row needs type set to option and all four of underlying, expiry, strike, and right filled in. Any one of those four on a non-option row is an error. quantity is in contracts, price is per share, and the ×100 contract multiplier is applied for you — it is never a column.

A split row records the shares added, not the post-split total: a 4-for-1 split of 10 shares is quantity 30. Its price must be blank and its amount blank or 0.

Keeping rows distinct

Every trade gets a deterministic id from its account, date, symbol, side, quantity, price, and seq. Two rows that agree on all of those are the same trade — which is what makes re-importing a file you've already imported a no-op rather than a duplicate.

Note what is not in that list: amount, fees, and note. Two identical cash rows on the same day — two margin-interest charges, two equal deposits — would otherwise collide, so the importer fills in a blank seq for you, taking the lowest number not already claimed within that file. Set seq yourself when you want a row pinned to a specific id. If two rows in one file end up claiming the same id, the second is rejected with a message telling you to give it a different seq.

One consequence worth knowing: that assignment is per-file and positional, and it counts only within the file — never against what's already stored. Strip rows out of the middle of a file and re-import it, and the rows that shared an identity with them slide down onto ids already in your history, where they're skipped as duplicates. Since amount, fees, and note aren't part of the id, the figures that stay are the deleted rows', not the surviving ones'. If you need to re-import part of a history, export it first — an export always writes a concrete seq, which pins each row's identity to the file rather than to its position in it.

Errors

A bad row is reported on its own line and never aborts the rest of the file. You see it in the preview before anything is written, with its line number and what went wrong.

Only three problems reject the whole file:

  • It's empty.
  • Its header doesn't match the line above, exactly. The dialog shows you the header it expected next to the one your file starts with.
  • It isn't text at all — usually a spreadsheet, which you'll need to export as CSV first. You can also land here by pasting text that was mangled on its way through the clipboard; upload the .csv file itself instead and the importer will work the encoding out from the bytes.

A worked file

Every side, an option, a split, cash rows, and a quoted note with an embedded quote:

date,account,symbol,type,side,quantity,price,fees,amount,note,underlying,expiry,strike,right,seq
2024-01-05,Brokerage,AAPL,,buy,10,150.5,1.25,,,,,,,
2024-01-06,Brokerage,MSFT,equity,sell,5,300,,,,,,,,
2024-01-07,Brokerage,AAPL,equity,dividend,0,0,0,12.34,Q1 dividend,,,,,
2024-01-08,Brokerage,,,interest,0,0,0,5.5,,,,,,
2024-01-09,Brokerage,,,fee,0,0,9.99,,"Maintenance fee, incl. ""overdraft"" surcharge",,,,,
2024-01-10,Brokerage,,,transfer,0,0,0,-500,"Wire to ""Checking"" acct",,,,,
2024-01-11,Brokerage,AAPL,equity,split,10,,0,,4:1 split,,,,,
2024-01-12,Retirement,AAPL,option,buy,2,5.25,1.5,,,AAPL,2024-06-21,150,call,0
2024-01-12,Retirement,BTC,crypto,sell,0.5,40000,20,,,,,,,1

And a cash-only file — an opening balance, deposits and withdrawals, both legs of a journal between two accounts, two same-day margin-interest charges, and an account fee:

date,account,symbol,type,side,quantity,price,fees,amount,note,underlying,expiry,strike,right,seq
2024-01-02,Brokerage,,,transfer,0,0,0,25000,Opening cash balance,,,,,
2024-02-01,Brokerage,,,transfer,0,0,0,5000,ACH deposit,,,,,
2024-02-15,Brokerage,,,transfer,0,0,0,-1200,ACH withdrawal,,,,,
2024-03-01,Brokerage,,,transfer,0,0,0,-10000,Journal to Retirement,,,,,
2024-03-01,Retirement,,,transfer,0,0,0,10000,Journal from Brokerage,,,,,
2024-03-31,Brokerage,,,interest,0,0,0,-187.97,Margin interest,,,,,
2024-03-31,Brokerage,,,interest,0,0,0,-9.09,Margin interest,,,,,
2024-04-01,Brokerage,,,interest,0,0,0,3.42,Cash sweep interest,,,,,
2024-04-30,Brokerage,,,fee,0,0,25,,Account maintenance fee,,,,,

What an export looks like

Export CSV — in the import dialog for every account, or on an account's trades screen for just that one — writes the same fifteen columns in the same order, sorted by date, account, symbol, and seq. Numbers come back with trailing zeros stripped (1.50 becomes 1.5), and everything is spelled out: a type you left blank and an amount that was computed are both written explicitly. The only deliberate blank in an export is price on a split row; every exported row carries a concrete seq.