Commodity Markets and Futures › Analyzing Futures Term Structure
Quantitative FinanceAll chapters Commodity Markets and Futures › Analyzing Futures Term StructureOne section · Sections in this chapter7 / 12 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Let's build tools to analyze commodity futures term structures and visualize contango and backwardation conditions.
import numpy as np
# Set random seed for reproducibility
np.random.seed(42)We'll create a function to generate theoretical futures curves under different market conditions:
def theoretical_futures_price(
spot, time_to_expiry, risk_free_rate, storage_cost, convenience_yield
):
"""
Calculate theoretical futures price using cost of carry model.
Parameters:
- spot: Current spot price
- time_to_expiry: Time to delivery in years
- risk_free_rate: Annualized risk-free rate
- storage_cost: Annualized storage cost rate
- convenience_yield: Annualized convenience yield rate
Returns:
- Theoretical futures price
"""
net_cost = risk_free_rate + storage_cost - convenience_yield
return spot * np.exp(net_cost * time_to_expiry)# Define time horizons (months to expiry)
months = np.array([1, 2, 3, 6, 9, 12, 18, 24])
times = months / 12 # Convert to years
# Current spot price
spot_price = 80 # e.g., dollars per barrel for crude oil
# Market parameters
risk_free_rate = 0.05 # 5% annual
storage_cost = 0.03 # 3% annual storage cost
# Scenario 1: Contango (low convenience yield)
low_convenience_yield = 0.02
contango_prices = [
theoretical_futures_price(
spot_price, t, risk_free_rate, storage_cost, low_convenience_yield
)
for t in times
]
# Scenario 2: Backwardation (high convenience yield)
high_convenience_yield = 0.15
backwardation_prices = [
theoretical_futures_price(
spot_price, t, risk_free_rate, storage_cost, high_convenience_yield
)
for t in times
]
# Scenario 3: Flat curve (convenience yield equals net carry cost)
balanced_convenience_yield = risk_free_rate + storage_cost
flat_prices = [
theoretical_futures_price(
spot_price, t, risk_free_rate, storage_cost, balanced_convenience_yield
)
for t in times
]Now let's visualize the three term structure scenarios:


# Select a month for analysis
target_idx = 3
target_month = months[target_idx]
# Calculate basis for this horizon
basis_contango = spot_price - contango_prices[target_idx]
basis_backwardation = spot_price - backwardation_prices[target_idx]Basis Analysis (Spot - Futures): -------------------------------------------------- Spot Price: $80.00 Contango (6-month): Futures: $82.44 Basis: $-2.44 (negative = contango) Backwardation (6-month): Futures: $77.25 Basis: $2.75 (positive = backwardation)
The basis values confirm our term structure shapes. In contango, the negative basis reflects futures prices above spot. In backwardation, the positive basis shows spot prices exceeding futures.
Calculating Roll Yield
Roll yield is the return generated when rolling futures positions forward. Let's calculate the annualized roll yield for different term structure conditions:
def calculate_roll_yield(front_price, back_price, days_between):
"""
Calculate annualized roll yield from calendar spread.
Parameters:
- front_price: Near-term futures price
- back_price: Far-term futures price
- days_between: Days between contract expirations
Returns:
- Annualized roll yield as a percentage
"""
spread_return = (front_price - back_price) / front_price
annualized = spread_return * (365 / days_between)
return annualized * 100 # Return as percentage# Calculate roll yields for 1-month to 2-month roll
days_between = 30
contango_roll = calculate_roll_yield(
contango_prices[0], contango_prices[1], days_between
)
backwardation_roll = calculate_roll_yield(
backwardation_prices[0], backwardation_prices[1], days_between
)
flat_roll = calculate_roll_yield(flat_prices[0], flat_prices[1], days_between)Annualized Roll Yield Analysis: -------------------------------------------------- Contango: -6.10% Backwardation: +7.08% Flat: +0.00% Negative roll yield = cost of maintaining long futures position Positive roll yield = benefit of maintaining long futures position

The roll yield calculations highlight why commodity investors care deeply about term structure. In persistent contango, continuously rolling long futures positions erodes returns. In persistent backwardation, roll yield adds to returns.