Option Pricing with C++ Tables

Once we fix an underlying asset (such as a stock), we can build derived assets whose payoffs depend on the behavior of the underlying asset. The simplest among them are European call options.

1. Introduction to European call options

European call option is a derived security that has the following parameters:

  • Underlying asset. Usually a specific stock is the underlying asset for a European call.
  • Expiration time. A time in the future is fixed. In real world, the expiration time is quoted as a specific date in the future. In our notes, the expiration time \(T\) will be the length of time that needs to pass from the present until the expiration of the option. Thus, if we write \(T=0.25\), this would mean that the option expires in \(0.25\) years. If we write \(T=2\), we will mean that the option expires in \(2\) years.
  • Strike price. The strike price will be denoted by \(K\).
Definition of European call option. The European call option with strike \(K\) and expiration \(T\) is the contract between the buyer (who is also called the holder of the long position) and the seller (who is also called the holder of the short position) in which the buyer (i.e. the holder of the long position) is allowed but not required to buy one share of underlying asset from the seller (i.e. the holder of the short position) at the expiration time \(T\) for the price \(K\).

If the buyer decides to buy one share of the underlying asset from the seller, the seller is not allowed to refuse. Thus, if at the expiration, the price of the underlying asset is higher than the strike \(K\), the buyer will choose to exercise the option and get the underlying asset. The buyer will be paying the cheaper price \(K\), instead of the regular price \(S_T\) for the underlying asset.

Exercising the option is equivalent to the seller giving money \((S_T-K)^+\) to the buyer. The quantity \((S_T-K)^+\) is called the payoff of the option.

2. Option prices in binomial model

Theorem 1.

If the price of the stock is assumed to follow the binomial model with parameters \(n\), \(S\), \(u\), and \(d\), and if the simple interest rate \(r\) over one period satisfies \(u> 1+r> d\), then the price of the derived security with expiration \(n\) satisfies \begin{eqnarray*}\mbox{Price}&=& \frac1{(1+r)^n}\cdot \mathbb E_*\left[\mbox{Payoff}(S_n)\right], \end{eqnarray*} where \(\mathbb E_*\) is the expectation under the risk-neutral probability.

The risk-neutral probability \(p_*\) that in each period stock price gets multiplied by \(u\) is \begin{eqnarray*}p_*&=&\mathbb P_*\left(S_{i+1}=S_i\cdot u\right)=\frac{1+r-d}{u-d}. \end{eqnarray*} Consequenlty, the risk neutral probability \(q_*\) of the event \(\{S_{i+1}=S_i\cdot d\}\) satisfies \(q_*=1-p_*=\frac{u-1-r}{u-d}\).

3. Example

Let us analyze a European call option with expiration \(n=2\) and strike \(K=\$180\) whose underlying security is the stock from the example we made in the section Binomial model. The parameters in the example were \(n=2\), \(S_0=S=\$200\), \(u=1.25\), \(d=0.75\). The stock price tree was

\begin{eqnarray*} \begin{array}{ccccc} \quad & \quad & \quad & \quad & \$312.5\\ & & & \nearrow & \quad\\ & & \$250& &\\ &\nearrow & &\searrow&\\ \$200& &&& \$187.5\\ &\searrow & & \nearrow&\\ & & \$150& &\\ & & & \searrow & \\ & & & & \$112.5 \end{array} \end{eqnarray*}

We will assume that the interest rate over each period is \(r=10\%=0.1\).

Our goal is to determine the price \(C_0\) of the European call option with expiration \(n=2\) and strike \(K=\$180\).

There are \(3\) possible prices that the stock can take at the expiration \(n=2\). They are \(312.5\), \(187.5\), and \(112.5\). The possible payoffs the European call option are \begin{eqnarray*}C_{u^2}&=&\mbox{Payoff}(312.5)=(312.5-180)^+=132.5, \\C_{ud}&=&\mbox{Payoff}(187.5)=(187.5-180)^+=7.5,\quad\mbox{and}\\ C_{d^2}&=&\mbox{Payoff}(112.5)=(112.5-180)^+=0.\end{eqnarray*} We completed our first step in constructing the option price tree. The result is not a complete tree. We only have the last column.

\begin{eqnarray*} \begin{array}{ccccc} \quad & \quad & \quad & \quad & \$132.5\\ & & & \nearrow & \quad\\ & &C_u& &\\ &\nearrow & &\searrow&\\ C_0& &&& \$7.5\\ &\searrow & & \nearrow&\\ & & C_d& &\\ & & & \searrow & \\ & & & & \$0 \end{array} \end{eqnarray*}

The numbers \(C_0\), \(C_u\), and \(C_d\) are unknown at the moment. We will calculate them soon. The number \(C_u\) is the price of the option in the binomial model with one period in which the possible payoffs are \(C_{u^2}=132.5\) and \(C_{ud}=7.5\). According to the Theorem 1, the price \(C_u\) satisfies \begin{eqnarray*} C_u&=&\frac1{1+r}\mathbb E_*\left[\mbox{Payoff}\right]\\ &=&\frac1{1+r}\cdot\left(C_{u^2}\cdot p_*+C_{ud}\cdot q_*\right),\quad \mbox{where }\\ p_*&=&\frac{1+r-d}{u-d}=0.7\quad \mbox{ and }\\ q_*&=&1-p_*=0.3. \end{eqnarray*} The price \(C_u\) is \(C_u=86.363636\).

