Contents Lesson 3 of 16

4 min read · practitioner

Why is the last price on this option two months old?

Here is a row from /mp/unicornbay/options/eod, taken from the specification's own example, snapshot dated 2025-08-12:

  • contract AAPL270115P00450000, a put struck at 450
  • last: 245.9, tradetime: '2025-06-08'
  • open: 0, high: 0, low: 0, volume: 0
  • previous: 0, previous_date: ""
  • bid: 218.4 at 2025-08-12 19:59:59, ask: 222.2, midpoint: 220.3

The "last price" on this contract is 245.9, and it was set on 8 June — 65 days before the snapshot. Note in passing that 8 June 2025 was a Sunday, and US listed options do not print on a Sunday: a published example illustrates the shape of a row, not a market observation, which is the whole reason this course prefers a live call. Meanwhile the bid and ask are timestamped to the second on the snapshot day itself, and their midpoint is 220.3.

That is a gap of 25.6, or 11.6% of the midpoint, between the number most people would call "the price" and the number the market was actually showing.

Two endpoints, two questions

/mp/unicornbay/options/contracts and /mp/unicornbay/options/eod take an identical filter set and look almost the same. They answer different questions.

Contracts asks what exists and what state is it in. EOD asks what was recorded for this contract on this day — one row per contract per day, which is why its id carries the date.

If you are building a chain snapshot, use contracts. If you are building a time series, use EOD and expect one row per day per contract, including days on which nothing traded.

Zeros are not prices

open, high, low and volume all read 0 on that row. Zero here does not mean the option was worthless; it means no trade occurred. A parser that treats these as prices will compute a daily range of zero, a return of minus one hundred percent, and a candle that plots at the origin.

The same is true of previous: 0 beside an empty previous_date — live it arrives as null, and the specification shows "", so a guard written against either one alone misses the other. Both say the same thing: there is no prior observation, not that the prior observation was 1 January of year zero. This is the same class of problem as the missing and stale values covered in Reading the Market, and options data hits it far harder than equities because most contracts in a chain do not trade on most days.

The practical consequence: for an illiquid contract, the quote (bid, ask, midpoint) is the only field carrying today's information. last is a fossil.

The spread is visible in the row

Look at the far-dated call from the contracts example on the same day: bid: 2.85, ask: 4.4, midpoint: 3.63.

Check the midpoint: (2.85 + 4.40) ÷ 2 = 3.625, which rounds to the published 3.63. Now measure the spread: 4.40 − 2.85 = 1.55, which is 42.8% of the midpoint.

Forty-three percent. On the underlying stock that same day, the spread was a small fraction of one percent. Liquidity is not an abstraction you have to look up somewhere else; it is sitting in two adjacent columns of the row you already fetched, and it varies enormously across a single chain — tight near the money and near expiry, wide out in the tails.

This is a description of how quoted markets behave, not a suggestion about which contracts anyone should transact in.

Compact mode, and why it changes your parser

The EOD endpoint takes compact with values 0 or 1. Set compact=1 and rows come back as arrays instead of objects, with the column names listed once in meta.fields. The payload shrinks substantially on a 40-column schema.

The cost is that your parser must read the header. Positional access to a compact row is only safe if you built the index from meta.fields on that same response — column order is not a contract, and a field you did not request with fields[options-eod] simply will not be there.

Try it now

  1. The chain endpoint is marketplace data, which this page does not render, and the Terminal shows the same chain. Open Apple's, pick one expiry, and count how many contracts show no volume on the day. On a normal day that fraction is large, and it is the single best measure of how much of a chain is real. Change the symbol in the Terminal to any other optionable US name and count again.

Open AAPL.US — options in the EODHD Terminal 2. In the same Terminal chain, take the January 2027 expiry and five calls: one well in the money, one near the money, and three further out. For each, compute (bid + ask) / 2 and compare it with the midpoint the chain shows. Then compute the spread as a percentage of that midpoint and see how it changes as you move away from the money.

https://terminal.eodhd.com/#/options?symbol=AAPL.US

  1. Still in the chain, find three contracts with no volume on the day. For each, compare the last traded price with the midpoint in percent, and note how old the last trade is if the chain shows its time. Then decide, in writing, which field your code will use as "the price", and what it does with a contract that has never traded at all, whose last arrives as 0 and whose tradetime is null.