Shrimp is one of the most interesting protein markets to model. Unlike chicken or pork, shrimp is globally traded, dominated by farmed supply from a handful of countries (Ecuador, India, Indonesia, Vietnam), and subject to boom-bust cycles driven by hatchery investment and disease outbreaks. It also has a textbook-clean seasonal signal from holiday demand and harvest cycles.

This post is a technical walk-through of how to decompose a monthly shrimp price series into trend, seasonal, and residual components, and to use that decomposition to build a forecast that respects seasonality — something a plain random walk can’t do.

Data

Approximate monthly average import unit-values for white shrimp, 21/25 count, shell-on, headless, raw, from Ecuador, CIF US port, January 2019 through December 2024 (USD / lb, 72 observations). Figures are illustrative but track the well-documented 2022 peak and 2023 oversupply-driven collapse.

The structural story in the chart:

  • 2019–early 2020: relatively stable at $4.50–$4.75 / lb.
  • COVID drop (mid-2020): foodservice demand evaporates; prices fall into the high $3s.
  • 2021 rebound: reopening + container shortages push prices back toward $4.80.
  • 2022 peak: tight supply and freight inflation drive prices above $5.
  • 2023 crash: Ecuador’s farmed output surges; prices collapse to near $3.10 — a textbook cobweb / pork cycle in seafood.
  • 2024 recovery: gradual drift back toward the high $3s.

Stationarity and first differencing

Levels are non-stationary (clear trend breaks and persistent drifts). For retail / trade unit-values, I usually work in first differences rather than log returns — the series is not traded as an asset, so the compounding interpretation of ln(P[t]/P[t-1]) doesn’t add much, and first differences preserve the natural units (USD / lb / month).

d[t] = P[t] - P[t-1]

The differenced series is visibly closer to stationary, with the bulk of the drops concentrated in 2022 Q4 and 2023 H1 (the oversupply episode). Volatility clusters suggest an ARCH component is present, but we’ll defer that to a future post.

Classical decomposition

A good first pass at a seasonal series is the additive classical decomposition:

P[t] = T[t] + S[t] + R[t]

where T[t] is a smooth trend, S[t] is a periodic seasonal component (period = 12), and R[t] is the residual. I estimate the three components as follows:

  1. Trend via a centred 2×12 moving average (a 12-month MA averaged with a 1-month lead to keep it centred on integer indices). This removes the seasonal frequency exactly for period-12 data.
  2. Seasonal as the mean of P[t] - T[t] for each calendar month, centred so that the twelve seasonal factors sum to zero.
  3. Residual as R[t] = P[t] - T[t] - S[t].

The average seasonal pattern is not huge in shrimp (peak-to-trough is on the order of a few cents) but it is consistent: prices tend to firm into the winter holiday / Lent run-up and ease through late summer. On a low-margin protein that’s a meaningful signal.

Once the trend and seasonal components are removed, the residual series R[t] should look roughly like noise. In practice there’s still structure — the 2023 collapse left a visible negative residual cluster — but for a one-page model this is an acceptable baseline.

A seasonal forecast

With decomposition in hand, the simplest honest forecast is:

  1. Extrapolate the trend linearly from an OLS fit on the last 24 months of T[t] (a localised linear trend; this is the “LOESS-lite” way of avoiding long-memory bias in the slope).
  2. Reapply the fitted seasonal factor for the forecast month.
  3. Build a 95% interval from the residual standard deviation: ± 1.96 · σ_R · sqrt(h) in the spirit of a random-walk error (conservative for the shorter horizons; simple).
P_hat[t+h] = T_hat[t+h] + S[month(t+h)]
CI_95%     = P_hat[t+h] ± 1.96 · σ_R · sqrt(h)

Summary statistics, computed client-side from the raw series so every number here is live with the chart:

What the decomposition gets right — and where it falls short

Right.

  • Captures the periodic seasonal pattern that a random walk with drift ignores entirely.
  • Produces a point forecast that respects the calendar month you’re projecting into.
  • Uses only elementary statistics, and is trivially reproducible.

Wrong.

  • The trend is assumed locally linear. A regime change (another Ecuador supply surge, disease outbreak, tariff shock) invalidates the extrapolation immediately.
  • Residual volatility is treated as constant. Shrimp has clear ARCH / GARCH dynamics.
  • No exogenous regressors — feed costs (soymeal, fishmeal), FX (USD / EUR, BRL), freight indices, and inventories all carry information the pure decomposition throws away.

A reasonable next step is SARIMA(p,d,q)(P,D,Q)12 selected by information criteria, followed by a SARIMAX that adds exogenous regressors — or moving directly to a state-space formulation where the seasonal component evolves rather than being fixed.

Takeaways

  1. Decompose before you model. Most of the intuition about a seasonal series comes from separating trend, seasonality, and residual and looking at each piece. If the trend is drifting or the seasonal factor is shrinking, a plain ARIMA will struggle no matter how well-specified.
  2. Classical decomposition is a baseline, not a model. It produces a defensible forecast and a set of residuals you can hand to an ARCH/GARCH test. If your fancier model can’t beat it, you’re adding complexity without value.
  3. Know your market’s cycle length. Shrimp’s oversupply episodes play out over 12–18 months. That’s longer than the horizon at which a seasonal decomposition is well-posed; you need a second, slower component (inventory, investment, disease) to call the cycle.