Wednesday, November 7

Cox-Ross-Rubinstein Option Pricing Model

So far we have been discussing mostly pricing and valuation of asset classes with certain and predictable cash flows, such as bonds, loans, bank deposits and others. The certainty of cash payments allowed us to price such instruments using time value of money framework.

However, the situation gets somewhat more complicated when the cash flows become uncertain or optional, as in case of stock options, pre-payable mortgages, interest-rate collars or other contingent claims. In fact, many complex financial instruments have embedded optionality to some extent.

When we consider optionality of cash flows, we usually think in terms of probabilities of such cash flow occurring. In most of the cases we can simplify that whether the cash flow does or doesn't occur is determined by the underlying embedded option. The options valuation is therefore quite fundamental topic of quantitative finance.

In this article, we will discuss Cox-Ross-Rubinstein Option Pricing Model. The model is using binomial tree to value american and European-style call and put options. The aim of this article is to analyze and explain this model on a numerical example and to compare calculated results with the real market prices.

For the purposes of this post, I have also prepared a case study implementation in Python. The more generic implementation can be found in blog's library.

Input Data and Case Study

Through this article, we will consider a simple plain-vanilla American-style call option giving the right to buy the underlying instrument at predetermined time and strike price. The important factors to consider would be how the current market value of instrument is far from the strike price, how volatile the market is, how much time is there left till the option expires and what is the risk-free rate and dividend yield.

All these factors constitute inputs to the option pricing model. Let's assume the underlying instrument to be iShares S&P 500 Index ETF, as of 5th of November 2012. The price series in attached data file looks as follows (Source: Google Finance):

date, open, high, low, close, volume
2012-11-01 00:00:00,142.23,143.58,142.13,143.46,628236
2012-11-02 00:00:00,144.28,144.28,142.0,142.1,569903
2012-11-05 00:00:00,141.94,142.73,141.53,142.41,345956

To retrieve the price history from Google Finance in Python, we can use the code already present in the datasources.google module:

import datasources.google as google
prices = google.getquotesfromweb('IVV').getprices()prices = prices[-250:]  # We will use last 250 trading days


For the valuation, we will need additional information, such as Dividend Yield and Risk Free Rate. The latest price and dividend yield on iShares S&P 500 Index ETF can be retrieved also from Google Finance:

Source: Google Finance

The risk-free rate is derived from US treasury yields with maturity date similar to the option's expiry date, as of 5th of November 2012. In this case, 1 month yield seems to be the most appropriate. We can safely assume that there is virtually no credit risk for both US Treasuries and option contracts, since their performance is guaranteed by US government and clearing houses, respectively:

Source: Financial Times
As we have already mentioned, the option being valued is an American Call on iShares S&P 500 Index ETF. We will choose the option with strike price 140, expiring on 2012/12/22. Given the valuation date of 2012/11/05, the time to expiration is precisely 46 calendar days.

Instrument Volatility Calculation

Calculation of instrument's volatility may be a bit tricky because of several reasons. The most important one is question how long history of data we should consider. If the data window is too short, we may end up with insufficient number of samples with very little statistical significance. On the other hand, looking to far to the past includes a risk of underlying structural changes which make the outcome irrelevant as well. Choosing a time-frame of 1 year (250 trading days) sounds like a reasonable solution.

First what we need to do is to calculate daily returns from the above price history. Bearing in mind the fact that daily returns are continuously compounded, we need to apply a logarithm function to get the nominal rates:
$$ e^{r} = \frac{p_i}{p_{i-1}} \; ; \; r = log \frac{p_i}{p_{i-1}} $$
Daily volatility is then defined as a standard deviation of these returns. Annualized figure will be calculated as follows:
$$ stdev\left ( R \right ) \times \sqrt{250} $$
The Python code performing the whole calculation just reflects this principle:

returns = []
for i in range(0len(prices)-1):
    r = log(prices[i] / prices[i-1])
    returns.append(r)

volat_d = numpy.std(returns)    # Daily volatility
volat = volat_d * 250**.5       # Annualized volatility


the output of this calculation is an annualized volatility of 18.2%, which will be used later as an input to the pricing model:

print('Volatility %0.3f' % volat)
Volatility : 0.182


Another solution would be to imply the volatility from other options' market prices using the reverse valuation process, instead of trying to calculate it directly from price data. The advantage of implied volatility approach is reduced model risk of choosing inappropriate parameters.

Generating a Binomial Tree

To generate the binomial tree, we first need to summarize all relevant inputs for the pricing model which we have mentioned previously. The inputs are as follows:

     Price : 142.410
    Strike : 140.000
 Risk-free :   0.001
 Div Yield :   0.020
  TTE Days :  46.000
Volatility :   0.182


From the given risk-free rate, dividend yield and annual volatility, we will calculate the up and down movements for each node of the tree. Assuming the binomial tree with 8 levels and 46 days to expiration, it turns out that each level represents step of 5.75 days, or 0.015753 years. This is denoted as \(t_\bigtriangleup=0.015753\).
Up and down price movements per step (u, d) are then calculated by de-annualizing instrument's volatility \(\nu\) from previous section and converting it back to an (expected) continuous daily return:
$$  u = e^{\nu \cdot \sqrt{t_{\bigtriangleup}}} \; ; \; d = \frac{1}{u} $$
These price movements must be balanced in terms of the probability in such a way that expected outcome will yield into the arbitrage-free future price determined by the risk-free rate and dividend yield:
$$ u \cdot \pi_u + d \cdot \pi_d = e^{(r_f - dy) \cdot t_{\bigtriangleup}} $$
where \(\pi_u\) is the probability of up movement, \(\pi_d = 1-\pi_u\) is the probability of down movement, \(r_f\) is the risk-free rate and \(dy\) is dividend yield.
Given the inputs above, generated binomial three with 8 levels would graphically look as follows:


