-
Notifications
You must be signed in to change notification settings - Fork 1
/
Binomial Option Valuation Calculator.py
91 lines (77 loc) · 3.56 KB
/
Binomial Option Valuation Calculator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def valueOption(s, x, t, r, b, v, nat = 'A', typ = 'C', prnt = True, exercisePeriods = []):
"""
Calculates the fair option price of a simple option, inputs are as follows:
s: The current stock price
x: The strike price of the option
t: The time in years until maturity of the option
r: The current risk-free rate
b: The number of branches to use in the option pricing
v: The volatility of the underlying asset's price
nat: 'A' for American (default), 'B' for Bermudan, 'E' for European
typ: 'C' for Call (default) or 'P' for Put
prnt: True (default) to print variables to console, False to disable
exercisePeriods: If option is Bermudan enter branches it is exercisable as a list.
Returns:
Option Value, Price Tree, Answer Tree
"""
if min(s,x,t,b,v) <= 0:
raise Exception('Inputs are Invalid: Use a positive value for s, x, t, b and v')
if nat not in ['A', 'B', 'E']:
raise Exception("Inputs are Invalid: Use 'A' for American Options, 'B' for Bermudan or 'E' for European")
if typ not in ['C', 'P']:
raise Exception("Inputs are Invalid: Use 'C' for Call Options or 'P' for Put Options")
if type(prnt) != bool:
raise Exception('Inputs are Invalid: Use True to print steps to console, False to Disable')
exp = 2.718281828459045
dt = t / b
u = exp ** (v * (dt ** 0.5))
d = 1/u
p = (exp ** (r * (dt)) - d) / (u - d)
q = (1-p)
priceTree = [[s], [s * d, s * u]]
for row in range(1, b):
newRow = [priceTree[row][0] * d]
for item in priceTree[row]:
newRow.append(item * u)
priceTree.append(newRow)
IVTree =[]
for row in priceTree:
newRow = []
for item in row:
if typ == 'C':
newRow.append(max(item-x,0))
elif typ == 'P':
newRow.append(max(x-item,0))
IVTree.append(newRow)
answerTree = []
for rowIndex in range(b):
newRow = []
for item in priceTree[rowIndex]:
newRow.append(0)
answerTree.append(newRow)
answerTree.append(IVTree[b])
if nat == 'A':
exercisePeriods = list(range(b+1))
elif nat == 'E':
exercisePeriods = []
for rowIndex in range(b - 1, -1, -1):
if rowIndex in exercisePeriods:
exercisible = True
else:
exercisible = False
for item in range(len(answerTree[rowIndex])):
intrinsicValue = IVTree[rowIndex][item]
discountedValue = exp ** (-r * dt) * (p * answerTree[rowIndex + 1][item + 1] + q * answerTree[rowIndex + 1][item])
if exercisible == False or discountedValue >= intrinsicValue:
answerTree[rowIndex][item] = discountedValue
else:
answerTree[rowIndex][item] = intrinsicValue
if prnt == True:
print(f'The up-factor is {round(u, 4)} and the down-factor is {round(d, 4)}')
print(f'\nThe probability of an upward price movement is {round(p, 4)}')
print('\nThe stock price at each node is:')
[print(['{0:.4f}'.format(item) for item in lst]) for lst in priceTree]
print('\nThe option value at each node are:')
[print(['{0:.4f}'.format(item) for item in lst]) for lst in answerTree]
print(f'\nThe fair value of the {nat} {typ} Option is ${round(answerTree[0][0], 4)}')
return answerTree[0][0], priceTree, answerTree