Class CommodityCurve

java.lang.Object
com.quantfinlib.commodities.CommodityCurve

public final class CommodityCurve extends Object
COMMODITY futures curve — where the P&L of a commodity position mostly does NOT come from being right about the spot price. A futures curve in CONTANGO (upward: deferred contracts above spot) charges a long position negative ROLL YIELD every month — selling the expiring cheap contract to buy the deferred rich one — while BACKWARDATION (downward) pays the long for rolling. Over a decade this roll term has dominated most commodity index returns, which is the single most misunderstood fact about the asset class (the USO oil fund's 2020 investors learned it the hard way: spot oil recovered, the contango roll ate the fund anyway).

The numbers this class produces:

  • annualized roll yield between two tenors: ln(F(near)/F(far)) / (far - near) — positive in backwardation (near above far: rolling down the curve pays the long);
  • implied carry versus spot: from the storage-arbitrage relation F = S * exp((r + u - y) * t), the market-implied u - y (storage cost minus convenience yield) is ln(F(t)/S)/t - r. A deeply negative value means the market pays dearly to HOLD the physical (convenience yield — think heating oil before a cold snap);
  • shape tests: isContango()/isBackwardation() across the whole curve, strict at every adjacent pillar pair.

Linear interpolation between pillar prices, no extrapolation (asking for a price beyond the pillars throws — a commodity curve's wings are opinions, not data). Seasonality (natural gas winters) makes whole-curve shape tests false for seasonal commodities by design — use pairwise roll yields there, stated. Research lane.

  • Method Summary

    Modifier and Type
    Method
    Description
    double
    annualizedRollYield(double nearYears, double farYears)
    Annualized roll yield earned by a LONG rolling from nearYears to farYears: positive in backwardation.
    double
    impliedCarry(double tenorYears, double rate)
    Market-implied storage-minus-convenience u - y (cc) at the tenor, from F = S * exp((r + u - y) t).
    boolean
    Strictly downward at every adjacent pillar pair.
    boolean
    Strictly upward at every adjacent pillar pair (deferred above near).
    of(double spot, double[] tenorYears, double[] prices)
     
    double
    price(double tenorYears)
    Interpolated futures price; throws beyond the pillars (no extrapolation).
    double
     

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • of

      public static CommodityCurve of(double spot, double[] tenorYears, double[] prices)
      Parameters:
      spot - spot price, > 0
      tenorYears - ascending futures tenors, all > 0
      prices - futures prices per tenor, all > 0
    • price

      public double price(double tenorYears)
      Interpolated futures price; throws beyond the pillars (no extrapolation).
    • annualizedRollYield

      public double annualizedRollYield(double nearYears, double farYears)
      Annualized roll yield earned by a LONG rolling from nearYears to farYears: positive in backwardation.
    • impliedCarry

      public double impliedCarry(double tenorYears, double rate)
      Market-implied storage-minus-convenience u - y (cc) at the tenor, from F = S * exp((r + u - y) t).
      Parameters:
      rate - the cc risk-free rate to the tenor
    • isContango

      public boolean isContango()
      Strictly upward at every adjacent pillar pair (deferred above near).
    • isBackwardation

      public boolean isBackwardation()
      Strictly downward at every adjacent pillar pair.
    • spot

      public double spot()