Skip to main content

A Small Example Computing Bilateral Trade with a Gravity Model

Mitch Phillipson October 24, 2025


According to USA Trade, Louisiana exported approximately $22 billion worth of soybeans in 2022, accounting for 42.6% of all soybeans exported from the United States that year. However, Louisiana only produced about $575 million of soybeans. This discrepancy is due to the United States recording exports as originating from the last port of exit, rather than the actual location of production. In Louisiana’s case, a significant portion of the soybeans exported through its ports are grown in other states, particularly in the Midwest, and then transported via the Mississippi to Louisiana for export. Our goal is trace this production back to its source using a gravity model. These methods can be extended to see the value soybeans traveling from Wisconsin to China.

Example Setup

We are going to consider a model with three states (si)(s_i), one good (gg), and three trade partners (cjc_j). For each state, we assume we have the following data for state sis_i, the for good:

  1. Production demand - did_i
  2. Foreign Export demand - xix_i
  3. Domestic Supply - yiy_i
  4. Foreign Import Supply - mim_i

Where total demand equals total supply, or

di+xi=yi+mi. d_i + x_i = y_i + m_i.

Additionally, we have the following data for each trade partner cjc_j:

  1. Total exports going to partner cjc_j - XjX_j
  2. Total imports coming from partner cjc_j - MjM_j

Finally, for the gravity model we need some metric determining trade impedances. We will use τ(a,b)\tau(a,b) to denote the trade impedance between locations aa and bb, where

  • τ(a,a)=1\tau(a,a) = 1
  • τ(a,b)=τ(b,a)\tau(a,b) = \tau(b,a)
  • τ(a,b)>1\tau(a,b) > 1 for aba \neq b if aa and bb are trade connected
  • τ(a,b)=0\tau(a,b) = 0 if aa and bb are not trade connected.

In our example we take the other countries to be exogenous trade partners, or τ(ci,cj)=0\tau(c_i,c_j) = 0 for i,ji, j.

Region did_i xix_i yiy_i mim_i
s1s_1 30 15 40 5
s2s_2 20 3 18 5
s3s_3 15 17 30 2
c1c_1 5 10
c2c_2 7 15
c3c_3 10 20

If you would like to follow along with the code, you can find it in the GitHub repository, in particular the file blog_example.jl.

Estimating Trade Flow

In order to apply the gravity model, we need to estimate the trade flows between each state and trade partner. To do this we will use trade and production shares of the input data. Let F(x,y)F(x,y) be the estimated flow of goods from location xx to location yy. Note that F(ci,cj)=0F(c_i,c_j) = 0 for all i,ji,j since we are treating the trade partners as exogenous.

We will first consider the flow of goods between states. For this calculation we use domestic demand in state sis_i which can be calculated as di+ximid_i + x_i - m_i. The domestic flow is then given using production shares as follows:

F(sorigin,sdest)=(Domestic Demand in sorigin)(Domestic Supply in sdest)Total Domestic Production=(dorigin+xoriginmorigin)ydestiyi=yoriginydestiyi\begin{aligned} F(s_\text{origin}, s_\text{dest}) & = \frac{(\text{Domestic Demand in $s_\text{origin}$})\cdot(\text{Domestic Supply in $s_\text{dest}$})}{\text{Total Domestic Production}} \\ & = \frac{ (d_\text{origin} + x_\text{origin} - m_\text{origin}) \cdot y_\text{dest} }{ \sum_{i} y_i } \\ &= \frac{y_\text{origin} \cdot y_\text{dest}}{\sum_{i} y_i} \end{aligned}

The import flow (country to state) is calculated using foreign import supply shares:

F(corigin,sdest)=Total Imports from coriginTotal ImportsImports into sdest=MoriginjMjmdest\begin{aligned} F(c_\text{origin}, s_\text{dest}) & = \frac{\text{Total Imports from $c_\text{origin}$}}{\text{Total Imports}} \cdot \text{Imports into $s_\text{dest}$} \\ & = \frac{M_\text{origin}}{\sum_{j} M_j} \cdot m_\text{dest} \end{aligned}

Similarly, the export flow (state to country) is calculated using foreign export demand shares:

