
A futures contract code is three pieces glued together: a product root, a month letter and a year code. To map codes correctly, read the tail first (the year, then the month letter), treat what remains as the root, and then confirm that root against the exchange and the contract specifications. The rest of this guide shows how to do that, where platforms disagree, and how to keep your mapping table clean when you backtest.
TL;DR
- Most futures symbols follow the pattern product root + month letter + year code, for example ESZ5 for the E-mini S&P 500 December 2025 contract, as MetroTrade's symbology guide explains.
- The twelve month letters are F, G, H, J, K, M, N, Q, U, V, X and Z. Vendors do not all use them, so configure the exact letters your feed uses.
- A one-digit year is ambiguous across decades. Use two- or four-digit years in any mapping table you keep.
- Roots can repeat across exchanges, sizes (full, mini, micro) and platforms, so a safe mapping key includes root, exchange, multiplier and expiry.
- For backtests, map every dated contract to a continuous series through a documented roll and adjustment rule.
Table of Contents
- How a futures code is built
- The month letters
- The year code is where mappings break
- Same contract, different symbols
- Verify before you trust a mapping
- From dated contracts to a continuous series
- Perspective
- Common mapping mistakes
- Putting a mapping table to work
- Start from clean data
- FAQ
- Sources
How a futures code is built
Every listed futures contract is a specific product expiring in a specific month. The code has to carry all three facts, so it is built in three parts.
- Root: one to three (sometimes more) characters naming the product. ES is the E-mini S&P 500, CL is crude oil, GC is gold.
- Month code: one letter for the delivery or expiration month.
- Year code: one, two or four digits.
Investopedia describes the full ticker as a commodity code, a single month letter and a two-digit year, and gives CCZ18 as a cocoa contract for December 2018. Tastytrade breaks a symbol into the same three components and notes that the year code matters most when you look up a back-month contract, especially near the end of a calendar year.
A practical trick: parse from the right. Take the year digits off the end, then the single letter before them, and what is left is the root. ESZ5 becomes year 5, month Z, root ES. Parsing from the left fails as soon as a root has two, three or four letters.
The month letters
The letters look arbitrary until you see how they were chosen. Investopedia notes that letters standing for actions like bid and ask, confusing ones such as C, D and E, and I and L, which are easy to mistake when handwritten, were dropped from the traditional set. What remains, for the CME-style convention that Overcharts lists, is:
| Month | Code | Month | Code |
|---|---|---|---|
| January | F | July | N |
| February | G | August | Q |
| March | H | September | U |
| April | J | October | V |
| May | K | November | X |
| June | M | December | Z |
Two memory aids help. The quarterly cycle used by index and currency futures is H, M, U, Z (March, June, September, December). And Z closes the alphabet just as December closes the year.
A caution from the same Overcharts page: there is no common nomenclature for every data feed, so a feed can use different letters for the same month. Many follow the standard of the exchange that lists the contract, but you should not assume it. Some platforms spell out a three-letter month instead (ES SEP23 in place of ESU3), which is a different format for the same contract.
The year code is where mappings break
The month letter is stable. The year is not.
- One digit: ESM6 means June of a year ending in 6.
- Two digits: ESM26 means June 2026.
- Four digits: ESM2026, which MetroTrade notes some platforms use.
Discount Trading explains that a single-digit code can be ambiguous across decades: ESM6 might be 2016, 2026 or 2036. For a trader who only looks at live contracts that is harmless, because only one of those exists at a time. For a researcher with ten or more years of history in one table, it is a real source of silent errors.
The industry has been moving away from the problem. AMP Futures announced in 2018 that CQG changed from a one-digit to a two-digit year code so that contracts spanning more than a decade could be handled, and warned that systems supporting only single-digit years would stop working with the new format. Overcharts lists four year formats (Y, YY, YYY and YYYY) and says the right one depends on the data feed.
Rule for your own tables: store the year as four digits in a separate column, and derive the vendor string from it. Never store only the vendor string.
Same contract, different symbols
Take the E-mini S&P 500 expiring in March 2024. Depending on where you look, that one contract can show up as ESH4, ESH24 or ES MAR24. On Rithmic it is written with an exchange suffix: Ironbeam describes the format as symbol code, month code, year digit, a dot and an exchange code, giving ESH4.CME.
The differences come from a few places:
- Year width: one, two or four digits, as above.
- Separators and suffixes: dots, slashes and exchange tags. Some retail platforms put a forward slash before the root, as in /ES.
- Month spelling: letter or three-letter abbreviation.
- Root naming: the exchange root and the vendor's root can differ, for example for products with a different clearing code.
- Size variants: Linn Software points out that Interactive Brokers uses one root for both full and micro contracts and separates them by a multiplier.
That last point is the one that bites. If your key is just the root, a micro and a full-size contract collapse into one row, and your PnL scaling is wrong by a factor of ten.
A safe mapping key
Linn Software notes that Interactive Brokers needs five pieces of information to match a future exactly: the underlying code, exchange, currency, expiration month and multiplier. That list is a good template for any mapping table, whatever the vendor:
| Column | Example | Why it is there |
|---|---|---|
| Exchange root | ES | The product on the exchange |
| Exchange | CME | Roots can repeat across venues |
| Currency | USD | Same product, different currency listings exist |
| Multiplier | 50 | Separates full, mini and micro |
| Expiry (YYYY-MM) | 2025-12 | Unambiguous, sortable |
| Vendor symbol(s) | ESZ5, ESZ25, ES DEC25 | One row, many aliases |
The alias column is the heart of the mapping. One canonical row per contract, many vendor strings pointing to it.
Verify before you trust a mapping
Symbol formats change when platforms update their feeds. Discount Trading's advice is to check the active symbol in the platform's own symbol search before ordering. Overcharts goes further for data work: treat the feed's official symbol format as authoritative, and set the exact year width and month letters, because a wrongly built symbol simply will not be recognized.
A short verification routine for each new root you add:
- Find the product on the listing exchange's page and note the exchange root, contract size, tick size and listed months.
- Compare the listed months with the months your data actually contains. A product listed only for March, June, September and December should not have a July bar.
- Build the symbol for one known expiry and look it up in your platform or feed.
- Check that the price level and tick size match the specification.
- Record the multiplier and currency in your table.
Step two catches more errors than any other. A contract that appears in a month the exchange never listed is almost always a mislabeled month letter or a mixed-up year.
For a quick reference of futures roots, exchanges and markets, a futures roots and exchanges reference is handy to keep open while you build the table.
From dated contracts to a continuous series
A backtest rarely runs on one contract. A strategy that trades the E-mini for ten years touches about forty quarterly contracts, and each one lives for only a few months of heavy liquidity. So you need a rule that stitches them into a single series. That is where code mapping stops being clerical and starts affecting results.
Quantpedia's methodology overview names the standard approach as building one continuous sequence from a stream of contracts. It describes two choices you have to make.
When to roll. You can roll on the last trading day of the expiring contract, but liquidity often moves to the next contract before then. Many researchers roll earlier, based on volume or a fixed number of days before expiry.
How to adjust. Quantpedia describes a difference method, where older contracts are shifted up or down by a constant to remove the jump at each roll, working backward from the most recent contract. It also describes a ratio method, where older prices are multiplied by a constant, and a weighted blend around the roll date.
What this means for mapping:
- Your mapping table must say which dated contract is the front on each date. Keep that as its own table with a start date, an end date and the contract identifier.
- Keep the roll rule versioned. If you change from last-trading-day to volume-based rolls, the series changes, and old results are no longer comparable.
- Expired contracts must stay in the table. Delete ESZ5 after it expires and you can no longer rebuild the series that used it.
- Back-adjusted series have prices that never traded. Use them for signals and returns, and use unadjusted prices for anything tied to a real level, such as stops placed at round numbers or margin estimates.
A worked example
Suppose the roll table says the December 2025 E-mini is front until 2025-12-11 and the March 2026 contract takes over after it. On the roll date the two contracts close 18 points apart. With the difference method you subtract that gap from every bar of the December contract and everything earlier, so there is no artificial 18-point jump in your return series. With the ratio method you multiply by the ratio of the two closes instead. Either way the table, not the vendor symbol, is what tells your code which contract was live.
Perspective
We collect and maintain our data sets ourselves, and the mapping problem in this article is one we deal with every day. A symbol is only useful if everyone downstream agrees what it means, so our approach is to verify the data bar by bar and to document every adjustment we make.
Our view is that a backtest is only as honest as its data. If a month code is wrong or a roll is undocumented, no amount of strategy tuning will repair it. That is why we build our sets as complete, clean minute-bar histories, ready to import into platforms like MT4 and MT5, with the adjustments written down so you can reproduce them. The same standard applies whether the person running the test is a human or an AI-driven pipeline.
When you have a question about a symbol, a roll or an adjustment, you talk to the engineers who collect the data, not to a ticket queue.
Start
Common mapping mistakes
- Using the root as the key. Full, mini and micro contracts, and the same root on different exchanges, collide.
- Trusting a one-digit year. It looks fine until the history crosses a decade boundary.
- Assuming every feed uses the same month letters. Overcharts is explicit that there is no universal nomenclature.
- Dropping expired contracts. You lose the ability to rebuild or audit the series.
- Mixing adjusted and unadjusted prices. A back-adjusted close is not a price you could have traded at.
- Ignoring session and time zone differences. Two vendors can agree on the symbol and still cut the daily bar at different times. Our guide on matching intraday data to execution covers this for metals, and the same logic applies to futures.
- Choosing a file format that hides the metadata. If expiry and multiplier are not in the file, they must live in your table. Our overview of market data formats for quants compares the options.
Putting a mapping table to work
Build the table once and let every other tool read from it. A workable layout has three tables:
- Contracts: one row per dated contract with the canonical key (root, exchange, currency, multiplier, expiry).
- Aliases: one row per vendor string, pointing at a contract, with the vendor name and the year width noted.
- Roll schedule: one row per continuous series per period, naming the front contract and the rule used.
With that in place, adding a new data source means adding rows to the alias table, not rewriting code. Adding a new product means adding its root, multiplier and listed months. And when a platform changes its format, as CQG did in 2018, you update aliases and nothing else.
Start from clean data
A mapping table is only as good as the history behind it. At BacktestMarket we sell one-time downloads of complete minute-bar historical data sets since 2014 across forex, metals, stock indices, bonds and commodities, with bundles by asset class and back-adjusted futures data such as the Dax Pack Back Adjusted. You can browse every data set on our historical data page, or look at the Annual Plan at €119 per year.
If you are setting up a new futures mapping and want to talk through symbols or adjustments, our engineers can help. You can also see our expert advisors and indicators on the BacktestMarket home page.
FAQ
What does ESZ5 mean?
ES is the product root for the E-mini S&P 500, Z is the December month code and 5 is the year. MetroTrade reads it as the December 2025 contract. Some platforms write the same contract with a two- or four-digit year.
Are futures month codes the same on every exchange?
Mostly, yes: the twelve letters F through Z are the common convention, and many feeds follow the listing exchange's standard. But Overcharts notes that there is no common nomenclature across all data feeds. Always configure the letters your own feed documents.
Why do some symbols have one-digit years and others two?
Older or simplified systems use only the last digit, while most modern platforms use two. Discount Trading explains that the one-digit form can be ambiguous across decades. CQG moved to two digits so that contracts spanning more than ten years could be represented.
How do I map expired contracts for backtesting?
Keep every expired contract in your contracts table with its expiry, and add a roll schedule that says which contract was front on each date. Then build the continuous series with a documented roll and adjustment method, as Quantpedia outlines. This lets you rebuild the same series later.
What should I use as a unique key for a futures contract?
Use exchange root, exchange, currency, multiplier and expiry month together. That mirrors the five details Interactive Brokers needs to match a future exactly. Store vendor symbols as aliases that point to that key.
Sources
- A Guide to Delivery Months in Futures Markets, Investopedia
- Futures Symbol Format, Overcharts Help Center
- Futures Symbology Explained for Beginners, MetroTrade
- Futures Contract Specifications Explained, Tastytrade
- Futures Symbol Guide, Discount Trading
- Change to CQG Symbols: Now 2-digit year code, AMP Futures
- Understanding Symbols on Rithmic, Ironbeam
- Interactive Brokers Symbol Guide, Linn Software
- Continuous Futures Contracts Methodology for Backtesting, Quantpedia
Recommended
- Rolling Rules for Futures Contracts
- Continuous Futures Data: How to Build and Use It
- Futures Rollover Methods That Cut Roll Drag for Quants with Minute Bar Tests
Related resources
Explore BacktestMarket's Expert Advisor robots to put the ideas in this article into practice.

