-
Option Payoffs 4
-
Lecture1.1
-
Lecture1.2
-
Lecture1.3
-
Lecture1.4
-
-
Binomial Model 8
-
Lecture2.1
-
Lecture2.2
-
Lecture2.3
-
Lecture2.4
-
Lecture2.5
-
Lecture2.6
-
Lecture2.7
-
Lecture2.8
-
-
Black-Scholes 6
-
Lecture3.1
-
Lecture3.2
-
Lecture3.3
-
Lecture3.4
-
Lecture3.5
-
Lecture3.6
-
-
Monte Carlo Simulations 3
-
Lecture4.1
-
Lecture4.2
-
Lecture4.3
-
Binomial Trees 1
Let’s define movements for different time increments. We have been using r to denote the continiously compounded growth rate in an up period, but we will now refer to it as sigma (to denote the annual volatility) and as well we are going to define a time increment as the number or fraction of years. In this case, we then have the following definitions of up and down states.
$$D = \frac{1}{U}$$
Let’s update the functions to reflect the new equation used.
#Now change the function to have time increment choices
#As well a second step that converts the node labels
def create_nodes(S, T, sigma, T_increment):
up = np.exp(sigma * (T_increment ** .5))
down = 1/up
node_levels = []
for t in range(T+1):
nodes = [S * (up ** k) * (down ** (t-k)) for k in range(t+1)]
nodes = nodes[::-1]
node_levels.append(nodes)
return node_levels
node_levels = create_nodes(100, 12, .08, 1/12)
print(node_levels)
def convert_nodes_to_labels(node_levels):
node_labels = []
for t in range(len(node_levels)):
nodes = ["T={}-${:.2f}".format(t, x) for x in node_levels[t]]
node_labels.append(nodes)
return node_labels
node_levels = convert_nodes_to_labels(node_levels)
print()
print(node_levels)
Run the binomial tree for a year where we use an increment of one month (t=1/12).
node_levels = create_nodes(100, 12, .08, 1/12)
node_levels = convert_nodes_to_labels(node_levels)
pos_dictionary = create_node_positions(node_levels)
draw_binary_tree(node_levels, pos_dictionary,node_levels)
An assumption when using binomial trees is the idea of a risk-neutral probability. For two possible nodes that a node could go to in the next time period, we want the expected value of the return to be equal to the risk-free rate. By this we mean that the probability of an up movement multiplied by the return in an up movement plus the probability of a down movement times the return in a down movement should equal the risk-free return (over the time increment). The formula for determining the probability of an up movement is:
$$r = \text{Risk-Free Rate}$$
$$t = \text{Time}$$
$$U = \text{Up Value}$$
$$D = \text{Down Value}$$
Given the risk-free rate, sigma (for computing the value for up and down), and the time incremenet we are building our tree with we can compute the risk neutral probability very easily. Below is code to implement.
#Formula to compute risk-neutral probability
def compute_up_probability(rf, T_increment, sigma):
r_period = np.exp(sigma * (T_increment ** .5))
rf_period = np.exp(rf * T_increment)
up = r_period
down = 1/r_period
return (rf_period - down) /(up-down)
p_up = compute_up_probability(.04, 1/12, .08)
print(p_up)
This probability represents only the probability from a node to one upwards in the next period (or otherwise downwards). To compute the values further down the line, we need to consider that there is more than one path to almost all nodes. For example, notice the probabilities for the first time period and the second period. There is almost a 50% chance that in the second period the stock is at the middle node because there were two possible paths to it.
The probability of a state at time t can be represented with a binomial variable which, in simple terms, gives the probability of k occurences of something in a set of n samples where the probability of the occurence is k. So for the very top node in each time period, it would be the probability of k up moves, for example. The equation for this probability is:
In this case n is equal to the number of nodes which is equal to t, the time period. The probability p is the probability of an up movement. Now to implement in code. We are able to easily compute factorials with the math library.
import math
#Easy way to get a factorial
print(math.factorial(5))
Challenge