Article Image
Article Image
read

Modeling Options commodities with Black 76 and QuantLib

Mathematics and Assumptions

  • Use the Black-Scholes equation to price commodity futures options.
  • We will not model commodities as the same as equity options because the prices do not fluctuate as much. Therefore, the commodiities will not be in a stochastic process.

  • Futures prices are log-normally distributed.
  • All options will be exercised at maturity.
  • Volatility is not constant (depends on time to maturity)

Use a stochastic process to model the time, t, and Ft:

Valuing a Call option

Valuing a Put option

Processes

Walkthrough example

Let’s assume that we want to price a 3000 copper future on a call option. The date till maturity (T) is 31 days with a volatility of 35 or 0.35 and annual interest of 0.005. The strike price (X) is 3000 while the futures price is 2900.

Let’s solve for D1 to fnd D2 first.

where F = 2900 and X = 3000 The logarithm base e for F/X or futures price over strike price is: -0.03390….

Sigma squared with respect to T/2 is: 0.0052019625 volaitlity is 0.35 multiplied to interest rate and time to maturity 31/365 = 0.08493

solve for T gives us: 0.1019996

The result for D1 is:

Solving for D2:

through cumulative normal distribution, we get (d1) = 0.38922098 (d2) = 0.35073028

Terminal price = (2900 * 0.38922098) - (3000 * 0.308547) = 203.099842

Let’s assume discount factor of 0.99

Calculate priceof option 0.99 * 203.099842 = 201.10

QuantLib Implementation

Instantiate the global data parameters and nacessary library packages.

    import QuantLib as ql
    import pandas as pd
    import math
    
    # Global Data
    calendar = ql.UnitedStates()
    businessConvention = ql.ModifiedFollowing
    settlementDays = 0
    daysCount = ql.ActualActual(ql.ActualActual.Bond)

Treasury Notes Futures Contract (2-Year Note)

Option on Treasury Futures Contracts. For these examples, we will assume the same volatility, strike, and spot price to showcase the differentiation of the option greeks.

2-Year note yields.

    # 2-Year Note 

    interestRate = 0.003
    calcDate = ql.Date(1,12,2023)
    yieldCurve = ql.FlatForward(calcDate, interestRate, daysCount, ql.Compounded, ql.Continuous)

    ql.Settings.instance().evaluationDate = calcDate
    optionMaturityDate = ql.Date(24,12,2025)
    strike = 100
    spot = 125 # spot price is the futures price
    volatility = 20/100.
    optionType = ql.Option.Call

    discount = yieldCurve.discount(optionMaturityDate)
    strikepayoff = ql.PlainVanillaPayoff(optionType, strike)
    T = yieldCurve.dayCounter().yearFraction(calcDate, optionMaturityDate)

    stddev = volatility*math.sqrt(T)

    black = ql.BlackCalculator(strikepayoff, spot, stddev, discount)

    print("%-20s: %4.4f" %("Option Price for Treasury Futures Contract (2-Year Note)", black.value() )) 
    print("%-20s: %4.4f" %("Delta", black.delta(spot)))
    print("%-20s: %4.4f" %("Gamma", black.gamma(spot)))
    print("%-20s: %4.4f" %("Theta", black.theta(spot, T))) 
    print("%-20s: %4.4f" %("Vega", black.vega(T)))
    print("%-20s: %4.4f" %("Rho", black.rho( T)))
3-Year Note yields.

    # 3-Year Note

    interestRate = 0.003
    calcDate = ql.Date(1,12,2023)
    yieldCurve = ql.FlatForward(calcDate, interestRate, daysCount, ql.Compounded, ql.Continuous)

    ql.Settings.instance().evaluationDate = calcDate
    optionMaturityDate = ql.Date(24,12,2026)
    strike = 100
    spot = 125 # spot price is the futures price
    volatility = 20/100.
    optionType = ql.Option.Call

    discount = yieldCurve.discount(optionMaturityDate)
    strikepayoff = ql.PlainVanillaPayoff(optionType, strike)
    T = yieldCurve.dayCounter().yearFraction(calcDate, optionMaturityDate)

    stddev = volatility*math.sqrt(T)
    black = ql.BlackCalculator(strikepayoff, spot, stddev, discount)

    print("%-20s: %4.4f" %("Option Price for Treasury Futures Contract (3-Year Note)", black.value() )) 
    print("%-20s: %4.4f" %("Delta", black.delta(spot)))
    print("%-20s: %4.4f" %("Gamma", black.gamma(spot)))
    print("%-20s: %4.4f" %("Theta", black.theta(spot, T))) 
    print("%-20s: %4.4f" %("Vega", black.vega(T)))
    print("%-20s: %4.4f" %("Rho", black.rho( T)))
