cmFutVolatilitySurfaceBuilder

Syntax

cmFutVolatilitySurfaceBuilder(referenceDate, futMaturities, optionExpiries, strikes, optionPrices, payoffTypes, discountCurve, futPriceCurve, [formula="Black76"], [model="SVI"], [surfaceName])

Details

Builds a volatility surface for the commodity futures and options.

Parameters

Notes: All vector inputs must be of equal length.

referenceDate A DATE scalar representing the reference date, i.e., the date when the curve is generated.

futMaturities A DATE vector representing the maturity dates of the future contracts.

optionExpires A DATE vector representing the expiration dates of the option contracts.

strikes A tuple indicating the strike prices, with each element a DOUBLE vector.

optionPrices A tuple indicating the option prices, with each element a DOUBLE vector.

payoffTypes A tuple indicating the pay/off types, with each element a STRING vector. It can be “Call” or “Put”.

Notes: The elements at corresponding positions in vectors strikes, optionPrices and payoffTypes must be of equal length.

discountCurve An IrYieldCurve object representing the discount curve.

futPriceCurve An AssetPriceCurve object representing the future price curve.

formula (optional) A STRING scalar representing the implied volatility formula, which can be:

  • “Black76” (default): Black76 model, generally used for European options.
  • “BAW”: Barone-Adesi Whaley formula, generally used for American options.

model (optional) A STRING scalar specifying the model used to construct the surface. Options:

  • “SVI” (default): Stochastic Volatility Inspired model

  • “SABR”: Stochastic Alpha Beta Rho model

  • “Linear”: Linear interpolation model

  • “CubicSpline”: Cubic spline interpolation model

surfaceName (optional) A STRING scalar representing the surface name.

Returns

A VolatilitySurface object of MKTDATA type.

Examples

Build the volatility surface for copper futures options:

// cu (copper futures options)

referenceDate = 2025.12.02

optionExpiries = [2025.12.25, 2026.01.26, 2026.02.13, 2026.03.25, 2026.04.24, 2026.05.25, 2026.06.24, 2026.07.27]
                

futMaturities  = [2026.01.15, 2026.02.24, 2026.03.16, 2026.04.15, 2026.05.15, 2026.06.15, 2026.07.15, 2026.08.17]

// strikes: list of strike vectors (each vector corresponds to a set of strikes for each option expiration date)
strikes = [
    [64000, 65000, 66000, 67000, 68000, 69000, 70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000, 100000],  //1
    [64000, 65000, 66000, 67000, 68000, 69000, 70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000, 100000], //2
    [64000, 65000, 66000, 67000, 68000, 69000, 70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000, 100000], //3
    [68000, 69000, 70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000, 100000], //4
    [70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000, 100000], //5
    [76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000], //6
    [76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000], //7
    [76000, 77000, 78000, 79000, 80000, 82000, 84000, 86000, 88000, 90000, 92000, 94000, 96000, 98000] //8
]

// optionPrices: A vector of option prices corresponding to each expiration date

