# Commodity pricing with Ornstein-Uhlenbeck price process and Kalman Filter calibration in Python

Let’s be clear: the literature on how to simulate the price of commodities is extensive, with models for all tastes and situations. However, often after reading a paper, the first thing I ask myself is *yes, but how do you actually do it?*

In this short article, I want to jump over that barrier and break down all the steps, from the maths to the calibration including the relevant code.

I will describe the process for pricing oil with a one-factor mean-reverting model calibrated with a simple Kalman Filter. The code is in Python.

# The Maths

## Pricing model

We model the oil price using the one-factor model. The model assumes that the log-spot price follows an Ornstein-Ulenbeck mean-reverting process. The choice for the simplest — yet perhaps more powerful — model is explained by its properties: the one-factor model allows for a closed-form solution for futures prices and for a linear relationship between the log-futures prices and the underlying factors. These properties are key for both the calibration and empirical application of the model. Considering X = ln (S) we write

where α = −σ^2/2k is the long-run mean log price and k is the speed of adjustment. Under the risk-neutral probability Q, we write equation (1) as

Here α*= α — λ, where λ is the market price of risk. Based on Girsanov’s Theorem dW* is a Brownian Motion under the martingale measure Q.

We can now apply Ito’s lemma with g(x,t) = e^{k μ}(α*-X) and obtain the solution

Now, from equation (1) we know that the conditional distribution of X at time t under the risk-neutral measure Q is normal, and has

Using the quadratic variation of a geometric Brownian motion we know that dW² = dt, hence we can resolve the integral in the variance and write

Recall that X = ln S, therefore the spot price at time t is log-normally distributed under the martingale measure Q.

We should also note that the commodity is not an asset in the usual sense, but the spot price (or log-spot)functions as the underlying state variable upon which contingent claims can be written. Such underlying assumption is the foundation of our mean-reverting process under the martingale measure in equation (2).

Let us now move our attention to the futures price of the commodity with maturity t. Assuming constant interest rates, the futures price at maturity t is the expected oil price at time t under the equivalent martingale measure

and from the properties of the log-normal distribution we have

Finally, substituting from equation (5) we obtain, in log form

We will use equation (8) for the calibration of the model. A final remark should be on the non-log form of equation (8), noting that it is nothing but the solution to the Ito’s PDE

with boundary condition F(S,0) = S.

## Model Calibration

In the case of oil commodity, one of the difficulties in the empirical implementation is that the state variable, i.e. the spot price, is not directly observable. On the other hand, Futures contracts are widely traded and their high liquidity makes their prices easily observable. Harvey (1989) discussion of the state space model comes handy in this instance: the state space form, in fact, is the appropriate tool to deal with state variables that are unobservable but generated by a Markov process. The Kalman filter can be applied to the model in the state-space form to estimate the unobserved parameters. Following Scwhartz (1999) and Harvey (1989), we will proceed as follows:

- We obtain the *measurement equation* by adding to equation (9) serially and cross-sectionally uncorrelated disturbances with mean zero, so that we take into account of bid-ask spreads, price limits and errors in the data. The measurement equation relates the time series of observable variables, in our case futures prices for different maturities, to the unobservable state variable, the spot price. Based on this, from equation (9) we write the measurement equation as

where

- We generate the unobserved state variable via the
*transition equation*, which is a discrete-time version of the stochastic process in equation (1. We can therefore write the transition equation as

where

- The Kalman filter is then applied as a recursive procedure to compute the optimal estimator of the state variable at a time t, based on the information at time t and updated continuously as new information becomes available. In order to apply the simple Kalman filter, we assume that both the disturbances and the initial state variable are normally distributed; we can therefore calculate the maximum likelihood function and estimate the model parameter that is otherwise unknown.

# Model Implementation

## Calibration

To calibrate, we collected the observed data from the time series of the price of 17 future contracts (1 to 35 months maturity) between 2015–2019. We further note that Z is the observation matrix, Q is the transition matrix, Var(ηt) is the transition covariance, from which we want to estimate k and σ. The calibration is run in Python, and we used the library Pykalman to apply the Kalman filter. To find the best parameters we proceed as follows. We define an objective function and the required parameters to apply the Kalman Filter (with the Pykalman library) and maximise the log-likelihood function of observed measurements using the Scipy optimiser. We then build a filtered and smoothed state estimate for comparison, obtaining the plot at the end of the code.

The python code is:

Here you go! We have the starting parameters k and σ for our pricing model!

## Pricing Model

We simulate 10000 scenarios using a Monte Carlo approach to the oil pricing model in Python. In particular, we simulate and produce a number of outcomes for a number of scenarios over a large number of time-steps (approximately 250). As a result, the technique produces a large number of possible outcomes of variables, along with their probabilities, as shown at the end of the code.

Done! To finish off, we can easily get the distribution of the price at different times:

Thank you for reading, if you have questions or would like more information please get in touch!