Movers don’t forecast. We use last June to staff this June and call it a system. It works okay until it doesn’t — until last June was a fluke, or a holiday fell on a different day, or a competitor went out of business and flooded the market with available trucks.
We can do better. Here’s the math.
Why Moving Demand Is Forecastable
Moving demand has three properties that make it unusually friendly to time-series forecasting:
- Strong yearly seasonality. 60%+ of all U.S. moves happen May–September. This repeats every year with remarkable consistency.
- Strong weekly seasonality. Saturdays run 2–3x weekday volume. Sundays are near-zero. Mondays are catch-up days.
- Holiday spikes that are known in advance. June 30, July 31, August 1, end-of-month lease dates, Canadian Moving Day (July 1 in Quebec) — these are baked into the calendar.
A forecaster that knows these patterns can produce useful projections from relatively modest amounts of historical data.
Why We Picked Prophet
Prophet is open-source, released by Meta (Facebook) in 2017. Per the official Prophet documentation, it’s designed for time series that have strong seasonal effects and several seasons of historical data. That’s moving demand with the lights on.
The peer-reviewed paper (Taylor & Letham, 2018, “Forecasting at Scale,” The American Statistician 72(1):37–45) describes it as an additive model where the forecast is the sum of interpretable components. That matters: you can see exactly why the model thinks June 28 is a Tier 5 day, because you can decompose the forecast into its parts.
We didn’t need a deep learning model. We needed something interpretable, seasonal, and robust to missing data and outliers — which Prophet is.
The Prophet Model in Plain English
Prophet decomposes a time series into additive components:
y(t) = g(t) + s(t) + h(t) + ε(t)
- g(t) — Trend. The long-term growth or decline in your business. Are you booking more jobs this year than last? The trend captures that.
- s(t) — Seasonality. Two layers: yearly (May–September peak) and weekly (Saturday spike). These are learned from your data as flexible Fourier series.
- h(t) — Holiday effects. Known dates that spike or dip. June 30, July 1, July 4, Labor Day, Memorial Day, Canadian Civic Holiday — these are added as one-time or recurring effects.
- ε(t) — Noise. Everything the model can’t explain. Random variation. One-off events.
Additive means each component is independent. If you want to know what the Saturday effect is, you can isolate it. If you want to remove the holiday spike to see the baseline, you can subtract it. The model is a glass box, not a black box.
What Signal We Feed It
The model consumes 18+ months of historical jobs per location. We use the move date, not the booking date, because we’re forecasting demand for service capacity, not for lead intake.
Each data point is weighted by truck count — a 3-truck job represents more demand than a 1-truck job. This gives the model a sense of actual capacity consumption, not just job count.
What Signal We Pulled Out
Canadian holiday calendars and U.S. holiday calendars are both loaded. Prophet’s built-in add_country_holidays method makes this trivial — you tell it which country, and it adds the relevant holidays as regressors. Canada Day and U.S. Independence Day are different holidays on different days with different demand effects. The model handles them correctly.
What It Doesn’t Do Well, and What We Add
Prophet doesn’t see weather. A heat wave in July doesn’t change the forecast until it’s already happened. We layer weather forecasts in as an extra regressor for operators who want it, but the model doesn’t depend on it.
Prophet doesn’t see competitor pricing. If a competitor drops their Saturday rate by 20%, the model doesn’t know. We track this manually when operators report it, and we can adjust the tier override accordingly.
These are edge cases. For the core forecast — “how busy is June 28 going to be based on what we know about June 28ths in general and the trend of this business specifically” — Prophet is accurate enough to assign a demand tier that’s directionally right and operationally useful.
The Output
A demand-tier label per day per location: 1 (slow) to 5 (peak). That’s it. The forecaster doesn’t produce a price — it produces a tier. The pricing engine picks up the tier and applies the rate card for that tier. The discount engine uses the tier to decide whether to offer the flexibility discount button.
The output is intentionally coarse. A 5-tier system is easy for dispatchers, sales agents, and owners to understand and act on. A continuous probability distribution is mathematically richer but operationally unusable. Five tiers give you the granularity you need to price differently without the cognitive overhead of a continuous scale.
What’s Next
Cross-validation. Prophet supports built-in cross-validation on historical data. We’re running retrospective tests against last year’s actuals to measure the model’s error rate per location and adjust where needed.
Prediction intervals. Prophet produces uncertainty cones naturally. We’re building the UI to show these to operators so they understand the confidence level behind each tier assignment.
Confidence-aware pricing. A Tier 5 assignment with a narrow confidence interval is different from a Tier 5 with a wide one. The pricing engine should treat them differently — and it will.
Curious what your own demand curve looks like? Send us 12 months of jobs and we’ll plot it.
References:
- Prophet homepage — https://facebook.github.io/prophet/
- Prophet GitHub — https://github.com/facebook/prophet
- Taylor, S.J. & Letham, B. (2018). Forecasting at Scale, The American Statistician 72(1):37–45 — https://doi.org/10.1080/00031305.2017.1380080
- Prophet seasonality & holidays docs — https://facebook.github.io/prophet/docs/seasonality,_holiday_effects,_and_regressors.html
- moveBuddha peak season data — https://www.movebuddha.com/blog/peak-moving-season/