The rule, in one line
Expiration = 3rd Friday of March / June / September / December
Roll date = 2nd Thursday, 8 days earlier
CME equity index futures trade on a quarterly cycle — H (March), M (June), U (September), Z (December). The contract stops trading on the third Friday of its month, but liquidity leaves earlier than that: open interest moves to the next quarter on the second Thursday, eight days before expiry. Trade the old contract after the roll and you'll find the spread wider and the book thinner, which is a slow, avoidable tax.
Why your journal shows two symbols for one strategy
After a roll, the same trade idea is recorded under a different contract code — ESU26 becomes ESZ26 — so any tool that groups by the full contract code silently splits your track record into quarterly fragments. ExpectancyIQ groups by the product root instead (`ESU26` and `ESZ26` both roll up to `ES`), which is what makes a year of ES trading readable as one strategy rather than four. Import your own history and see it grouped properly.
What this covers — and what it doesn't
The dates above apply to the CME equity index quarterly cycle: ES, MES, NQ, MNQ, RTY, M2K, YM and MYM. They all share one rule, so one calendar serves all eight.
They do not apply to energy, metals or treasuries. Crude oil rolls monthly on a business-day count before the delivery month; gold and natural gas have their own delivery calendars; treasury futures key off first notice day rather than a fixed Friday. Those rules are different enough that publishing a guess here would be worse than publishing nothing — check the CME contract specifications for those products.
Exchange holidays aren't modelled either. If the third Friday falls on a market holiday the real last trading day shifts, and this calendar won't know.
Related tools
Futures market hours shows whether the session is open right now, and the contract size calculator gives tick and notional values for each of these contracts.