thainowcast: nowcasting models for Thai GDP and inflation

No weights here, and no results about Thailand. These models keep no fitted state. At every forecast origin each one is re-estimated from scratch on the data released by that date, so a frozen set of weights would be stale the day after it was saved. This repository records the models instead: the classes, hyperparameters, feature sets and the model × feature-set grid. Every number quoted below comes from synthetic test data. It shows that the pipeline works, not how well these models nowcast the Thai economy.

These are the models of the working paper ThaiNowcast: Pseudo-Real-Time Nowcasting of Thai GDP and Inflation with Official and Alternative Data by Thanatchon Chongmankhong (read online · PDF · DOI 10.5281/zenodo.23995547). Code: https://github.com/thanatchon36/thainowcast. Data and full results: thanatchon36/thainowcast (dataset).

Independent personal research. Does not represent the views of any employer or institution.

Targets

target frequency forecast origins
gdp_yoy: real GDP growth, y-o-y (%), NESDC quarterly M1, M2, M3 (end of each month of the quarter), PR (the day before the official release)
cpi_yoy: headline CPI inflation, y-o-y (%), TPSO monthly M0 (mid-month), PR

Models

code class hyperparameters
rw RandomWalk last released value
ar AR AR(p), p ≤ 4 chosen by AIC
bridge Bridge indicators completed to the end of the target period with AR(1) forecasts, averaged to the target frequency, 2 principal components, OLS
midas MIDAS one regressor (mean of standardized indicators), 12 monthly lags, exponential Almon weights re-estimated for each number of missing months. GDP only
dfm DFM mixed-frequency dynamic factor model (statsmodels DynamicFactorMQ), 1 factor, AR(1) factor, EM up to 50 iterations, re-estimated once a year; also gives the news decomposition
enet ElasticNetNowcast ElasticNetCV, l1 ratio in {0.1, 0.5, 0.9}, 40 alphas, time-series CV with up to 4 folds
lgbm LightGBMNowcast 300 trees, learning rate 0.03, 4 leaves, min 5 samples per leaf, row and column subsampling 0.8, L2 1.0, deterministic

Feature sets: hard_only (14 official monthly statistics), hard_trends, hard_lights, hard_no2 and hard_prices (hard data plus one family of alternative data: Google Trends, nighttime lights, Sentinel-5P NO2, online prices), all (hard data plus all five families, mobility included) and none for the univariate benchmarks. GDP runs 20 model × feature-set pairs and CPI 22. Each model's 80% interval is the conformal quantile of its absolute backtest errors at the same origin.

Files

path content
model_specs.json every model's class and hyperparameters, the indicators in each feature set, the backtest settings and the full grid per target, pinned to code commit ce9dd21
config/indicators.yaml the indicator registry: agency, frequency, start, publication lag, transform and the source of each series
live_nowcast.json synthetic. The live nowcast as of 2026-11-05: every model's value and interval, the headline model and the GDP news decomposition. Rerunning the snippet under Use reproduces the GDP headline, 2.622
LICENSE MIT, as for the code

Accuracy on synthetic data

RMSFE at the last origin (PR) over the full backtest, relative to the AR benchmark (below 1 beats AR). GDP covers 2015Q1 to 2026Q2 (46 quarters), CPI 2015-01 to 2026-09 (141 months).

model GDP hard_only GDP all CPI hard_only CPI all
enet 0.46 0.78 0.68 0.54
bridge 0.55 0.66 1.45 1.29
dfm 0.64 0.89 0.92 0.92
midas 0.64 0.66 – –
lgbm 0.73 0.72 0.72 0.60
rw 1.04 1.02

The synthetic generator sets how much each data family helps, so this ranking tells you nothing about Thailand. The full tables, Diebold-Mariano tests, regime splits and ablations are in the dataset.

Use

The models run inside the pipeline, so you use the code rather than a download from this repository:

git clone https://github.com/thanatchon36/thainowcast && cd thainowcast
make setup          # uv venv + pip install -e ".[dev,app]"
make all            # data -> eval (backtest) -> live -> dashboard -> paper

To nowcast for real, put the official CSVs named in docs/data_sources.md into data/raw/ (the synthetic_* files are used only when a real one is missing, with a warning), then run make all ASOF=YYYY-MM-DD. One model on its own:

from thainowcast.config import load_config
from thainowcast.data.loaders import load_panel
from thainowcast.features import transform_wide
from thainowcast.models import MODELS
from thainowcast.config import RAW_DIR
import pandas as pd

cfg, asof = load_config(), pd.Timestamp("2026-11-05")
panel = load_panel(cfg, RAW_DIR)
y = panel.series_available(asof, "gdp_yoy")                       # GDP released by asof
X = transform_wide(panel.wide_available(asof, list(cfg.indicators), "M"), cfg.indicators)
X = X[cfg.set_columns("hard_only")]
print(MODELS["enet"]().nowcast(y, X, pd.Period("2026Q3", "Q"), asof))

Limitations

  • Trained and evaluated on synthetic data only. Real Thai series have revisions, breaks and gaps the generator does not reproduce, and the backtest uses first releases, not real-time vintages.
  • Publication lags in config/indicators.yaml are approximations of each agency's usual timing.
  • The panel is short: 46 GDP quarters in the backtest, so differences between models are noisy.

Citation

@misc{chongmankhong2026thainowcast,
  author = {Chongmankhong, Thanatchon},
  title  = {ThaiNowcast: Pseudo-Real-Time Nowcasting of Thai GDP and Inflation with Official and Alternative Data},
  year   = {2026},
  doi    = {10.5281/zenodo.23995547},
  url    = {https://thanatchon36.github.io/thainowcast/paper/},
  note   = {Working paper; results are from synthetic test data}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train thanatchon36/thainowcast