optionPrices = [
    [25090, 24090, 23090, 22090, 21090, 20090, 19090, 18090, 17090, 16090, 15090, 14090, 13090, 12092, 11100, 10114, 9138 , 7240 , 5468 , 3898 , 2600 , 1608 , 914  , 482  , 232  , 102  , 40   ], // 1
    [25080, 24080, 23080, 22080, 21080, 20080, 19080, 18080, 17080, 16080, 15084, 14092, 13106, 12132, 11168, 10218, 9290 , 7520 , 5896 , 4462 , 3246 , 2266 , 1516 , 972  , 596  , 350  , 196  ], // 2
    [25030, 24030, 23030, 22030, 21030, 20030, 19030, 18030, 17034, 16044, 15058, 14082, 13116, 12164, 11230, 10316, 9426 , 7736 , 6196 , 4832 , 3660 , 2696 , 1930 , 1338 , 894  , 586  , 370   ], // 3
    [20970, 19970, 18970, 17972, 16980, 15996, 15018, 14052, 13100, 12162, 11244, 10348, 9478 , 7830 , 6336 , 5010 , 3864 , 2906 , 2136 , 1522 , 1066 , 722  , 480   ], // 4
    [18952, 17958, 16974, 15996, 15030, 14076, 13136, 12214, 11314, 10438, 9590 , 7986 , 6522 , 5228 , 4102 , 3150 , 2370 , 1742 , 1254 , 886  , 608   ], // 5
    [12830, 11924, 11040, 10182, 9350 , 7786 , 6372 , 5110 , 4030 , 3104 , 2354 , 1740 , 1270 , 904  ], // 6
    [13176, 12314, 11476, 10670, 9888 , 8416 , 7068 , 5874 , 4814 , 3890 , 3102 , 2450 , 1908 , 1468  ], // 7
    [12848, 11988, 11148, 10346, 9568 , 8102 , 6772 , 5590 , 4546 , 3644 , 2890 , 2260 , 1740 , 1320  ] // 8
]

// payoffTypes: Represented by strings "Put" or "Call"
payoffTypes = [
    take("Call", size(optionPrices[0])),
    take("Call", size(optionPrices[1])),
    take("Call", size(optionPrices[2])),
    take("Call", size(optionPrices[3])),
    take("Call", size(optionPrices[4])),
    take("Call", size(optionPrices[5])),
    take("Call", size(optionPrices[6])),
    take("Call", size(optionPrices[7]))
]

pillar_dates = [
    referenceDate + 2,
    referenceDate + 8,
    referenceDate + 93,
    referenceDate + 185,
    referenceDate + 276,
    referenceDate + 367,
    referenceDate + 732,
    referenceDate + 1099,
    referenceDate + 1463,
    referenceDate + 1828,
    referenceDate + 2558,
    referenceDate + 3654
]

pillar_values = [
    0.0145993931630537,
    0.0229075517972275,
    0.0253020667393029,
    0.0257564866303201,
    0.0259751440992468,
    0.0260355181479988,
    0.0265336263144786,
    0.0272721454114050,
    0.0282024453631075,
    0.0290231222075799,
    0.0304665029488732,
    0.0319855013976250
]

curve_dict = {
    "mktDataType": "Curve",
    "curveType": "IrYieldCurve",
    "referenceDate": referenceDate,
    "currency": "CNY",
    "dayCountConvention": "Actual365",
    "compounding": "Continuous",
    "interpMethod": "Linear",
    "extrapMethod": "Flat",
    "frequency": "", 
    "dates": pillar_dates,
    "values": pillar_values,
    "name": "CNY_FR_007"
}

discountCurve = parseMktData(curve_dict)

print(discountCurve)

curve_dict = {
    "mktDataType": "Curve",
    "curveType": "AssetPriceCurve",
    "referenceDate": referenceDate,
    "dates":[2025.12.15, 2026.01.15, 2026.02.24, 2026.03.16, 2026.04.15, 2026.05.15, 2026.06.15, 2026.07.15, 2026.08.17, 2026.09.15, 2026.10.15, 2026.11.16],
    "values":[88770, 89090, 89080, 89030, 88970, 88950, 88590, 88660, 88350, 88120, 87910, 87840]
}
futPriceCurve = parseMktData(curve_dict)
print(futPriceCurve)

surf = cmFutVolatilitySurfaceBuilder(referenceDate, futMaturities, optionExpiries, strikes, optionPrices, payoffTypes, discountCurve, futPriceCurve, formula='Black76', model='SVI', surfaceName='cu_future_option_vol_surface');

dts = (0..20)*0.05
ks = (0..40)*((max(strikes[0])-min(strikes[0]))\40)+min(strikes[0])
m = optionVolPredict(surf, dts, ks).rename!(dts, ks)

plot(
    m,
    title=["Vol Surface", "K", "T", "vol"],
    chartType=SURFACE)
    

Related Functions: parseMktData