Commodity Markets and Futures › Hedging Example: Crude Oil Producer

Michael BrenndoerferNovember 12, 20259 min read
Quantitative FinanceAll chapters
Part 3 of 15Forwards, Futures, and Options
Chapter 16Commodity Markets and Futures › Hedging Example: Crude Oil Producer
Reading section 8 of 12 · Hedging Example: Crude Oil Producer · 9 minSection 8 of 12 · 9 min

Book contents

Section 8 of 12 · 9 min read

Commodity Markets and Futures › Hedging Example: Crude Oil ProducerOne section · Sections in this chapter8 / 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 work through a complete hedging example for an oil producer seeking to lock in prices for future production.

In[15]:
Code
# Producer's situation
production_volume = 100000  # barrels to hedge
current_spot = 75.00  # current spot price per barrel
futures_price = 77.50  # 6-month futures price
contract_size = 1000  # barrels per futures contract

# Calculate number of contracts needed
num_contracts = production_volume / contract_size

# Simulate price scenarios at delivery
np.random.seed(123)
price_scenarios = np.linspace(50, 100, 21)  # Range of possible prices


# Calculate outcomes
def calculate_hedge_outcome(
    final_spot, futures_price, volume, num_contracts, contract_size
):
    """Calculate total revenue and effective price from hedged position."""
    # Revenue from physical sales
    physical_revenue = final_spot * volume

    # Profit/loss from futures (short position profits when prices fall)
    futures_pnl = (futures_price - final_spot) * num_contracts * contract_size

    # Total revenue
    total_revenue = physical_revenue + futures_pnl

    # Effective price per barrel
    effective_price = total_revenue / volume

    return physical_revenue, futures_pnl, total_revenue, effective_price
In[16]:
Code
import pandas as pd

# Calculate outcomes for all price scenarios
results = []
for spot in price_scenarios:
    physical, futures_pnl, total, effective = calculate_hedge_outcome(
        spot, futures_price, production_volume, num_contracts, contract_size
    )
    results.append(
        {
            "final_spot": spot,
            "physical_revenue": physical / 1e6,  # Convert to millions
            "futures_pnl": futures_pnl / 1e6,
            "total_revenue": total / 1e6,
            "effective_price": effective,
        }
    )

results_df = pd.DataFrame(results)
Out[17]:
Visualization
Line chart showing hedged revenue constant while unhedged revenue varies with spot price.
Revenue comparison between unhedged and hedged positions across spot price scenarios. The hedge locks in total revenue regardless of final spot price.
Line chart showing hedged effective price constant at futures price while unhedged varies.
Effective price received by the producer. Unhedged position receives spot price while hedged position locks in the futures price.
Out[18]:
Visualization
Area and line chart showing physical revenue (blue fill), futures P&L (red line), and total hedged revenue (green line) as functions of final spot price, illustrating how futures gains offset physical revenue losses.
Decomposition of hedged position outcomes showing physical revenue, futures P&L, and total revenue across price scenarios. When spot prices fall, futures gains offset physical revenue losses. When spot prices rise, futures losses offset physical revenue gains. The total revenue remains constant.
In[19]:
Code
# Analyze specific price scenarios
low_scenario = 60
high_scenario = 90

# Retrieve effective prices for these scenarios
eff_price_low = results_df.loc[
    results_df["final_spot"] == low_scenario, "effective_price"
].values[0]
eff_price_high = results_df.loc[
    results_df["final_spot"] == high_scenario, "effective_price"
].values[0]

# Calculate locked revenue
locked_revenue = futures_price * production_volume / 1e6
Out[20]:
Console
Hedge Analysis Summary:
--------------------------------------------------
Production volume: 100,000 barrels
Futures contracts sold: 100
Locked-in price: $77.50/barrel
Locked-in revenue: $7.75 million

Sample outcomes:
  If spot falls to $60: effective price = $77.50
  If spot rises to $90: effective price = $77.50

The visualization demonstrates the core trade-off of hedging. The producer sacrifices the potential to benefit from price increases in exchange for protection against price declines. The hedge turns uncertain future revenue into a known quantity.

Calculating the Optimal Hedge Ratio

When the commodity being hedged doesn't perfectly match the futures contract, we need to calculate the optimal hedge ratio using historical price data:

In[21]:
Code
# Simulate historical price data for spot and futures
n_obs = 252  # One year of daily data

# Generate correlated price changes
correlation = 0.92  # Typical correlation between spot and futures

vol_spot = 0.02  # Daily spot volatility
vol_futures = 0.025  # Daily futures volatility

# Create correlated returns
cov_matrix = np.array(
    [
        [vol_spot**2, vol_spot * vol_futures * correlation],
        [vol_spot * vol_futures * correlation, vol_futures**2],
    ]
)
mean_returns = [0, 0]