F(sorigin,cdest)=Total Exports to cdestTotal ExportsExports from sorigin=XdestjXjxorigin\begin{aligned} F(s_\text{origin}, c_\text{dest}) & = \frac{\text{Total Exports to $c_\text{dest}$}}{\text{Total Exports}} \cdot \text{Exports from $s_\text{origin}$} \\ & = \frac{X_\text{dest}}{\sum_{j} X_j} \cdot x_\text{origin} \end{aligned}

Notice the following properties preserved by the flow function: - Domestic supply: iF(si,sj)=yi \sum_{i} F(s_i, s_j) = y_i - Domestic Demand: jF(si,sj)=yi=di+ximi \sum_{j} F(s_i, s_j) = y_i = d_i + x_i - m_i - Foreign Import Supply: jF(cj,si)=mi \sum_{j} F(c_j, s_i) = m_i - Foreign Export Demand: jF(si,cj)=xi \sum_{j} F(s_i, c_j) = x_i

We now have an estimate for the trade flows. Why not stop here? Why is the gravity model needed? There are a few issues with this data. First, production do not take into account trade impedances. For example, if state s1s_1 is very far from trade partner s3s_3, we would expect less trade between them than production shares estimate. Second, the production shares are too high. Most soybeans grown in Wisconsin are used in Wisconsin as cattle feed. A gravity model solves both of these issues by adjusting the flows based on trade impedances and scaling the flows to match observed trade data.

An Overview of the Gravity Model

Our gravity model is a CGE model implemented in MPSGE. The general idea is to apply trade impedances to the network of flows given by FF and find a new equilibrium point FF'.

To further this discussion we need to introduce prices. Define the following:

  • PYiPY_i be the output price in state sis_i
  • PMiPM_i be the import price coming from country cic_i
  • PFXPFX be the foreign exchange price
  • PAiPA_i be the price of absorption in state sis_i

Absorption in state sdests_\text{dest} is defined as all goods that are consumed within the state, regardless of origin. This includes both domestic goods produced in other states and foreign goods imported from trade partners. It is given by

Abdest=iF(si,sdest)+jF(cj,sdest). Ab_\text{dest} = \sum_{i} F(s_i, s_\text{dest}) + \sum_{j} F(c_j, s_\text{dest}).

This identity defines the key sector in our gravity model, AiA_i the absorption sector in state sis_i. This sector outputs goods at the following price and quantity,

  • Price: PAdestPA_\text{dest}
  • Reference Quantity: AbdestAb_\text{dest}

For inputs into this sector, we have a choice we can either use domestic goods or foreign goods. This choice introduces a nest in our cost function. For each choice we’ll either specify an elasticity or a price and quantity.

  • Domestic: 2σ2\sigma
    • Within State
      • Price: PYiPY_i
      • Reference Quantity: τ(sdest,sdest)F(sdest,sdest)\tau(s_\text{dest}, s_\text{dest})\cdot F(s_\text{dest}, s_\text{dest})
      • Reference Price: 1τ(sdest,sdest)\frac{1}{\tau(s_\text{dest}, s_\text{dest})}
    • Domestically: 4σ4\sigma, for each state soriginsdests_\text{origin} \neq s_\text{dest}
      • Price: PYoriginPY_\text{origin}
      • Reference Quantity: τ(sorigin,sdest)F(sorigin,sdest)\tau(s_\text{origin}, s_\text{dest})\cdot F(s_\text{origin}, s_\text{dest})
      • Reference Price: 1τ(sorigin,sdest)\frac{1}{\tau(s_\text{origin}, s_\text{dest})}
  • Foreign: 2σ2\sigma, for each country coriginc_\text{origin}
    • Price: PMoriginPM_\text{origin}
    • Reference Quantity: τ(corigin,sdest)F(corigin,sdest)\tau(c_\text{origin}, s_\text{dest})\cdot F(c_\text{origin}, s_\text{dest})
    • Reference Price: 1τ(corigin,sdest)\frac{1}{\tau(c_\text{origin}, s_\text{dest})}

This is written in MPSGE syntax, and one natural question is what do Reference Quantity and Reference Price mean? The Reference Price is adjusts the price of the good, in particular this appears in the cost function as:

PReference Price. \frac{P}{\text{Reference Price}}.