In a very similar way we obtain \begin{eqnarray*}C_d &=& \frac1{1+r}\cdot \left(C_{ud}\cdot p_*+C_{d^2}\cdot q_*\right)\\ &=& \frac1{1.1}\cdot \left(7.5\cdot 0.7+0\cdot 0.3\right)\\ &=&4.772727.\end{eqnarray*} The tree after the second step is \begin{eqnarray*} \begin{array}{ccccc} \quad & \quad & \quad & \quad & \$132.5\\ & & & \nearrow & \quad\\ & &86.363636& &\\ &\nearrow & &\searrow&\\ C_0& &&& \$7.5\\ &\searrow & & \nearrow&\\ & & 4.772727& &\\ & & & \searrow & \\ & & & & \$0 \end{array} \end{eqnarray*} Finally, \begin{eqnarray*}C_0 &=& \frac1{1+r}\cdot \left(C_{u}\cdot p_*+C_{d}\cdot q_*\right)=56.26033.\end{eqnarray*} The final tree is \begin{eqnarray*} \begin{array}{ccccc} \quad & \quad & \quad & \quad & \$132.5\\ & & & \nearrow & \quad\\ & &86.363636& &\\ &\nearrow & &\searrow&\\ 56.26033& &&& \$7.5\\ &\searrow & & \nearrow&\\ & & 4.772727& &\\ & & & \searrow & \\ & & & & \$0 \end{array} \end{eqnarray*}

4. Option price tree with C++ tables

In the section Binomial model we made a program that creates the stock price tree. We will need that program now. We will extend it to calculate prices of European call options.

4.1. Input variables

The two additional variables that we need are the interest rate \(r\) and the strike \(K\). We will read them from A[0][4] and A[0][5].

double r,K;
r=A[0][4]; K=A[0][5];

4.2. Data structure for option tree

The option price tree has the same format as the stock price tree. We need a vector of \(n+1\) vectors whose lengths are \(1\), \(2\), \(\dots\), \(n+1\). Instead of manually resizing the vectors, we can just copy the data structure stock_tree. Eventually, we will re-write each of its entries. This copying is done merely as a convenient way to allocate memory of correct shape.

std::vector<std::vector<double> > option_tree=stock_tree;

4.3. Calculations of option prices

The option tree is constructed backwards. The last column is the payoff column. Its entries are the payoffs of the options at the expiration time \(n\). There are \(n+1\) elements in the payoff column because there are \(n+1\) possible prices for the stock at the expiration time \(n\). Each price of the stock determines the payoff uniquely.

i=0;
while(i<=n){
  if(stock_tree[n][i]>K){
    option_tree[n][i]=stock_tree[n][i]-K;
  }
  else{
    option_tree[n][i]=0;
  }
  i=i+1;
}

The remaining columns are treated differently than the last column \(n\). For fixed \(i\) that satisfies \(i< n\) and for fixed \(j\) that satisfies \(0\leq j\leq i\), we will use the entries option_tree[i+1][j] and option_tree[i+1][j+1] to evaluate option_tree[i][j] using the formula \[\mbox{option_tree}[i][j]=\frac1{1+r}\left(p_*\cdot \mbox{option_tree}[i+1][j]+q_*\cdot \mbox{option_tree}[i+1][j+1]\right).\]

double pStar,qStar;
pStar=(1.0+r-d)/(u-d); qStar=1.0-pStar;
i=n-1;
while(i>=0){
  j=0;
  while(j<=i){
    option_tree[i][j]=(1.0/(1.0+r)) * (pStar*option_tree[i+1][j]+qStar*option_tree[i+1][j+1]);
    j=j+1;
  }
  i=i-1;
}

4.4. Preparation of output

In the section Binomial model we made a transfer from stock_tree to B. Here we will do an analogous operation. We'll just use option_tree instead of stock_tree.

i=0;
while(i<=n){
  j=i;
  while(j<=n){
    B[i][j]=option_tree[j][i];
    j=j+1;
  }
  i=i+1;
}

4.5. Final code

double S, u, d;
S=A[0][1]; u=A[0][2]; d=A[0][3];
int n;
n=A[0][0];
std::vector<std::vector<double> > stockTree;
stockTree.resize(n+1);
int i;
i=0;
while(i<=n){
  stockTree[i].resize(i+1);
  i=i+1;
}
stockTree[0][0]=S;
int j;
i=1;
while(i<=n){
  stockTree[i][0]=stockTree[i-1][0]*u;
  j=1;
  while(j<=i){
    stockTree[i][j]=stockTree[i-1][j-1]*d;
    j=j+1;
  }
  i=i+1;
}
double r,K;
r=A[0][4]; K=A[0][5];
std::vector<std::vector<double> > optionTree=stockTree;
i=0;
while(i<=n){
  if(stockTree[n][i]>K){
    optionTree[n][i]=stockTree[n][i]-K;
  }
  else{
    optionTree[n][i]=0;
  }
  i=i+1;
}
double pStar,qStar;
pStar=(1.0+r-d)/(u-d); qStar=1.0-pStar;
i=n-1;
while(i>=0){
  j=0;
  while(j<=i){
    optionTree[i][j]=(1.0/(1.0+r))
                       * (pStar*optionTree[i+1][j]
                           + qStar*optionTree[i+1][j+1]);
    j=j+1;
  }
  i=i-1;
}
i=0;
while(i<=n){
  j=i;
  while(j<=n){
    B[i][j]=optionTree[j][i];
    j=j+1;
  }
  i=i+1;
}