Spaces:
Build error
Build error
Commit
·
12f4bef
1
Parent(s):
d799cda
commit name
Browse files- .DS_Store +0 -0
- Dockerfile +11 -0
- cache.sqlite +0 -0
- option_Pricing/Base.py +29 -0
- option_Pricing/BinomialTreeModel.py +79 -0
- option_Pricing/BlackScholesModel.py +63 -0
- option_Pricing/MonteCarloSimulation.py +92 -0
- option_Pricing/Ticker.py +95 -0
- option_Pricing/__init__.py +4 -0
- option_Pricing/__pycache__/Base.cpython-310.pyc +0 -0
- option_Pricing/__pycache__/Base.cpython-311.pyc +0 -0
- option_Pricing/__pycache__/BinomialTreeModel.cpython-310.pyc +0 -0
- option_Pricing/__pycache__/BinomialTreeModel.cpython-311.pyc +0 -0
- option_Pricing/__pycache__/BlackScholesModel.cpython-310.pyc +0 -0
- option_Pricing/__pycache__/BlackScholesModel.cpython-311.pyc +0 -0
- option_Pricing/__pycache__/MonteCarloSimulation.cpython-310.pyc +0 -0
- option_Pricing/__pycache__/MonteCarloSimulation.cpython-311.pyc +0 -0
- option_Pricing/__pycache__/Ticker.cpython-310.pyc +0 -0
- option_Pricing/__pycache__/Ticker.cpython-311.pyc +0 -0
- option_Pricing/__pycache__/__init__.cpython-310.pyc +0 -0
- option_Pricing/__pycache__/__init__.cpython-311.pyc +0 -0
- option_pricing_test.py +34 -0
- streamlit_app.py +131 -0
.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
Dockerfile
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10
|
2 |
+
|
3 |
+
COPY . /app
|
4 |
+
|
5 |
+
WORKDIR /app
|
6 |
+
|
7 |
+
RUN pip install -r Requirements.txt
|
8 |
+
|
9 |
+
EXPOSE 8080
|
10 |
+
|
11 |
+
CMD streamlit run --server.port 8080 --server.enableCORS false streamlit_app.py
|
cache.sqlite
ADDED
Binary file (24.6 kB). View file
|
|
option_Pricing/Base.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Imports
|
2 |
+
from enum import Enum
|
3 |
+
from abc import ABC, abstractclassmethod
|
4 |
+
|
5 |
+
class OPTION_TYPE(Enum):
|
6 |
+
CALL_OPTION = 'Call Option'
|
7 |
+
PUT_OPTION = 'Put Option'
|
8 |
+
|
9 |
+
class OptionPricingModel(ABC):
|
10 |
+
"""Abstract class defining interface for option pricing models."""
|
11 |
+
|
12 |
+
def calculate_option_price(self, option_type):
|
13 |
+
"""Calculates call/put option price according to the specified parameter."""
|
14 |
+
if option_type == OPTION_TYPE.CALL_OPTION.value:
|
15 |
+
return self._calculate_call_option_price()
|
16 |
+
elif option_type == OPTION_TYPE.PUT_OPTION.value:
|
17 |
+
return self._calculate_put_option_price()
|
18 |
+
else:
|
19 |
+
return -1
|
20 |
+
|
21 |
+
@abstractclassmethod
|
22 |
+
def _calculate_call_option_price(self):
|
23 |
+
"""Calculates option price for call option."""
|
24 |
+
pass
|
25 |
+
|
26 |
+
@abstractclassmethod
|
27 |
+
def _calculate_put_option_price(self):
|
28 |
+
"""Calculates option price for put option."""
|
29 |
+
pass
|
option_Pricing/BinomialTreeModel.py
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Imports
|
2 |
+
import numpy as np
|
3 |
+
from scipy.stats import norm
|
4 |
+
from .Base import OptionPricingModel
|
5 |
+
|
6 |
+
|
7 |
+
class BinomialTreeModel(OptionPricingModel):
|
8 |
+
"""
|
9 |
+
Class implementing calculation for European option price using BOPM (Binomial Option Pricing Model).
|
10 |
+
It caclulates option prices in discrete time (lattice based), in specified number of time points between date of valuation and exercise date.
|
11 |
+
This pricing model has three steps:
|
12 |
+
- Price tree generation
|
13 |
+
- Calculation of option value at each final node
|
14 |
+
- Sequential calculation of the option value at each preceding node
|
15 |
+
"""
|
16 |
+
|
17 |
+
def __init__(self, underlying_spot_price, strike_price, days_to_maturity, risk_free_rate, sigma, number_of_time_steps):
|
18 |
+
"""
|
19 |
+
Initializes variables used in Black-Scholes formula .
|
20 |
+
|
21 |
+
underlying_spot_price: current stock or other underlying spot price
|
22 |
+
strike_price: strike price for option cotract
|
23 |
+
days_to_maturity: option contract maturity/exercise date
|
24 |
+
risk_free_rate: returns on risk-free assets (assumed to be constant until expiry date)
|
25 |
+
sigma: volatility of the underlying asset (standard deviation of asset's log returns)
|
26 |
+
number_of_time_steps: number of time periods between the valuation date and exercise date
|
27 |
+
"""
|
28 |
+
self.S = underlying_spot_price
|
29 |
+
self.K = strike_price
|
30 |
+
self.T = days_to_maturity / 365
|
31 |
+
self.r = risk_free_rate
|
32 |
+
self.sigma = sigma
|
33 |
+
self.number_of_time_steps = number_of_time_steps
|
34 |
+
|
35 |
+
def _calculate_call_option_price(self):
|
36 |
+
"""Calculates price for call option according to the Binomial formula."""
|
37 |
+
# Delta t, up and down factors
|
38 |
+
dT = self.T / self.number_of_time_steps
|
39 |
+
u = np.exp(self.sigma * np.sqrt(dT))
|
40 |
+
d = 1.0 / u
|
41 |
+
|
42 |
+
# Price vector initialization
|
43 |
+
V = np.zeros(self.number_of_time_steps + 1)
|
44 |
+
|
45 |
+
# Underlying asset prices at different time points
|
46 |
+
S_T = np.array( [(self.S * u**j * d**(self.number_of_time_steps - j)) for j in range(self.number_of_time_steps + 1)])
|
47 |
+
|
48 |
+
a = np.exp(self.r * dT) # risk free compounded return
|
49 |
+
p = (a - d) / (u - d) # risk neutral up probability
|
50 |
+
q = 1.0 - p # risk neutral down probability
|
51 |
+
V[:] = np.maximum(S_T - self.K, 0.0)
|
52 |
+
|
53 |
+
# Overriding option price
|
54 |
+
for i in range(self.number_of_time_steps - 1, -1, -1):
|
55 |
+
V[:-1] = np.exp(-self.r * dT) * (p * V[1:] + q * V[:-1])
|
56 |
+
return V[0]
|
57 |
+
|
58 |
+
def _calculate_put_option_price(self):
|
59 |
+
"""Calculates price for put option according to the Binomial formula."""
|
60 |
+
# Delta t, up and down factors
|
61 |
+
dT = self.T / self.number_of_time_steps
|
62 |
+
u = np.exp(self.sigma * np.sqrt(dT))
|
63 |
+
d = 1.0 / u
|
64 |
+
|
65 |
+
# Price vector initialization
|
66 |
+
V = np.zeros(self.number_of_time_steps + 1)
|
67 |
+
|
68 |
+
# Underlying asset prices at different time points
|
69 |
+
S_T = np.array( [(self.S * u**j * d**(self.number_of_time_steps - j)) for j in range(self.number_of_time_steps + 1)])
|
70 |
+
|
71 |
+
a = np.exp(self.r * dT) # risk free compounded return
|
72 |
+
p = (a - d) / (u - d) # risk neutral up probability
|
73 |
+
q = 1.0 - p # risk neutral down probability
|
74 |
+
V[:] = np.maximum(self.K - S_T, 0.0)
|
75 |
+
|
76 |
+
# Overriding option price
|
77 |
+
for i in range(self.number_of_time_steps - 1, -1, -1):
|
78 |
+
V[:-1] = np.exp(-self.r * dT) * (p * V[1:] + q * V[:-1])
|
79 |
+
return V[0]
|
option_Pricing/BlackScholesModel.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Imports
|
2 |
+
import numpy as np
|
3 |
+
from scipy.stats import norm
|
4 |
+
|
5 |
+
from .Base import OptionPricingModel
|
6 |
+
|
7 |
+
|
8 |
+
class BlackScholesModel(OptionPricingModel):
|
9 |
+
"""
|
10 |
+
Class implementing calculation for European option price using Black-Scholes Formula.
|
11 |
+
|
12 |
+
Call/Put option price is calculated with following assumptions:
|
13 |
+
- European option can be exercised only on maturity date.
|
14 |
+
- Underlying stock does not pay divident during option's lifetime.
|
15 |
+
- The risk free rate and volatility are constant.
|
16 |
+
- Efficient Market Hypothesis - market movements cannot be predicted.
|
17 |
+
- Lognormal distribution of underlying returns.
|
18 |
+
"""
|
19 |
+
|
20 |
+
def __init__(self, underlying_spot_price, strike_price, days_to_maturity, risk_free_rate, sigma):
|
21 |
+
"""
|
22 |
+
Initializes variables used in Black-Scholes formula .
|
23 |
+
|
24 |
+
underlying_spot_price: current stock or other underlying spot price
|
25 |
+
strike_price: strike price for option cotract
|
26 |
+
days_to_maturity: option contract maturity/exercise date
|
27 |
+
risk_free_rate: returns on risk-free assets (assumed to be constant until expiry date)
|
28 |
+
sigma: volatility of the underlying asset (standard deviation of asset's log returns)
|
29 |
+
"""
|
30 |
+
self.S = underlying_spot_price
|
31 |
+
self.K = strike_price
|
32 |
+
self.T = days_to_maturity / 365
|
33 |
+
self.r = risk_free_rate
|
34 |
+
self.sigma = sigma
|
35 |
+
|
36 |
+
def _calculate_call_option_price(self):
|
37 |
+
"""
|
38 |
+
Calculates price for call option according to the formula.
|
39 |
+
Formula: S*N(d1) - PresentValue(K)*N(d2)
|
40 |
+
"""
|
41 |
+
# cumulative function of standard normal distribution (risk-adjusted probability that the option will be exercised)
|
42 |
+
d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma ** 2) * self.T) / (self.sigma * np.sqrt(self.T))
|
43 |
+
|
44 |
+
# cumulative function of standard normal distribution (probability of receiving the stock at expiration of the option)
|
45 |
+
# d2 = (d1 - (sigma * sqrt(T)))
|
46 |
+
d2 = (np.log(self.S / self.K) + (self.r - 0.5 * self.sigma ** 2) * self.T) / (self.sigma * np.sqrt(self.T))
|
47 |
+
|
48 |
+
return (self.S * norm.cdf(d1, 0.0, 1.0) - self.K * np.exp(-self.r * self.T) * norm.cdf(d2, 0.0, 1.0))
|
49 |
+
|
50 |
+
|
51 |
+
def _calculate_put_option_price(self):
|
52 |
+
"""
|
53 |
+
Calculates price for put option according to the formula.
|
54 |
+
Formula: PresentValue(K)*N(-d2) - S*N(-d1)
|
55 |
+
"""
|
56 |
+
# cumulative function of standard normal distribution (risk-adjusted probability that the option will be exercised)
|
57 |
+
d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma ** 2) * self.T) / (self.sigma * np.sqrt(self.T))
|
58 |
+
|
59 |
+
# cumulative function of standard normal distribution (probability of receiving the stock at expiration of the option)
|
60 |
+
# d2 = (d1 - (sigma * sqrt(T)))
|
61 |
+
d2 = (np.log(self.S / self.K) + (self.r - 0.5 * self.sigma ** 2) * self.T) / (self.sigma * np.sqrt(self.T))
|
62 |
+
|
63 |
+
return (self.K * np.exp(-self.r * self.T) * norm.cdf(-d2, 0.0, 1.0) - self.S * norm.cdf(-d1, 0.0, 1.0))
|
option_Pricing/MonteCarloSimulation.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Third party imports
|
2 |
+
import numpy as np
|
3 |
+
from scipy.stats import norm
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
|
6 |
+
# Local package imports
|
7 |
+
from .Base import OptionPricingModel
|
8 |
+
|
9 |
+
|
10 |
+
class MonteCarloPricing(OptionPricingModel):
|
11 |
+
"""
|
12 |
+
Class implementing calculation for European option price using Monte Carlo Simulation.
|
13 |
+
We simulate underlying asset price on expiry date using random stochastic process - Brownian motion.
|
14 |
+
For the simulation generated prices at maturity, we calculate and sum up their payoffs, average them and discount the final value.
|
15 |
+
That value represents option price
|
16 |
+
"""
|
17 |
+
|
18 |
+
def __init__(self, underlying_spot_price, strike_price, days_to_maturity, risk_free_rate, sigma, number_of_simulations):
|
19 |
+
"""
|
20 |
+
Initializes variables used in Black-Scholes formula .
|
21 |
+
|
22 |
+
underlying_spot_price: current stock or other underlying spot price
|
23 |
+
strike_price: strike price for option cotract
|
24 |
+
days_to_maturity: option contract maturity/exercise date
|
25 |
+
risk_free_rate: returns on risk-free assets (assumed to be constant until expiry date)
|
26 |
+
sigma: volatility of the underlying asset (standard deviation of asset's log returns)
|
27 |
+
number_of_simulations: number of potential random underlying price movements
|
28 |
+
"""
|
29 |
+
# Parameters for Brownian process
|
30 |
+
self.S_0 = underlying_spot_price
|
31 |
+
self.K = strike_price
|
32 |
+
self.T = days_to_maturity / 365
|
33 |
+
self.r = risk_free_rate
|
34 |
+
self.sigma = sigma
|
35 |
+
|
36 |
+
# Parameters for simulation
|
37 |
+
self.N = number_of_simulations
|
38 |
+
self.num_of_steps = days_to_maturity
|
39 |
+
self.dt = self.T / self.num_of_steps
|
40 |
+
|
41 |
+
def simulate_prices(self):
|
42 |
+
"""
|
43 |
+
Simulating price movement of underlying prices using Brownian random process.
|
44 |
+
Saving random results.
|
45 |
+
"""
|
46 |
+
np.random.seed(20)
|
47 |
+
self.simulation_results = None
|
48 |
+
|
49 |
+
# Initializing price movements for simulation: rows as time index and columns as different random price movements.
|
50 |
+
S = np.zeros((self.num_of_steps, self.N))
|
51 |
+
# Starting value for all price movements is the current spot price
|
52 |
+
S[0] = self.S_0
|
53 |
+
|
54 |
+
for t in range(1, self.num_of_steps):
|
55 |
+
# Random values to simulate Brownian motion (Gaussian distibution)
|
56 |
+
Z = np.random.standard_normal(self.N)
|
57 |
+
# Updating prices for next point in time
|
58 |
+
S[t] = S[t - 1] * np.exp((self.r - 0.5 * self.sigma ** 2) * self.dt + (self.sigma * np.sqrt(self.dt) * Z))
|
59 |
+
|
60 |
+
self.simulation_results_S = S
|
61 |
+
|
62 |
+
def _calculate_call_option_price(self):
|
63 |
+
"""
|
64 |
+
Call option price calculation. Calculating payoffs for simulated prices at expiry date, summing up, averiging them and discounting.
|
65 |
+
Call option payoff (it's exercised only if the price at expiry date is higher than a strike price): max(S_t - K, 0)
|
66 |
+
"""
|
67 |
+
if self.simulation_results_S is None:
|
68 |
+
return -1
|
69 |
+
return np.exp(-self.r * self.T) * 1 / self.N * np.sum(np.maximum(self.simulation_results_S[-1] - self.K, 0))
|
70 |
+
|
71 |
+
|
72 |
+
def _calculate_put_option_price(self):
|
73 |
+
"""
|
74 |
+
Put option price calculation. Calculating payoffs for simulated prices at expiry date, summing up, averiging them and discounting.
|
75 |
+
Put option payoff (it's exercised only if the price at expiry date is lower than a strike price): max(K - S_t, 0)
|
76 |
+
"""
|
77 |
+
if self.simulation_results_S is None:
|
78 |
+
return -1
|
79 |
+
return np.exp(-self.r * self.T) * 1 / self.N * np.sum(np.maximum(self.K - self.simulation_results_S[-1], 0))
|
80 |
+
|
81 |
+
|
82 |
+
def plot_simulation_results(self, num_of_movements):
|
83 |
+
"""Plots specified number of simulated price movements."""
|
84 |
+
plt.figure(figsize=(12,8))
|
85 |
+
plt.plot(self.simulation_results_S[:,0:num_of_movements])
|
86 |
+
plt.axhline(self.K, c='k', xmin=0, xmax=self.num_of_steps, label='Strike Price')
|
87 |
+
plt.xlim([0, self.num_of_steps])
|
88 |
+
plt.ylabel('Simulated price movements')
|
89 |
+
plt.xlabel('Days in future')
|
90 |
+
plt.title(f'First {num_of_movements}/{self.N} Random Price Movements')
|
91 |
+
plt.legend(loc='best')
|
92 |
+
plt.show()
|
option_Pricing/Ticker.py
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Library imports
|
2 |
+
import datetime
|
3 |
+
import requests_cache
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
from pandas_datareader import data as wb
|
6 |
+
import yfinance as yf
|
7 |
+
|
8 |
+
class Ticker:
|
9 |
+
"""Class for fetcing data from yahoo finance."""
|
10 |
+
|
11 |
+
@staticmethod
|
12 |
+
def get_historical_data(ticker, start_date = None, end_date = None, cache_data = True, cache_days = 1):
|
13 |
+
"""
|
14 |
+
Fetches stock data from yahoo finance. Request is by default cashed in sqlite db for 1 day.
|
15 |
+
|
16 |
+
Params:
|
17 |
+
ticker: ticker symbol
|
18 |
+
start_date: start date for getting historical data
|
19 |
+
end_date: end date for getting historical data
|
20 |
+
cache_date: flag for caching fetched data into sqlite db
|
21 |
+
cache_days: number of days data will stay in cache
|
22 |
+
"""
|
23 |
+
try:
|
24 |
+
# initializing sqlite for caching yahoo finance requests
|
25 |
+
expire_after = datetime.timedelta(days = 1)
|
26 |
+
session = requests_cache.CachedSession(cache_name = 'cache', backend = 'sqlite', expire_after = expire_after)
|
27 |
+
|
28 |
+
# Adding headers to session
|
29 |
+
session.headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
|
30 |
+
'Accept': 'application/json;charset=utf-8'
|
31 |
+
}
|
32 |
+
|
33 |
+
if(start_date is not None and end_date is not None):
|
34 |
+
data = yf.download(ticker, start = start_date, end = end_date)
|
35 |
+
else:
|
36 |
+
data = yf.download(ticker)
|
37 |
+
|
38 |
+
if data is None:
|
39 |
+
return None
|
40 |
+
return data
|
41 |
+
|
42 |
+
except Exception as e:
|
43 |
+
print(e)
|
44 |
+
return None
|
45 |
+
|
46 |
+
@staticmethod
|
47 |
+
def get_columns(data):
|
48 |
+
"""
|
49 |
+
Gets dataframe columns from previously fetched stock data.
|
50 |
+
|
51 |
+
Params:
|
52 |
+
data: dataframe representing fetched data
|
53 |
+
"""
|
54 |
+
if data is None:
|
55 |
+
return None
|
56 |
+
return [column for column in data.columns]
|
57 |
+
|
58 |
+
@staticmethod
|
59 |
+
def get_last_price(data, column_name):
|
60 |
+
"""
|
61 |
+
Returns last available price for specified column from already fetched data.
|
62 |
+
|
63 |
+
Params:
|
64 |
+
data: dataframe representing fetched data
|
65 |
+
column_name: name of the column in dataframe
|
66 |
+
"""
|
67 |
+
if data is None or column_name is None:
|
68 |
+
return None
|
69 |
+
if column_name not in Ticker.get_columns(data):
|
70 |
+
return None
|
71 |
+
return data[column_name].iloc[len(data) - 1]
|
72 |
+
|
73 |
+
|
74 |
+
@staticmethod
|
75 |
+
def plot_data(data, ticker, column_name):
|
76 |
+
"""
|
77 |
+
Plots specified column values from dataframe.
|
78 |
+
|
79 |
+
Params:
|
80 |
+
data: dataframe representing fetched data
|
81 |
+
column_name: name of the column in dataframe
|
82 |
+
"""
|
83 |
+
try:
|
84 |
+
if data is None:
|
85 |
+
return
|
86 |
+
data[column_name].plot()
|
87 |
+
plt.ylabel(f'{column_name}')
|
88 |
+
plt.xlabel('Date')
|
89 |
+
plt.title(f'Historical data for {ticker} - {column_name}')
|
90 |
+
plt.legend(loc = 'best')
|
91 |
+
plt.show()
|
92 |
+
|
93 |
+
except Exception as e:
|
94 |
+
print(e)
|
95 |
+
return
|
option_Pricing/__init__.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .BlackScholesModel import BlackScholesModel
|
2 |
+
from .MonteCarloSimulation import MonteCarloPricing
|
3 |
+
from .BinomialTreeModel import BinomialTreeModel
|
4 |
+
from .Ticker import Ticker
|
option_Pricing/__pycache__/Base.cpython-310.pyc
ADDED
Binary file (1.49 kB). View file
|
|
option_Pricing/__pycache__/Base.cpython-311.pyc
ADDED
Binary file (1.97 kB). View file
|
|
option_Pricing/__pycache__/BinomialTreeModel.cpython-310.pyc
ADDED
Binary file (3.31 kB). View file
|
|
option_Pricing/__pycache__/BinomialTreeModel.cpython-311.pyc
ADDED
Binary file (5.25 kB). View file
|
|
option_Pricing/__pycache__/BlackScholesModel.cpython-310.pyc
ADDED
Binary file (2.85 kB). View file
|
|
option_Pricing/__pycache__/BlackScholesModel.cpython-311.pyc
ADDED
Binary file (4.43 kB). View file
|
|
option_Pricing/__pycache__/MonteCarloSimulation.cpython-310.pyc
ADDED
Binary file (4.17 kB). View file
|
|
option_Pricing/__pycache__/MonteCarloSimulation.cpython-311.pyc
ADDED
Binary file (6.15 kB). View file
|
|
option_Pricing/__pycache__/Ticker.cpython-310.pyc
ADDED
Binary file (3.22 kB). View file
|
|
option_Pricing/__pycache__/Ticker.cpython-311.pyc
ADDED
Binary file (4.49 kB). View file
|
|
option_Pricing/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (371 Bytes). View file
|
|
option_Pricing/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (449 Bytes). View file
|
|
option_pricing_test.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Script testing functionalities of option_pricing package:
|
3 |
+
- Testing stock data fetching from Yahoo Finance using pandas-datareader
|
4 |
+
- Testing Black-Scholes option pricing model
|
5 |
+
- Testing Binomial option pricing model
|
6 |
+
- Testing Monte Carlo Simulation for option pricing
|
7 |
+
"""
|
8 |
+
|
9 |
+
from option_pricing import BlackScholesModel, MonteCarloPricing, BinomialTreeModel, Ticker
|
10 |
+
|
11 |
+
# Fetching the prices from yahoo finance
|
12 |
+
data = Ticker.get_historical_data('TSLA')
|
13 |
+
print(Ticker.get_columns(data))
|
14 |
+
print(Ticker.get_last_price(data, 'Adj Close'))
|
15 |
+
Ticker.plot_data(data, 'TSLA', 'Adj Close')
|
16 |
+
|
17 |
+
# Black-Scholes model testing
|
18 |
+
BSM = BlackScholesModel(100, 100, 365, 0.1, 0.2)
|
19 |
+
print(BSM.calculate_option_price('Call Option'))
|
20 |
+
print(BSM.calculate_option_price('Put Option'))
|
21 |
+
|
22 |
+
# Binomial model testing
|
23 |
+
BOPM = BinomialTreeModel(100, 100, 365, 0.1, 0.2, 15000)
|
24 |
+
print(BOPM.calculate_option_price('Call Option'))
|
25 |
+
print(BOPM.calculate_option_price('Put Option'))
|
26 |
+
|
27 |
+
# Monte Carlo simulation testing
|
28 |
+
MC = MonteCarloPricing(100, 100, 365, 0.1, 0.2, 10000)
|
29 |
+
MC.simulate_prices()
|
30 |
+
print(MC.calculate_option_price('Call Option'))
|
31 |
+
print(MC.calculate_option_price('Put Option'))
|
32 |
+
MC.plot_simulation_results(20)
|
33 |
+
|
34 |
+
|
streamlit_app.py
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Standart python imports
|
2 |
+
from enum import Enum
|
3 |
+
from datetime import datetime, timedelta
|
4 |
+
|
5 |
+
# Third party imports
|
6 |
+
import streamlit as st
|
7 |
+
|
8 |
+
# Local package imports
|
9 |
+
from option_Pricing import BlackScholesModel, MonteCarloPricing, BinomialTreeModel, Ticker
|
10 |
+
|
11 |
+
class OPTION_PRICING_MODEL(Enum):
|
12 |
+
BLACK_SCHOLES = 'Black Scholes Model'
|
13 |
+
MONTE_CARLO = 'Monte Carlo Simulation'
|
14 |
+
BINOMIAL = 'Binomial Model'
|
15 |
+
|
16 |
+
@st.cache_data
|
17 |
+
def get_historical_data(ticker):
|
18 |
+
"""Getting historical data for speified ticker and caching it with streamlit app."""
|
19 |
+
return Ticker.get_historical_data(ticker)
|
20 |
+
|
21 |
+
# Ignore the Streamlit warning for using st.pyplot()
|
22 |
+
st.set_option('deprecation.showPyplotGlobalUse', False)
|
23 |
+
|
24 |
+
# Main title
|
25 |
+
st.title('Option pricing')
|
26 |
+
|
27 |
+
# User selected model from sidebar
|
28 |
+
pricing_method = st.sidebar.radio('Please select option pricing method', options = [model.value for model in OPTION_PRICING_MODEL])
|
29 |
+
|
30 |
+
# Displaying specified model
|
31 |
+
st.subheader(f'Pricing method: {pricing_method}')
|
32 |
+
|
33 |
+
if pricing_method == OPTION_PRICING_MODEL.BLACK_SCHOLES.value:
|
34 |
+
# Parameters for Black-Scholes model
|
35 |
+
ticker = st.text_input('Ticker symbol', 'AAPL')
|
36 |
+
strike_price = st.number_input('Strike price', 0)
|
37 |
+
risk_free_rate = st.slider('Risk-free rate (%)', 0, 100, 10)
|
38 |
+
sigma = st.slider('Sigma (%)', 0, 100, 20)
|
39 |
+
exercise_date = st.date_input('Exercise date', min_value = datetime.today() + timedelta(days = 1), value = datetime.today() + timedelta(days = 365))
|
40 |
+
|
41 |
+
if st.button(f'Calculate option price for {ticker}'):
|
42 |
+
# Getting data for selected ticker
|
43 |
+
data = get_historical_data(ticker)
|
44 |
+
st.write(data.tail())
|
45 |
+
Ticker.plot_data(data, ticker, 'Adj Close')
|
46 |
+
st.pyplot()
|
47 |
+
|
48 |
+
# Formating selected model parameters
|
49 |
+
spot_price = Ticker.get_last_price(data, 'Adj Close')
|
50 |
+
risk_free_rate = risk_free_rate / 100
|
51 |
+
sigma = sigma / 100
|
52 |
+
days_to_maturity = (exercise_date - datetime.now().date()).days
|
53 |
+
|
54 |
+
# Calculating option price
|
55 |
+
BSM = BlackScholesModel(spot_price, strike_price, days_to_maturity, risk_free_rate, sigma)
|
56 |
+
call_option_price = BSM.calculate_option_price('Call Option')
|
57 |
+
put_option_price = BSM.calculate_option_price('Put Option')
|
58 |
+
|
59 |
+
# Displaying call/put option price
|
60 |
+
st.subheader(f'Call option price: {call_option_price}')
|
61 |
+
st.subheader(f'Put option price: {put_option_price}')
|
62 |
+
|
63 |
+
elif pricing_method == OPTION_PRICING_MODEL.MONTE_CARLO.value:
|
64 |
+
# Parameters for Monte Carlo simulation
|
65 |
+
ticker = st.text_input('Ticker symbol', 'AAPL')
|
66 |
+
strike_price = st.number_input('Strike price', 0)
|
67 |
+
risk_free_rate = st.slider('Risk-free rate (%)', 0, 100, 10)
|
68 |
+
sigma = st.slider('Sigma (%)', 0, 100, 20)
|
69 |
+
exercise_date = st.date_input('Exercise date', min_value = datetime.today() + timedelta(days = 1), value = datetime.today() + timedelta(days = 365))
|
70 |
+
number_of_simulations = st.slider('Number of simulations', 100, 100000, 10000)
|
71 |
+
num_of_movements = st.slider('Number of price movement simulations to be visualized ', 0, int(number_of_simulations / 10), 100)
|
72 |
+
|
73 |
+
if st.button(f'Calculate option price for {ticker}'):
|
74 |
+
# Getting data for selected ticker
|
75 |
+
data = get_historical_data(ticker)
|
76 |
+
st.write(data.tail())
|
77 |
+
Ticker.plot_data(data, ticker, 'Adj Close')
|
78 |
+
st.pyplot()
|
79 |
+
|
80 |
+
# Formating simulation parameters
|
81 |
+
spot_price = Ticker.get_last_price(data, 'Adj Close')
|
82 |
+
risk_free_rate = risk_free_rate / 100
|
83 |
+
sigma = sigma / 100
|
84 |
+
days_to_maturity = (exercise_date - datetime.now().date()).days
|
85 |
+
|
86 |
+
# ESimulating stock movements
|
87 |
+
MC = MonteCarloPricing(spot_price, strike_price, days_to_maturity, risk_free_rate, sigma, number_of_simulations)
|
88 |
+
MC.simulate_prices()
|
89 |
+
|
90 |
+
# Visualizing Monte Carlo Simulation
|
91 |
+
MC.plot_simulation_results(num_of_movements)
|
92 |
+
st.pyplot()
|
93 |
+
|
94 |
+
# Calculating call/put option price
|
95 |
+
call_option_price = MC.calculate_option_price('Call Option')
|
96 |
+
put_option_price = MC.calculate_option_price('Put Option')
|
97 |
+
|
98 |
+
# Displaying call/put option price
|
99 |
+
st.subheader(f'Call option price: {call_option_price}')
|
100 |
+
st.subheader(f'Put option price: {put_option_price}')
|
101 |
+
|
102 |
+
elif pricing_method == OPTION_PRICING_MODEL.BINOMIAL.value:
|
103 |
+
# Parameters for Binomial-Tree model
|
104 |
+
ticker = st.text_input('Ticker symbol', 'AAPL')
|
105 |
+
strike_price = st.number_input('Strike price', 0)
|
106 |
+
risk_free_rate = st.slider('Risk-free rate (%)', 0, 100, 10)
|
107 |
+
sigma = st.slider('Sigma (%)', 0, 100, 20)
|
108 |
+
exercise_date = st.date_input('Exercise date', min_value = datetime.today() + timedelta(days = 1), value = datetime.today() + timedelta(days = 365))
|
109 |
+
number_of_time_steps = st.slider('Number of time steps', 5000, 100000, 15000)
|
110 |
+
|
111 |
+
if st.button(f'Calculate option price for {ticker}'):
|
112 |
+
# Getting data for selected ticker
|
113 |
+
data = get_historical_data(ticker)
|
114 |
+
st.write(data.tail())
|
115 |
+
Ticker.plot_data(data, ticker, 'Adj Close')
|
116 |
+
st.pyplot()
|
117 |
+
|
118 |
+
# Formating simulation parameters
|
119 |
+
spot_price = Ticker.get_last_price(data, 'Adj Close')
|
120 |
+
risk_free_rate = risk_free_rate / 100
|
121 |
+
sigma = sigma / 100
|
122 |
+
days_to_maturity = (exercise_date - datetime.now().date()).days
|
123 |
+
|
124 |
+
# Calculating option price
|
125 |
+
BOPM = BinomialTreeModel(spot_price, strike_price, days_to_maturity, risk_free_rate, sigma, number_of_time_steps)
|
126 |
+
call_option_price = BOPM.calculate_option_price('Call Option')
|
127 |
+
put_option_price = BOPM.calculate_option_price('Put Option')
|
128 |
+
|
129 |
+
# Displaying call/put option price
|
130 |
+
st.subheader(f'Call option price: {call_option_price}')
|
131 |
+
st.subheader(f'Put option price: {put_option_price}')
|