Contents Lesson 8 of 16

5 min read · professional

What is a bar made of, if not simply the trades?

Underneath every bar are individual trades — ticks. It is natural to assume a 1-minute bar is just first, max, min, last and sum over the ticks in that minute. Fetch both and the assumption does not survive contact.

What a tick response looks like

/ticks returns historical trade-level data for US equities only. Its parameters are s (the symbol, required), from and to as UNIX seconds, limit, and fmt — which accepts json and nothing else.

The response shape is unusual. It is not an array of trade objects; it is one object of parallel arrays, each as long as the number of ticks:

mkt, price, seq, shares, sl, sub_mkt, ts

Element i of every array describes the same trade. Seven arrays — and note that the specification declares an eighth, ex ("list of exchanges where transactions took place"), which the server does not send. Build your column index from the keys you actually received, not from the documented list, or the first zip over all eight raises. price and shares are the transaction, mkt and sub_mkt name where it was reported, seq is the tape sequence number, sl carries the sale-condition codes, and ts is the timestamp.

Note the unit change: from and to go in as seconds, and ts comes back in milliseconds. In one endpoint.

The density

Ask for Apple's opening minute on 20 July 2026 with limit=40. Those forty trades span timestamps 1784554200016 to 1784554200289 — 273 milliseconds. Forty prints in the first quarter-second of the session. A full minute at the open is thousands; a full day is hundreds of thousands. This is why bars exist.

Where the naive reconstruction fails

Now compare. The first price in that tick stream is 333.39. The 1-minute bar for the same minute reports open = 333.505 — a price that appears eight trades later in the sample.

The bar did not take the first trade. It took the first eligible one.

The reason is in the sl field. Every print carries condition codes: @ marks a regular sale, and additional letters flag categories such as odd lots (I), extended-hours prints and intermarket sweeps (F). The consolidated tape's rules exclude some of those categories from setting the last sale price and the session's official high and low — odd lots and extended-hours trades among them, while an intermarket sweep stays fully eligible. The first print in that sample is a 3-share @F I, and it is the odd-lot I that keeps it out of the official open. A bar built by a data vendor respects those rules. A loop that takes min(price) and max(price) over every row does not, and will produce a wider range than the official one — occasionally a much wider one, because ineligible prints are exactly the ones that stray.

shares needs the same caution. In that forty-trade sample, two rows report shares: 0. Summing the column naively gives a number that is not the bar's volume and never will be.

Where trades happen

The mkt field in that sample carries the codes K, D, Z, Y, V, P, Q, B, X and J — ten venues inside a quarter of a second, for one stock. Each is a different exchange or reporting facility.

One deserves a name: D, appearing with sub_mkt Q, is the off-exchange reporting route — trades executed away from a lit exchange and printed to the tape afterwards. These are the off-exchange prints, and "dark" is only part of what is in them: wholesalers internalising retail flow, dark-pool (ATS) executions and broker crosses all arrive through the same reporting route. FINRA publishes ATS volume separately from the rest of off-exchange volume precisely because they are different businesses; the tape does not separate them for you. They are genuine transactions and they count in consolidated volume, but nobody could have traded against them at the time. If you are studying execution, separating D from the lit venues is the first thing you do.

This is liquidity-revisited at the level of individual prints: volume is not one pool, and where a trade happened changes what it tells you.

Cost and scope

Two limitations to state plainly. /ticks covers US exchanges only — there is no equivalent for London or Tokyo through this path. And tick requests are metered more heavily against your quota than an ordinary call, because one of them can return hundreds of thousands of rows. Course 1 covers how that accounting works. /mp/unicornbay/tickdata/ticks offers marketplace tick data with a conventional array-of-objects shape (timestamp, price, volume, exchange, conditions), which is a separate product with separate coverage.

Try it now

  1. Here is /ticks?s=AAPL&from=1790346660&to=1790346720&limit=100, the single minute from 14:31 UTC on 25 September 2026 (from and to are required; without them the call answers 404), reduced to the first and the hundredth trade. Convert ts from milliseconds and work out how much of the minute the hundred trades actually cover, and what share of the minute that is.
Live API response: mda1 apple ticks one minute
  1. Across all hundred of those ticks, measured on 28 September 2026, min(price) was 335.93 and max(price) 336.4201. Compare them with the 1-minute bar's low and high for the same minute, below. Say which end of your range is wider than the bar's and which is narrower, and why each one is.
Live API response: mda12 apple 1m bar 1431
  1. In the same hundred ticks, 78 rows carried mkt = D, and they held 1,289 of the 2,165 shares. Work out both shares: of prints and of volume. That fraction is a real, measurable property of the stock and the minute.