Natural gas prices often move on a weather forecast before a single extra furnace turns on. When a new forecast says next week will be colder than expected, traders expect people to burn more gas for heat, and prices tend to rise. When the forecast turns warmer, prices tend to fall.
In this guide you will learn what weather models are, how temperature turns into gas demand, and how to test a simple trading idea yourself. You will use Python, natural gas futures prices from Databento, and free weather forecasts from Open-Meteo. By the end you will have a small backtest that decides each day whether to buy, hold or sell.
This article is for learning. It is not financial advice, and the simple strategy here is a starting point, not a finished trading system.
What are weather models?
A weather model is a computer program that predicts the weather. It starts from what the air looks like right now, using readings from weather stations, balloons, planes and satellites. Then it uses the laws of physics to step forward in time, a few minutes at a time, until it reaches days or weeks ahead.
Each fresh start is called a run. Runs are named by the hour they start, in UTC time, such as "the 12z run." Natural gas traders watch every new run, because each one can change the forecast.
What is the GFS model?
The GFS (Global Forecast System) is the main weather model of the U.S. National Weather Service. It runs four times a day, at 00z, 06z, 12z and 18z, and forecasts about 16 days ahead. Its data is free, which makes it the model most people see first.
What is the ECMWF model?
The ECMWF model, often called "the Euro," comes from the European Centre for Medium-Range Weather Forecasts. Many forecasters consider it the most accurate global model over the long run. Its main runs come out twice a day, at 00z and 12z. When the GFS and the Euro disagree, traders pay close attention.
What is an ensemble, like GEFS?
An ensemble runs the same model many times, each with tiny changes to the starting weather. If most of the runs agree, the forecast is more certain. If they spread apart, it is less certain. The GEFS (Global Ensemble Forecast System) is the ensemble version of the GFS, with 21 members. Its average, called the ensemble mean, is often steadier than any single run.
What are the CPC 6–10 and 8–14 day outlooks?
The Climate Prediction Center (CPC), part of NOAA, publishes maps every afternoon. They do not give exact temperatures. Instead, they give the chance that each area will be warmer than normal, near normal or colder than normal over the next 6 to 10 days and 8 to 14 days. Weekday outlooks are checked by a forecaster; weekend ones are fully automated.
Quick comparison
| Model | Made by | Type | Runs per day | Forecast length |
|---|---|---|---|---|
| GFS | U.S. National Weather Service | Single run | 4 | About 16 days |
| ECMWF ("Euro") | European Centre for Medium-Range Weather Forecasts | Single run | 2 main runs | 10 to 15 days |
| GEFS | U.S. National Weather Service | Ensemble (21 runs) | 4 | About 16 days |
| CPC outlooks | NOAA Climate Prediction Center | Odds of warm or cold | 1 | Days 6–14 |
How does temperature turn into gas demand?
Traders turn temperatures into degree days, a simple way to measure how much heating or cooling people need. The starting point is 65 °F, the temperature at which most homes need neither heat nor air conditioning.
- Heating degree days (HDD) count how far the day's average temperature falls below 65 °F. A day that averages 40 °F has 25 HDD. More HDD means more furnaces running and more gas burned.
- Cooling degree days (CDD) count how far the average rises above 65 °F. A day that averages 85 °F has 20 CDD. Many power plants burn gas, and gas-fired power peaks in summer as air conditioners run, so hot days also raise gas demand.
In winter, HDD matter most. About 47% of U.S. homes heat mainly with natural gas, according to the U.S. Energy Information Administration, so a cold week in Chicago or New York uses a lot of it.
Why the forecast change matters more than the forecast
Prices already include what traders expected yesterday. What moves the price is new information. So traders care less about "next week will be cold" and more about "next week now looks 15 HDD colder than this morning's forecast." That change between runs is the signal we will use.
Not every city counts the same
A cold day in Chicago matters more for gas demand than a cold day in a small, warm town. So traders weight each city by how much gas it uses. In this guide we use five cities with these weights, the same demand hubs the Arc terminal uses:
| City | Weight |
|---|---|
| Chicago | 35% |
| New York City | 30% |
| Houston | 15% |
| Boston | 10% |
| Atlanta | 10% |
What you need before you start
You need Python 3.10 or newer, four free Python packages and one API key.
-
Install the packages. Open a terminal and run:
-
Get a Databento API key. Sign up at databento.com, then copy your key from the portal. Databento charges by how much data you download. Two or three years of daily prices for one contract is a very small request, and the code below checks the cost before it downloads anything.
-
Save the key as an environment variable so it never ends up in your code:
-
Open-Meteo needs no key for personal, non-commercial use, within the limits in its terms. If you plan to use it for a business, Open-Meteo asks you to buy an API plan.
Put all the code from the next four steps in one file, such as weather_backtest.py, in the order shown.
Step 1: Get natural gas futures prices from Databento
Natural gas futures trade on NYMEX, which is part of the CME Group. Databento sells the exchange's own data. We will download one price bar per day for the front-month contract, the one that expires next and that most traders watch.
=
=
=
=
=
=
=
# Daily return: how much the price changed since the day before.
=
# NG.c.0 switches to the next month's contract about once a month (the "roll").
# The jump between two different contracts is not a real gain or loss, so skip it.
= ==
= 0.0
What each part does:
NG.c.0is a continuous symbol. It always points to the front-month contract on each date, so you do not have to look up contract names like NGZ26 yourself.get_costasks Databento what the download will cost before you pay for it.instrument_idtells you which actual contract each row came from. When it changes, the series has rolled to a new month. Databento does not adjust prices across the roll, and the two contracts have different prices, so we set that day's return to zero instead of counting a fake jump.
For every option get_range accepts, see Databento's API reference.
The daily close in these bars is the last trade of the day, which can differ slightly from NYMEX's official settlement price. For a learning backtest, that difference is small.
Step 2: Get GFS and ECMWF forecasts from Open-Meteo
To test a weather strategy honestly, you need the forecasts as they looked at the time, not the weather that actually happened. Open-Meteo's Previous Model Runs API gives exactly that. For every hour, it can return the forecast made 1 day earlier, 2 days earlier, and so on up to 7 days earlier.
Its history starts in January 2024 for most models (GFS temperature goes back to March 2021), according to the API's documentation, which is why our backtest starts in 2024.
=
# City: (latitude, longitude, weight)
=
=
= # forecasts made 1 to 7 days before each day
"""Daily average temperature (°F), as forecast 1 to 7 days earlier."""
=
=
=
=
=
=
=
return
"""Gas-weighted degree days for every day, as forecast 1 to 7 days earlier."""
= 0
=
= # HDD in winter, CDD in summer
= + *
return
=
What each part does:
gfs_seamlessandecmwf_ifs025are Open-Meteo's names for the GFS and the ECMWF model. Check the API page for the current list if a name is rejected.temperature_2m_previous_day3means "the temperature 2 meters above the ground, as forecast 3 days earlier." We ask for days 1 through 7.resample("D").mean()turns 24 hourly temperatures into one daily average.(temps - 65).abs()gives HDD on cold days and CDD on hot days in one number. Both mean more gas demand, so the strategy works in winter and summer.- The result,
forecasts, holds one table per model. Each row is a day, and column 3, for example, is that day's gas-weighted degree days as forecast 3 days before.
Step 3: Turn forecast changes into buy, hold or sell
Our rule is simple: each day, check whether the next six days now look colder (or hotter) than they did in yesterday's forecast.
| If the forecast change is… | Then we… | Why |
|---|---|---|
| More than +3 degree days | Buy (go long) | More demand than the market expected |
| Less than −3 degree days | Sell (go short) | Less demand than the market expected |
| Between −3 and +3 | Hold | Not enough new information to act |
"Go short" means you profit if the price falls. With futures, buying and selling short are equally easy.
Here is an example. On Monday, the forecast for Wednesday was made 2 days ahead. On Sunday, the forecast for Wednesday was made 3 days ahead. Subtract the Sunday number from the Monday number, and you have how much Wednesday's outlook changed overnight. The code does this for each of the next six days and adds the changes up, then averages the GFS and ECMWF results.
= # the next 6 days
= 3.0 # degree days of change needed to act
"""How much the next 6 days' degree days changed since yesterday's forecast."""
= 0
= # made k days before the day it predicts
= # made one day earlier than that
= +
return
= /
return 1 # BUY: more demand than expected yesterday
return -1 # SELL: less demand than expected yesterday
return None # HOLD: keep whatever we had
=
What each part does:
.shift(-k)moves each future day's change back to the day we would have seen it, so every row lines up with the decision date.decidereturns 1 for buy, −1 for sell and nothing for hold..ffill()fills each "hold" day with the last buy or sell, so we keep our position until a new signal arrives.
The threshold of 3 degree days is a starting guess. Try other values, but be careful: if you try many and keep the best one, your results will look better than they really are.
Step 4: Backtest the strategy in Python
A backtest replays the past to see how a rule would have done. The most common mistake is letting the past "peek" at information it could not have had yet. That is called look-ahead bias, and it makes a strategy look far better than it is.
We avoid it with one rule: act a day late. Some of the forecast runs behind a day's signal finish that evening, after the market has closed. So we trade on each signal at the next trading day's close.
We also charge a small fee every time we change position, because real trading has costs.
= 0.001 # 0.1% of the price each time we change position
# A day's signal uses forecast runs that finish late that evening, so we
# act on it one day later, at the next trading day's close.
=
=
=
= * - *
=
=
=
=
, =
How to read the results
- Total return shows how $1 would have grown or shrunk. Compare it with buy and hold. A weather strategy is only useful if it beats simply owning gas, or if it loses less.
- Number of trades shows how busy the strategy is. More trades mean more fees.
- Winning days above 50% means the strategy was right more often than wrong while in a trade. It does not guarantee a profit, because a few big losing days can outweigh many small wins.
- The chart shows the path, not just the end point. A line that climbs steadily is more believable than one that jumps once and then goes flat.
Run the whole file with python weather_backtest.py. Expect the first run to take a few minutes while it downloads ten weather files.
Why this is a starting point, not a trading system
This strategy is built to teach the idea, and real traders would add a lot before risking money. Keep these limits in mind:
- The test period is short. Open-Meteo's forecast history starts in 2024, so you get only two or three winters. A strategy can look great or terrible over that span by luck.
- The market often moves first. Big trading firms read each model run within minutes. By the next day's close, much of a forecast change may already be in the price.
- Weather is not the only driver. The EIA's weekly storage report every Thursday, LNG exports, production and pipeline problems all move gas prices, sometimes more than weather.
- Five cities are a rough stand-in. A cold snap in Texas or the Pacific Northwest can matter a lot and barely show up here.
- Futures use leverage. One NYMEX natural gas contract covers 10,000 MMBtu, so a $0.10 move is $1,000. Losses can grow faster than you expect.
- Fees and slippage are estimates. Real costs depend on your broker and how you trade.
Good next steps are adding the GEFS ensemble, weighting the forecast change by how far ahead it is, and testing the rule on winter days only.