5-Year Note yields.

    # 5-Year Note

    interestRate = 0.003
    calcDate = ql.Date(1,12,2023)
    yieldCurve = ql.FlatForward(calcDate, interestRate, daysCount, ql.Compounded, ql.Continuous)

    ql.Settings.instance().evaluationDate = calcDate
    optionMaturityDate = ql.Date(24,12,2028)
    strike = 100
    spot = 125 # spot price is the futures price
    volatility = 20/100.
    optionType = ql.Option.Call

    discount = yieldCurve.discount(optionMaturityDate)
    strikepayoff = ql.PlainVanillaPayoff(optionType, strike)
    T = yieldCurve.dayCounter().yearFraction(calcDate, optionMaturityDate)

    stddev = volatility*math.sqrt(T)

    black = ql.BlackCalculator(strikepayoff, spot, stddev, discount)

    print("%-20s: %4.4f" %("Option Price for Treasury Futures Contract (5-Year Note)", black.value() )) 
    print("%-20s: %4.4f" %("Delta", black.delta(spot)))
    print("%-20s: %4.4f" %("Gamma", black.gamma(spot)))
    print("%-20s: %4.4f" %("Theta", black.theta(spot, T))) 
    print("%-20s: %4.4f" %("Vega", black.vega(T)))
    print("%-20s: %4.4f" %("Rho", black.rho( T)))
10-Year Note yields.

    # 10-Year Note

    interestRate = 0.003
    calcDate = ql.Date(1,12,2023)
    yieldCurve = ql.FlatForward(calcDate, interestRate, daysCount, ql.Compounded, ql.Continuous)

    ql.Settings.instance().evaluationDate = calcDate
    optionMaturityDate = ql.Date(24,12,2033)
    strike = 100
    spot = 125 # futures price
    volatility = 20/100.
    optionType = ql.Option.Call

    discount = yieldCurve.discount(optionMaturityDate)
    strikepayoff = ql.PlainVanillaPayoff(optionType, strike)
    T = yieldCurve.dayCounter().yearFraction(calcDate, optionMaturityDate)

    stddev = volatility*math.sqrt(T)
    black = ql.BlackCalculator(strikepayoff, spot, stddev, discount)

    print("%-20s: %4.4f" %("Option Price for Treasury Futures Contract (10-Year Note)", black.value() )) 
    print("%-20s: %4.4f" %("Delta", black.delta(spot)))
    print("%-20s: %4.4f" %("Gamma", black.gamma(spot)))
    print("%-20s: %4.4f" %("Theta", black.theta(spot, T))) 
    print("%-20s: %4.4f" %("Vega", black.vega(T)))
    print("%-20s: %4.4f" %("Rho", black.rho( T)))
Natural Gas Futures Option.

    # Natural Gas Futures Option

    interestRate = 0.0015
    calcDate = ql.Date(23,9,2015)
    yieldCurve = ql.FlatForward(calcDate, interestRate, daysCount, ql.Compounded, ql.Continuous)

    ql.Settings.instance().evaluationDate = calcDate
    T = 31/365.

    strike = 3.3
    spot = 2.4360
    volatility = 0.4251
    contract = ql.Option.Call

    discount = yieldCurve.discount(T)
    strikepayoff = ql.PlainVanillaPayoff(contract, strike)
    stddev = volatility*math.sqrt(T)

    strikepayoff = ql.PlainVanillaPayoff(contract, strike)
    black = ql.BlackCalculator(strikepayoff, spot, stddev, discount)

    print("%-20s: %4.4f" %("Option Price for Natural Gas Futures ", black.value() )) 
    print("%-20s: %4.4f" %("Delta", black.delta(spot)))
    print("%-20s: %4.4f" %("Gamma", black.gamma(spot)))
    print("%-20s: %4.4f" %("Theta", black.theta(spot, T))) 
    print("%-20s: %4.4f" %("Vega", black.vega(T)))
    print("%-20s: %4.4f" %("Rho", black.rho( T)))        
Gold Futures Options (31 days).

    # Gold Futures Option for April 2023
    # Time to maturity is 31 days; 31/365

    interestRate = 0.0015
    calcDate = ql.Date(23,9,2015)
    yieldCurve = ql.FlatForward(calcDate, interestRate, daysCount, ql.Compounded, ql.Continuous)

    ql.Settings.instance().evaluationDate = calcDate
    T = 31/365.

    strike = 2000
    spot = 1867.20
    volatility = 0.11
    contract = ql.Option.Call

    discount = yieldCurve.discount(T)
    strikepayoff = ql.PlainVanillaPayoff(contract, strike)
    stddev = volatility*math.sqrt(T)

    strikepayoff = ql.PlainVanillaPayoff(contract, strike)
    black = ql.BlackCalculator(strikepayoff, spot, stddev, discount)

    print("%-20s: %4.4f" %("Option Price for Natural Gas Futures ", black.value() )) 
    print("%-20s: %4.4f" %("Delta", black.delta(spot)))
    print("%-20s: %4.4f" %("Gamma", black.gamma(spot)))
    print("%-20s: %4.4f" %("Theta", black.theta(spot, T))) 
    print("%-20s: %4.4f" %("Vega", black.vega(T)))
    print("%-20s: %4.4f" %("Rho", black.rho( T)))
Blog Logo

Nijaz Kovacevic


Published

Image

Nijaz Kovacevic

Quantitative Analysis - Software Engineering - Mathematics

Back to Overview