Since we set a reference price of 1τ\frac{1}{\tau}, this has the effect of multiplying the price by the trade impedance. Thus higher trade impedances lead to higher effective prices, which leads to less consumption of that good. The Reference Quantity is the total value of the good consumed. Since we increase the price by the trade impedance, we also need to scale the quantity by the trade impedance to keep the total value of the good consumed the same.

In addition to the absorption sector, we have several consumers in the model:

  • Exports for each country cjc_j
    • Demands: 2σ2\sigma for each state sis_i
      • Price: PYiPY_i
      • Reference Quantity: τ(si,cj)F(si,cj)\tau(s_i, c_j)\cdot F(s_i, c_j)
      • Reference Price: 1τ(si,cj)\frac{1}{\tau(s_i, c_j)}
    • Endowments:
      • Price: PFXPFX, Quantity: iF(si,cj)\sum_i F(s_i,c_j)
  • Representative Agent
    • Demands
      • Price: PFXPFX
      • Reference Quantity: Sum of endowment quantities
    • Endowments:
      • Price: PFXPFX, Quantity: Total flow of goods
      • Price: PYjPY_j, Quantity: (iF(si,sj)+(iF(ci,sj))SYj\left(\sum_{i} F(s_i,s_j) + (\sum_i F(c_i,s_j)\right)\cdot SY_j
      • Price: PMiPM_i, Quantity: (jF(ci,sj))SMi\left(\sum_{j} F(c_i,s_j)\right)\cdot SM_i
  • State Demands: For each state sis_i
    • Demands
      • Price: PAiPA_i
      • Reference Quantity: ABiAB_i
    • Endowments
      • Price: PFXPFX, Quantity: ABiAB_i

Two auxiliary variables were used in the model to help with scaling, SYiSY_i for each state ii and SMjSM_j for each country jj. These variables let us link PYPY and PMPM, holding them both into a ratio with PFXPFX. The constraint for SYiSY_i is given by:

SYiPYi=syiPFX SY_i \cdot PY_i = sy_i \cdot PFX

Where syisy_i is a model parameter that allows us to scale the output price PYiPY_i relative to the foreign exchange price PFXPFX. The constraint for SMjSM_j is given by:

SMjPMj=PFX SM_j \cdot PM_j = PFX

This fully describes the gravity model. The final step is to run the model and extract the new trade flows FF'. These new trade flows will take into account trade impedances and will be scaled to match observed trade data.

The process to run the model is as follows:

  1. At the benchmark to ensure we starting at an equilibrium.
  2. Set trade impedances and fix SYiSY_i and SMjSM_j to maintain a ratio between prices. This ensures the model stays convex.
  3. Unfix SYiSY_i and SMjSM_j to allow prices to adjust.
  4. Finally, we extract the new trade flows FF'.

Results

Let’s start by identifying locations of the states and countries. The following graph shows the locations of each state and country in our example.

We define the trade impedance to be one plus the Euclidean distance between locations. We offset by one to ensure that trade impedances are at least one.

Before we implement our gravity model, let’s make some predictions.

  1. Within state trade should be much higher in the gravity model. We expect production shares to underestimate within state trade as most goods are consumed locally.
  2. We expect overall trade between s1s_1 and s3s_3 to decrease as they are the furthest apart.
  3. c3c_3 should prioritize trade with s3s_3
  4. The share of goods flowing from c1c_1 to s1s_1 should be higher than the share of goods flowing from c2c_2 to s1s_1 since c1c_1 is closer to s1s_1.

Here is what the model predicts for import values:

This matches really well with our predictions. Trade between s1s_1 and s3s_3 has decreased significantly, while within state trade has increased. Additionally, c3c_3 is primarily trading with s3s_3, and c1c_1 is trading proportionally more with s1s_1 than c2c_2.

For completeness, here are the export values predicted by the model:

Similar conclusions can be drawn from the export values.

I am working on an interactive dashboard to explore the results of this model. However, given other responsibilities, this may take some time. I will post an update here when it is ready.

Next Steps

This is a small example meant to illustrate the mechanics of applying a gravity model to trace production back to its source. The next step is to scale this up to a full model with all US states and major trade partners. Additionally, I would like to explore different methods for estimating initial trade flows beyond production shares.