Futures data blog

MNQ Historical Data in Parquet: Download, Inspect, and Validate It

Download free MNQ Parquet samples, inspect their schema, check bar quality, and avoid common timestamp and continuous-contract mistakes.

Published · 1,248 words

Start with the file that matches your question

MNQ is the Micro E-mini Nasdaq-100 futures contract. It has a 0.25 index-point minimum tick and a multiplier of 2 USD per index point, so one tick is worth 0.50 USD per contract. Those two numbers matter when a research result moves from a chart into a P&L calculation.

The MNQ dataset page offers monthly Parquet bars in eight timeframes: 10 seconds, 1 minute, 2 minutes, 5 minutes, 30 minutes, 1 hour, 4 hours, and 1 day. The latest three months are available in the free tier. Ten-second files can be downloaded without an account. The other monthly timeframes require a free verified account. Older monthly files and the full tick archive are paid datasets.

Use a small monthly bar file to inspect a workflow, check a parser, or prototype a feature. Use the longer archive only after that workflow survives basic checks. Three months is enough to catch schema and alignment errors. It is not enough to establish that a trading strategy works across different volatility regimes.

Open the MNQ page and choose the month and timeframe from the current list. Monthly filenames follow this pattern:

cme.mnq.bars.<timeframe>.<YYYY-MM>.parquet

For example, this shell fragment downloads the October 2026 one-minute file. Change MONTH when the catalog moves forward, or copy the current URL from the dataset page.

MONTH=2026-10
curl -LO "https://historicalfuturesdata.com/samples/MNQ/1m/cme.mnq.bars.1m.${MONTH}.parquet"

A 403 response for a non-10-second sample usually means you need to log in. A 404 can mean the month is outside the current free window or the filename is wrong. Check the published links rather than assuming that every calendar month exists.

Inspect the schema before calculating anything

The monthly bar schema is deliberately small: ts, open, high, low, close, volume, and trade_count. Load it with explicit columns and look at actual rows before writing a strategy.

import pandas as pd

path = "cme.mnq.bars.1m.2026-10.parquet"
columns = ["ts", "open", "high", "low", "close", "volume", "trade_count"]
df = pd.read_parquet(path, columns=columns)

print(df.dtypes)
print(df.head(3).to_string(index=False))
print(df.tail(3).to_string(index=False))
print(f"rows={len(df):,}")

The timestamp is timezone-aware UTC. Keep it that way for sorting, joins, and resampling. Convert to America/Chicago only when you need exchange-local labels. Converting early and then dropping timezone information is a common way to mix observations from different sessions.

Bars omit empty intervals. A missing one-minute row can mean there were no eligible trades in that bucket, or the market was closed. Do not fill every gap with the previous close and then treat the manufactured rows as executable prices.

Run inexpensive checks that catch expensive mistakes

A Parquet reader can parse a file perfectly while the research dataset is still wrong for your purpose. Start with structural checks. The following assertions test ordering, duplicates, OHLC relationships, and nonnegative activity. They do not prove market completeness, but they catch many ingestion errors immediately.

assert df["ts"].is_monotonic_increasing
assert not df["ts"].duplicated().any()
assert df[["open", "high", "low", "close"]].notna().all().all()
assert (df["high"] >= df[["open", "close", "low"]].max(axis=1)).all()
assert (df["low"] <= df[["open", "close", "high"]].min(axis=1)).all()
assert (df["volume"] >= 0).all()
assert (df["trade_count"] >= 0).all()
assert (df["volume"] >= df["trade_count"]).all()

# Empty buckets are omitted, so investigate gaps instead of filling them blindly.
gaps = df["ts"].diff()
print(gaps.value_counts().head(10))

The OHLC checks use the row's open, close, low, and high values rather than hard-coded price limits. This keeps the test useful during large market moves. If a row fails, preserve it for inspection instead of deleting it automatically. A bad price can be a parsing problem, a scale problem, or a genuine extreme trade. Those require different responses.

Also check the filename against the data. Every timestamp in a monthly sample should belong to that UTC month. A file can have the right name and still contain an accidental concatenation if a pipeline was changed incorrectly.

month = df["ts"].dt.strftime("%Y-%m").unique()
assert month.tolist() == ["2026-10"]

Reproduce another timeframe before trusting your resampler

One useful pipeline test is to aggregate the one-minute file into five-minute bars and compare the result with the published five-minute file. Intraday bars are aligned to UTC epoch boundaries. Use left-labeled, left-closed intervals, then remove buckets with no source rows.

one_minute = df.set_index("ts")
rebuilt = one_minute.resample(
    "5min", label="left", closed="left", origin="epoch"
).agg({
    "open": "first",
    "high": "max",
    "low": "min",
    "close": "last",
    "volume": "sum",
    "trade_count": "sum",
}).dropna(subset=["open"])

published = pd.read_parquet(
    "cme.mnq.bars.5m.2026-10.parquet"
).set_index("ts")

pd.testing.assert_frame_equal(
    rebuilt.sort_index(),
    published[rebuilt.columns].sort_index(),
    check_dtype=False,
)

If the comparison fails, print a handful of mismatched buckets. Check the boundary convention first, then timezone handling, then empty-bucket treatment. Changing random parameters until the frames match is not a diagnosis. Record the rule that makes the two independently produced datasets agree.

Daily bars need separate treatment. They follow the Chicago 17:00 session boundary with daylight-saving handling, not a simple UTC-midnight resample. Use the published daily file or the documented session logic rather than applying the intraday example to 1D data.

Know what the continuous series cannot tell you

These bars are derived from back-adjusted continuous futures ticks. A continuous series is useful for studying signals over time, but it is not a dated contract you could have held from beginning to end. The bar file does not tell you which contract filled every order, what the spread was, or whether your size would have moved the market.

Back adjustment changes the historical price level. It does not change the cash needed for a trade, and it is not profit or loss. For MNQ, contract P&L is calculated from raw dated-contract price differences:

pnl_usd = side * (exit_raw - entry_raw) * 2.00 * contracts
# side is +1 for long and -1 for short.

Charge the exit of the old contract and the entry of the new contract during a roll. A single percentage change across a continuous join is not a substitute for those two transactions. The companion article on continuous futures signals, rolls, and P&L works through that distinction.

Keep the research split honest

Do not choose a moving-average window, threshold, or stop because it happens to work best across all three free months and then report the same months as an out-of-sample test. If you experiment on the free sample, treat it as development data. Reserve later history for evaluation, or finish with a genuinely untouched chronological period from the full archive.

Write down the file names, row counts, download date, and validation checks used in each run. Small details such as an updated monthly sample or a changed empty-bucket rule should be visible in the experiment record. That record is more useful than a polished equity curve that cannot be reproduced.

A practical first-pass checklist

  • Confirm the month, timeframe, schema, UTC timezone, and row count.
  • Test OHLC identities and investigate duplicates and gaps without inventing bars.
  • Reproduce a second timeframe to validate resampling rules.
  • Use continuous prices for signal research and dated contracts for execution accounting.
  • Apply the MNQ multiplier and transaction costs before reading net P&L.
  • Keep a later, untouched period for evaluation.

The dataset documentation describes the schemas and session rules in detail. Read it alongside the code you write, especially before mixing monthly samples with annual or per-contract files.