Backward Reduction of the Tree

As soon as the binomial tree is generated using the up and down turns, we will use it to value options. It is quite apparent that options just before the expiration have no uncertainty or time value associated, so their whole appraisal consists only from the intrinsic value given as a difference between the strike price (140) and underlying instrument's price (black figures in the terminal nodes of tree). If the option is out-of-money, it's price is naturally zero, as portrayed by the bottom half of the terminal nodes.

In fact, we are not interested in options' value at their expiration, but at the present time. Hence, we will use non-terminal nodes of the tree to bring the terminal option value back to the present. This is done by a reduction of the binomial tree as depicted by red arrows.

Value of European-style option at any node is again determined by the probabilistic outcome of up and down movements, discounted to the present using a risk-free rate. For American-style options, we need to bear in mind also an early exercise scenario, where the node is prematurely terminated, similarly as other terminal nodes in the 8th level. The option value for any such node is then calculated as follows:
$$ v = max \left( \frac{v_u \cdot \pi_u + v_d \cdot \pi_d}{e^{r_f \cdot t_{\bigtriangleup}}} \; ; \; p - s\right) $$
where \(v\) and \(p\) are the option value and instrument price at given node, \(s\) is the strike price, \(u\) and \(d\) are up and down movements, \(\pi_u\) and \(\pi_d\) are probabilities of these movements, and \(e^{r_f \cdot t_{\bigtriangleup}}\) is a risk-free discount factor.
If we speak in terms of concrete figures, option value in the starting node is calculated as an expected value in the successive nodes \((0.488 \times 6.924 + 0.512 \times 2.791=4.899\)), which is almost the same as after application of the discount factor \(e^{r_f \cdot t_{\bigtriangleup}}\) (0.07% treasury yield is negligible on a daily basis for the purpose of this example).
In case of the option being exercised prematurely, it's intrinsic value would be \(p-s = 2.41\), which is less than the expected value. The option value at starting node is therefore 4.899.

The corresponding Python implementation of tree reduction algorithm would look similarly to this:

# Generate terminal nodes of binomial tree
level = []
print('Tree level %i' % n)
for i in range(0, n+1)# Iterate through nodes
    # Instrument's price at the node
    pr = price * d*** u**(n-i)    
    # Option value at the node (depending on side)
    ov = max(0.0, pr-strike) if side==call else max(0.0, strike-pr)
    level.append((pr, ov))
    print('Node Price %.3f, Option Value %.3f' %(pr, ov))
    
levels = [None,None,None] # Remember levels 0,1,2 for the greeks

# reduce binomial tree
for i in range(n-1, -1, -1)# [n-1 to 0]
    levelNext = []
    print('Tree level %i' % i)
    for j in range(0, i+1)# Iterate through nodes
        node_u, node_d = level[j], level[j+1]
        # Instrument's price at the node
        pr = node_d[0] / d
        # Option value at the node (depending on side)
        ov = (node_d[1] * pd + node_u[1] * pu) / (1 + rf)   
        if style==american: # American options can be exercised anytime
            ov = max(ov, pr-strike if side==call else strike-pr)
        levelNext.append((pr, ov))
        print('Node Price %.3f, Option Value %.3f' %(pr, ov))
    level = levelNext
    if j<=2: levels[j]=level # save level 0,1,2 of the tree


The Real Market

We originally based our case study on the real market conditions as of 2012/11/05, taking into the consideration underlying instrument's market data from Google Finance and Financial Times. Google also provides market data for options traded on NYSE Arca.

As we can see from the following screenshot, the option being discussed and valued in this article is currently trading at 4.500 - 4.900, which is fairly close to the theoretical option price of 4.899.

Source: Google Finance

The difference between theoretical value and real market price could have several possible causes, such as the model risk or inefficiency of a market itself. As we have seen, there have been done lots of assumptions regarding model parameters and it would be also reasonable to expect that not all analysts are using the same estimates.

It is also worth noting that there may be significant fluctuations in model's output depending on the length of volatility look-back window, mostly due to volatility clustering and conditional heteroskedasticity. For instance, a time-frame of 100, 200 and 250 days would lead to valuations of 4.714, 4.339 and 4.899. As we have mentioned previously, this problem could be partially solved by implying volatility from option market prices.

The Greeks

Apart of the option value at the head node, we can extract few other figures from the tree, such as option's delta, gamma and theta. For this purpose, we need to process first three levels of the tree:


Delta is the rate of change of option's value with respect to changes in underlying instrument's price. Looking to the figure above, this rate is derived from nodes 10 and 11 as follows:
$$ \delta =\frac{v_{10} - v_{11}}{p_{10} - p_{11}} =  \frac{6.924 - 2.971}{145.701 - 139.194} = 0.607 $$
Gamma is a rate of change of option's delta with respect to changes in underlying instrument's price. Again, we first need to calculate deltas in nodes 10 and 11:
$$ \delta_{10} =\frac{v_{20} - v_{21}}{p_{20} - p_{21}} \; ; \; \delta_{11} =\frac{v_{21} - v_{22}}{p_{21} - p_{22}} $$
Gamma is then calculated as:
$$ \gamma = \frac{\delta_{10}-\delta_{11}}{p_{10} - p_{11}} = 0.022 $$
Theta is sensitivity of option's value with respect to the passage of time. Please note that nodes 00 and 21 have the same instrument's price, only the option's value differs. It is therefore possible to derive option's theta as follows:
$$ \theta = \frac{v_{21} - v_{00}}{2 \times t_{\bigtriangleup}} = -13.157 $$

No comments:

Post a Comment