Class CommodityCurve
java.lang.Object
com.quantfinlib.commodities.CommodityCurve
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-impliedu - y(storage cost minus convenience yield) isln(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 TypeMethodDescriptiondoubleannualizedRollYield(double nearYears, double farYears) Annualized roll yield earned by a LONG rolling fromnearYearstofarYears: positive in backwardation.doubleimpliedCarry(double tenorYears, double rate) Market-implied storage-minus-convenienceu - y(cc) at the tenor, fromF = S * exp((r + u - y) t).booleanStrictly downward at every adjacent pillar pair.booleanStrictly upward at every adjacent pillar pair (deferred above near).static CommodityCurveof(double spot, double[] tenorYears, double[] prices) doubleprice(double tenorYears) Interpolated futures price; throws beyond the pillars (no extrapolation).doublespot()
-
Method Details
-
of
- Parameters:
spot- spot price, > 0tenorYears- ascending futures tenors, all > 0prices- 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 fromnearYearstofarYears: positive in backwardation. -
impliedCarry
public double impliedCarry(double tenorYears, double rate) Market-implied storage-minus-convenienceu - y(cc) at the tenor, fromF = 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()
-