returns = np.random.multivariate_normal(mean_returns, cov_matrix, n_obs)
spot_returns = returns[:, 0]
futures_returns = returns[:, 1]

# Convert to price levels
spot_prices = 75 * np.exp(np.cumsum(spot_returns))
futures_prices = 77 * np.exp(np.cumsum(futures_returns))
In[22]:
Code
# Calculate optimal hedge ratio
def calculate_optimal_hedge_ratio(spot_changes, futures_changes):
    """
    Calculate minimum variance hedge ratio.

    h* = correlation * (std_spot / std_futures)
    """
    correlation = np.corrcoef(spot_changes, futures_changes)[0, 1]
    std_spot = np.std(spot_changes)
    std_futures = np.std(futures_changes)

    optimal_ratio = correlation * (std_spot / std_futures)

    return optimal_ratio, correlation, std_spot, std_futures


# Calculate price changes
spot_changes = np.diff(spot_prices)
futures_changes = np.diff(futures_prices)

h_star, corr, std_s, std_f = calculate_optimal_hedge_ratio(
    spot_changes, futures_changes
)
Out[23]:
Visualization
Scatter plot of daily spot price changes on the y-axis versus futures price changes on the x-axis, with a red regression line whose slope equals the optimal hedge ratio.
Scatter plot of daily spot price changes versus futures price changes. The positive correlation between the two series justifies using futures to hedge spot exposure. The regression line slope represents the optimal hedge ratio, indicating how many futures units to sell per unit of spot exposure.
In[24]:
Code
# Calculate contracts needed
naive_contracts = production_volume / contract_size
optimal_contracts = h_star * naive_contracts
Out[25]:
Console
Optimal Hedge Ratio Analysis:
--------------------------------------------------
Correlation (spot, futures): 0.9235
Spot price volatility: $1.4884
Futures price volatility: $1.6636

Optimal hedge ratio (h*): 0.8263

Interpretation:
  To hedge 100,000 barrels of spot exposure,
  use 83 futures contracts (each = 1,000 barrels)

The optimal hedge ratio of approximately 0.74 indicates that the hedge requires fewer futures contracts than a naive one-to-one hedge. This occurs because futures prices are more volatile than spot prices in our simulated data, so fewer contracts are needed to offset the same dollar risk.

Hedge Effectiveness

We can measure how well the hedge performs by comparing the variance of unhedged and hedged positions:

In[26]:
Code
def calculate_hedge_effectiveness(spot_changes, futures_changes, hedge_ratio):
    """
    Calculate hedge effectiveness as variance reduction.

    Effectiveness = 1 - Var(hedged) / Var(unhedged)
    """
    # Unhedged variance is just spot variance
    var_unhedged = np.var(spot_changes)

    # Hedged position: spot - h * futures
    hedged_changes = spot_changes - hedge_ratio * futures_changes
    var_hedged = np.var(hedged_changes)

    effectiveness = 1 - (var_hedged / var_unhedged)

    return effectiveness, var_unhedged, var_hedged


# Calculate for different hedge ratios
hedge_ratios = np.linspace(0, 1.5, 31)
effectiveness_values = []

for h in hedge_ratios:
    eff, _, _ = calculate_hedge_effectiveness(spot_changes, futures_changes, h)
    effectiveness_values.append(eff)

# Get effectiveness at optimal ratio
opt_eff, var_unh, var_h = calculate_hedge_effectiveness(
    spot_changes, futures_changes, h_star
)
Out[27]:
Visualization
Line chart showing hedge effectiveness peaking at the optimal hedge ratio around 0.74.
Hedge effectiveness as a function of hedge ratio. The curve peaks at the optimal hedge ratio (red dashed line), where variance reduction is maximized. Hedge ratios far from optimal provide less variance reduction.
Out[28]:
Console
Hedge Effectiveness at Optimal Ratio:
--------------------------------------------------
Unhedged variance: 2.215373
Hedged variance:   0.325806
Variance reduction: 85.3%

The optimal hedge removes approximately 85% of price risk.
Remaining risk is basis risk due to imperfect correlation.
Out[29]:
Visualization
Overlapping histogram showing a wider blue distribution for the unhedged position and a narrower green distribution for the hedged position, with dashed vertical lines marking one standard deviation for each.
Distribution of daily P&L for unhedged versus optimally hedged positions. The hedged position shows a much tighter distribution around zero, showing the variance reduction achieved by the hedge. The remaining spread in the hedged distribution represents basis risk.

The hedge effectiveness of approximately 85% indicates that the optimal hedge removes most, but not all, price risk. The remaining 15% represents basis risk arising from imperfect correlation between the spot commodity and the futures contract used for hedging.