Oct 7, 2026
Mexico's Auto Market with Live INEGI Data
Pipeline that stores every monthly INEGI release on light-vehicle sales, production, and exports as an immutable snapshot, to analyze brands, seasonality, and the exchange rate, and to measure how figures get revised between releases. Work in progress: snapshot ingestion with revision detection is live.
Problem
Every month, INEGI (Mexico’s national statistics institute) publishes light-vehicle sales, production, and exports by brand and model. The data is live: each release adds the new month and can also correct earlier months. For example, May 2025 sales were first released as 119,959 units and now show 121,110. An analysis that only downloads “the latest version” misses those corrections and cannot explain why a figure changed.
The project asks how sales evolve by brand, how seasonal they are, and how much the exchange rate explains them. It includes a 3–6 month forecast that is only reported if it beats a seasonal naive model in backtesting.
Status
Work in progress. This page is updated at every iteration and only describes what has actually run.
| Stage | Status |
|---|---|
| Ingestion of each release into raw as an immutable snapshot | Done |
| New-release detector and automatic download | Pending |
| Curated layer in Parquet (types, normalization, duplicates) | Pending |
| Data contracts that stop a bad batch | Pending |
| Reconciliation against the INEGI API and Banxico exchange rate | Pending |
| Comparison between releases (what was revised and why) | Pending |
| BigQuery warehouse and marts | Pending |
| Forecast with backtesting against a baseline | Pending |
| Dashboard | Pending |
| Scheduled runs on Google Cloud | Pending |
Planned architecture
INEGI (4 monthly zips) ─► raw/ (one snapshot per release) ─► curated/ (Parquet) ─► BigQuery ─► dashboard
INEGI API + Banxico ─► reconciliation and exchange rate ──────────┘
The raw layer exists today. Each release is stored exactly as it arrived, in raw/raiavl/<product>/publication_date=YYYY-MM-DD/, together with a copy of its metadata file and a manifest. The manifest includes the sha256 of the zip and of every file inside it.
What works today
- Snapshot ingestion: the product and release date are read from the zip’s content, not from its file name. Integrity (CRC) and structure are checked before anything is stored. Ingesting both real releases (8 zips, 69 MB) takes about one second, and a second run writes nothing.
- A snapshot is never overwritten. If another zip arrives with the same release date, the files inside are compared:
- if it is the same content with different packaging, nothing is written and a warning is logged;
- if it is a silent correction, ingestion stops and lists the files that changed.
- Offline tests: 73 tests run on GitHub Actions on every push. They use 71 KB of fixtures cut from the real releases without changing any value. The fixtures deliberately include the hard cases: duplicate keys, negative corrections, a brand rename, and the BMW reclassification.
Findings about the source
Measured by comparing two real releases (September and October 2026). The pipeline does not compute them automatically yet; that comes with the release diff.
- Figures are revised between releases. In October, BMW moved units of imported “Serie 2” and “Serie 3” to new domestic models (“Serie 2-”, “Serie 3-”) going back to December 2021. For example, in August 2026 the imported Serie 2 went from 157 to 50 units, and 107 appeared under the domestic version. Total historical sales changed by only 1 unit.
- The October revision only touched 2021–2026. In sales, the files for 2005 to 2020 arrived byte-for-byte identical.
- Figures become final one month at a time. In October only September 2023 moved from revised to final, across all four products. The official note says the change happens every February. Hypothesis to confirm with upcoming releases: a rolling 36-month window.
- Packaging changes without notice. The October zips arrived uncompressed and are 12 to 34 times larger depending on the product, with the same columns. This is why ingestion compares content, not just bytes.
- Source quality: repeated keys (137 in sales, 0.11% of units), corrections with negative units (87 sales rows, the largest −791), and brands that change names (JETOUR becomes “Jetour Soueast” in March 2025).
Design decisions
- Each release is an immutable snapshot, identified by the
modifieddate in its metadata. Revision history only exists from the first stored snapshot, and past revisions are not simulated. - Repackaging is told apart from a real correction: the comparison is per file, so a zip regenerated with the same data does not stop the pipeline, but a silent correction does.
- The same code runs locally and in the cloud: storage sits behind a common interface (
LocalStorage/GCSStorage). - No credentials in the repository: INEGI and Banxico tokens only live in environment variables or Secret Manager.
Stack
Today: Python (standard library), pytest, ruff, GitHub Actions. Planned: pandas and pyarrow, SQL on BigQuery, Cloud Storage, Cloud Run Jobs, Cloud Scheduler, Terraform, and a Looker Studio dashboard.
Data
Source: INEGI, Registro Administrativo de la Industria Automotriz de Vehículos Ligeros (RAIAVL), open data used under INEGI’s free-use terms. This is an independent project: INEGI does not endorse or review it. No values have been transformed so far; the zips are stored exactly as published. The exchange rate will come from Banxico’s Economic Information System (SIE), series SF43718.
Technical documentation (in Spanish): repository README and test fixtures and their cases.