Spaces:
Runtime error
Runtime error
first commit
Browse files
[Reference and Explanation Notebook] Calculate Intrinsic Value of a Stock.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|
app.py
ADDED
@@ -0,0 +1,345 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Importing required modules
|
2 |
+
import pandas as pd
|
3 |
+
import numpy as np
|
4 |
+
import numpy as np
|
5 |
+
import plotly.express as px
|
6 |
+
|
7 |
+
# To extract and parse fundamental data like beta and growth estimates from finviz website
|
8 |
+
import requests
|
9 |
+
from bs4 import BeautifulSoup as bs
|
10 |
+
|
11 |
+
# For parsing financial statements data from financialmodelingprep api
|
12 |
+
from urllib.request import urlopen
|
13 |
+
import json
|
14 |
+
|
15 |
+
# For Gradio App
|
16 |
+
import gradio as gr
|
17 |
+
|
18 |
+
import os
|
19 |
+
# uncomment and set API Key in the environment variable below
|
20 |
+
# or you can choose to set it using any other method you know
|
21 |
+
#os.environ['FMP_API_KEY'] = "your_api_key"
|
22 |
+
|
23 |
+
# read the environment variable to use in API requests later
|
24 |
+
apiKey = os.environ['FMP_API_KEY']
|
25 |
+
|
26 |
+
|
27 |
+
############################################################################################################
|
28 |
+
###### GET DATA FROM FINANCIAL MODELING PREP
|
29 |
+
############################################################################################################
|
30 |
+
|
31 |
+
# Financialmodelingprep api url
|
32 |
+
base_url = "https://financialmodelingprep.com/api/v3/"
|
33 |
+
|
34 |
+
def get_jsonparsed_data(url):
|
35 |
+
response = urlopen(url)
|
36 |
+
data = response.read().decode("utf-8")
|
37 |
+
return json.loads(data)
|
38 |
+
|
39 |
+
# get financial statements using financial modelling prep API
|
40 |
+
def get_financial_statements(ticker):
|
41 |
+
# quarterly cash flow statements for calculating latest trailing twelve months (TTM) free cash flow
|
42 |
+
columns_drop = ['acceptedDate', 'period', 'symbol', 'reportedCurrency', 'cik', 'fillingDate', 'depreciationAndAmortization']
|
43 |
+
q_cash_flow_statement = pd.DataFrame(get_jsonparsed_data(base_url+'cash-flow-statement/' + ticker + '?period=quarter' + '&apikey=' + apiKey))
|
44 |
+
q_cash_flow_statement = q_cash_flow_statement.set_index('date').drop(columns_drop, axis=1).iloc[:4] # extract for last 4 quarters
|
45 |
+
latest_year = int(q_cash_flow_statement.iloc[0]['calendarYear'])
|
46 |
+
|
47 |
+
# annual cash flow statements
|
48 |
+
cash_flow_statement = pd.DataFrame(get_jsonparsed_data(base_url+'cash-flow-statement/' + ticker + '?apikey=' + apiKey))
|
49 |
+
cash_flow_statement = cash_flow_statement.set_index('date').drop(columns_drop, axis=1)
|
50 |
+
|
51 |
+
# combine annual and latest TTM cash flow statements
|
52 |
+
ttm_cash_flow_statement = q_cash_flow_statement.sum() # sum up last 4 quarters to get TTM cash flow
|
53 |
+
cash_flow_statement = cash_flow_statement[::-1].append(ttm_cash_flow_statement.rename('TTM')).drop(['netIncome'], axis=1)
|
54 |
+
final_cash_flow_statement = cash_flow_statement[::-1] # reverse list to show most recent ones first
|
55 |
+
|
56 |
+
# quarterly balance sheet statements
|
57 |
+
columns_drop = ['acceptedDate', 'calendarYear', 'period', 'symbol', 'reportedCurrency', 'cik', 'fillingDate']
|
58 |
+
q_balance_statement = pd.DataFrame(get_jsonparsed_data(base_url+'balance-sheet-statement/' + ticker + '?' + '&apikey=' + apiKey))
|
59 |
+
q_balance_statement = q_balance_statement.set_index('date').drop(columns_drop, axis=1)
|
60 |
+
q_balance_statement = q_balance_statement.apply(pd.to_numeric, errors='coerce')
|
61 |
+
|
62 |
+
return q_cash_flow_statement, cash_flow_statement, final_cash_flow_statement, q_balance_statement, latest_year
|
63 |
+
|
64 |
+
|
65 |
+
# check stability of cash flows
|
66 |
+
def plot_cash_flow(ticker, cash_flow_statement):
|
67 |
+
# DCF model works best only if the free cash flows are POSITIVE, STABLE and STEADILY INCREASING.
|
68 |
+
# So let's plot the graph and verify if this is the case.
|
69 |
+
fig_cash_flow = px.bar(cash_flow_statement , y='freeCashFlow', title=ticker + ' Free Cash Flows')
|
70 |
+
fig_cash_flow.update_xaxes(type='category', tickangle=270, title='Date')
|
71 |
+
fig_cash_flow.update_yaxes(title='Free Cash Flows')
|
72 |
+
#fig_cash_flow.show()
|
73 |
+
return fig_cash_flow
|
74 |
+
|
75 |
+
|
76 |
+
# get ttm cash flow, most recent total debt and cash & short term investment data from statements
|
77 |
+
def get_statements_data(final_cash_flow_statement, q_balance_statement):
|
78 |
+
cash_flow = final_cash_flow_statement.iloc[0]['freeCashFlow'] # ttm cash flow
|
79 |
+
total_debt = q_balance_statement.iloc[0]['totalDebt']
|
80 |
+
cash_and_ST_investments = q_balance_statement.iloc[0]['cashAndShortTermInvestments']
|
81 |
+
return cash_flow, total_debt, cash_and_ST_investments
|
82 |
+
|
83 |
+
|
84 |
+
############################################################################################################
|
85 |
+
###### GET DATA FROM FINVIZ WEBSITE
|
86 |
+
############################################################################################################
|
87 |
+
|
88 |
+
# Price, EPS next Y/5Y, Beta, Number of Shares Outstanding
|
89 |
+
# Extract (using requests.get) and Parse (using Beautiful Soup) data from Finviz table in the Finviz website (see screenshot above), needed to calculate intrinsic value of stock.
|
90 |
+
|
91 |
+
# List of data we want to extract from Finviz Table
|
92 |
+
# Price is the current stock price
|
93 |
+
# EPS next Y is the estimated earnings growth for next year
|
94 |
+
# EPS next 5Y is the estimated earnings growth for next 5 years (if this is not present on finviz, we will use EPS next Y instead)
|
95 |
+
# Beta captures the volatility of the stock, used for estimating discount rate later
|
96 |
+
# Shs Outstand is the number of shares present in the market
|
97 |
+
metric = ['Price', 'EPS next Y', 'EPS next 5Y', 'Beta', 'Shs Outstand']
|
98 |
+
|
99 |
+
def fundamental_metric(soup, metric):
|
100 |
+
# the table which stores the data in Finviz has html table attribute class of 'snapshot-td2'
|
101 |
+
return soup.find_all(text = metric)[-1].find_next(class_='snapshot-td2').text
|
102 |
+
|
103 |
+
# get above metrics from finviz and store as a dict
|
104 |
+
def get_finviz_data(ticker):
|
105 |
+
try:
|
106 |
+
url = ("http://finviz.com/quote.ashx?t=" + ticker.lower())
|
107 |
+
soup = bs(requests.get(url,headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0'}).content)
|
108 |
+
dict_finviz = {}
|
109 |
+
for m in metric:
|
110 |
+
dict_finviz[m] = fundamental_metric(soup,m)
|
111 |
+
for key, value in dict_finviz.items():
|
112 |
+
# replace percentages
|
113 |
+
if (value[-1]=='%'):
|
114 |
+
dict_finviz[key] = value[:-1]
|
115 |
+
dict_finviz[key] = float(dict_finviz[key])
|
116 |
+
# billion
|
117 |
+
if (value[-1]=='B'):
|
118 |
+
dict_finviz[key] = value[:-1]
|
119 |
+
dict_finviz[key] = float(dict_finviz[key])*1000000000
|
120 |
+
# million
|
121 |
+
if (value[-1]=='M'):
|
122 |
+
dict_finviz[key] = value[:-1]
|
123 |
+
dict_finviz[key] = float(dict_finviz[key])*1000000
|
124 |
+
try:
|
125 |
+
dict_finviz[key] = float(dict_finviz[key])
|
126 |
+
except:
|
127 |
+
pass
|
128 |
+
except Exception as e:
|
129 |
+
print (e)
|
130 |
+
print ('Not successful parsing ' + ticker + ' data.')
|
131 |
+
return dict_finviz
|
132 |
+
|
133 |
+
|
134 |
+
def parse_finviz_dict(finviz_dict):
|
135 |
+
EPS_growth_5Y = finviz_dict['EPS next 5Y']
|
136 |
+
# sometimes EPS next 5Y is empty and shows as a '-' string, in this case use EPS next Y
|
137 |
+
if isinstance(EPS_growth_5Y, str):
|
138 |
+
if not EPS_growth_5Y.isdigit():
|
139 |
+
EPS_growth_5Y = finviz_dict['EPS next Y']
|
140 |
+
EPS_growth_6Y_to_10Y = EPS_growth_5Y/2 # Half the previous growth rate, conservative estimate
|
141 |
+
#EPS_growth_11Y_to_20Y = np.minimum(EPS_growth_6Y_to_10Y, 4) # Slightly higher than long term inflation rate, conservative estimate
|
142 |
+
long_term_growth_rate = np.minimum(EPS_growth_6Y_to_10Y, 3) # Slightly higher than long term inflation rate, conservative estimate
|
143 |
+
shares_outstanding = finviz_dict['Shs Outstand']
|
144 |
+
beta = finviz_dict['Beta']
|
145 |
+
current_price = finviz_dict['Price']
|
146 |
+
|
147 |
+
return EPS_growth_5Y, EPS_growth_6Y_to_10Y, long_term_growth_rate, beta, shares_outstanding, current_price
|
148 |
+
|
149 |
+
|
150 |
+
## Estimate Discount Rate from Beta
|
151 |
+
def estimate_discount_rate(beta):
|
152 |
+
# Beta shows the volatility of the stock,
|
153 |
+
# the higher the beta, we want to be more conservative by increasing the discount rate also.
|
154 |
+
discount_rate = 7
|
155 |
+
if(beta<0.80):
|
156 |
+
discount_rate = 5
|
157 |
+
elif(beta>=0.80 and beta<1):
|
158 |
+
discount_rate = 6
|
159 |
+
elif(beta>=1 and beta<1.1):
|
160 |
+
discount_rate = 6.5
|
161 |
+
elif(beta>=1.1 and beta<1.2):
|
162 |
+
discount_rate = 7
|
163 |
+
elif(beta>=1.2 and beta<1.3):
|
164 |
+
discount_rate = 7.5
|
165 |
+
elif(beta>=1.3 and beta<1.4):
|
166 |
+
discount_rate = 8
|
167 |
+
elif(beta>=1.4 and beta<1.6):
|
168 |
+
discount_rate = 8.5
|
169 |
+
elif(beta>=1.61):
|
170 |
+
discount_rate = 9
|
171 |
+
|
172 |
+
return discount_rate
|
173 |
+
|
174 |
+
|
175 |
+
############################################################################################################
|
176 |
+
## Calculate Intrinsic Value
|
177 |
+
############################################################################################################
|
178 |
+
|
179 |
+
# 1. First Project Cash Flows from Year 1 to Year 10 using Present (TTM) Free Cash Flow
|
180 |
+
# 2. Discount the Cash Flows to Present Value
|
181 |
+
# 3. Calculate the Terminal Value after Year 10 (Discounted to Present Value) Assuming the Company will Grow at a Constant Steady Rate Forever (https://corporatefinanceinstitute.com/resources/financial-modeling/dcf-terminal-value-formula/)
|
182 |
+
# 4. Add the Cash Flows and the Terminal Value Up
|
183 |
+
# 5. Then Account for the Cash + Short Term Investments and Subtract Total Debt
|
184 |
+
# 6. Divide by Total Number of Shares Outstanding
|
185 |
+
|
186 |
+
def calculate_intrinsic_value(latest_year, cash_flow, total_debt, cash_and_ST_investments,
|
187 |
+
EPS_growth_5Y, EPS_growth_6Y_to_10Y, long_term_growth_rate,
|
188 |
+
shares_outstanding, discount_rate, current_price):
|
189 |
+
|
190 |
+
# Convert all percentages to decmials
|
191 |
+
EPS_growth_5Y_d = EPS_growth_5Y/100
|
192 |
+
EPS_growth_6Y_to_10Y_d = EPS_growth_6Y_to_10Y/100
|
193 |
+
long_term_growth_rate_d = long_term_growth_rate/100
|
194 |
+
discount_rate_d = discount_rate/100
|
195 |
+
# print("Discounted Cash Flows\n")
|
196 |
+
|
197 |
+
# Lists of projected cash flows from year 1 to year 20
|
198 |
+
cash_flow_list = []
|
199 |
+
cash_flow_discounted_list = []
|
200 |
+
year_list = []
|
201 |
+
|
202 |
+
# Years 1 to 5
|
203 |
+
for year in range(1, 6):
|
204 |
+
year_list.append(year + latest_year)
|
205 |
+
cash_flow*=(1 + EPS_growth_5Y_d)
|
206 |
+
cash_flow_list.append(cash_flow)
|
207 |
+
cash_flow_discounted = cash_flow/((1 + discount_rate_d)**year)
|
208 |
+
cash_flow_discounted_list.append(cash_flow_discounted)
|
209 |
+
# print("Year " + str(year + latest_year) + ": $" + str(cash_flow_discounted)) ## Print out the projected discounted cash flows
|
210 |
+
|
211 |
+
# Years 6 to 10
|
212 |
+
for year in range(6, 11):
|
213 |
+
year_list.append(year + latest_year)
|
214 |
+
cash_flow*=(1 + EPS_growth_6Y_to_10Y_d)
|
215 |
+
cash_flow_list.append(cash_flow)
|
216 |
+
cash_flow_discounted = cash_flow/((1 + discount_rate_d)**year)
|
217 |
+
cash_flow_discounted_list.append(cash_flow_discounted)
|
218 |
+
# print("Year " + str(year + latest_year) + ": $" + str(cash_flow_discounted)) ## Print out the projected discounted cash flows
|
219 |
+
|
220 |
+
# Store all forecasted cash flows in dataframe
|
221 |
+
forecast_cash_flows_df = pd.DataFrame.from_dict({'Year': year_list, 'Cash Flow': cash_flow_list, 'Discounted Cash Flow': cash_flow_discounted_list})
|
222 |
+
forecast_cash_flows_df = forecast_cash_flows_df.set_index('Year')
|
223 |
+
|
224 |
+
# Growth in Perpuity Approach
|
225 |
+
cashflow_10Y = cash_flow_discounted_list[-1]
|
226 |
+
# Formula to Calculate: https://corporatefinanceinstitute.com/resources/financial-modeling/dcf-terminal-value-formula/
|
227 |
+
terminal_value = cashflow_10Y*(1+long_term_growth_rate_d)/(discount_rate_d-long_term_growth_rate_d)
|
228 |
+
|
229 |
+
# Yay finally
|
230 |
+
intrinsic_value = (sum(cash_flow_discounted_list) + terminal_value - total_debt + cash_and_ST_investments)/shares_outstanding
|
231 |
+
margin_of_safety = (1-current_price/intrinsic_value)*100
|
232 |
+
|
233 |
+
return forecast_cash_flows_df, terminal_value, intrinsic_value, margin_of_safety
|
234 |
+
|
235 |
+
|
236 |
+
# Plot forecasted cash flows from years 1 to 10, as well as the discounted cash flows
|
237 |
+
def plot_forecasted_cash_flows(ticker, forecast_cash_flows_df):
|
238 |
+
|
239 |
+
fig_cash_forecast = px.bar(forecast_cash_flows_df, barmode='group', title=ticker + ' Projected Free Cash Flows')
|
240 |
+
fig_cash_forecast.update_xaxes(type='category', tickangle=270)
|
241 |
+
fig_cash_forecast.update_xaxes(tickangle=270, title='Forecasted Year')
|
242 |
+
fig_cash_forecast.update_yaxes(title='Free Cash Flows')
|
243 |
+
# fig_cash_forecast.show()
|
244 |
+
|
245 |
+
return fig_cash_forecast
|
246 |
+
|
247 |
+
|
248 |
+
# chain all the steps from the functions above together
|
249 |
+
def run_all_steps(ticker):
|
250 |
+
q_cash_flow_statement, cash_flow_statement, final_cash_flow_statement, q_balance_statement, latest_year = get_financial_statements(ticker)
|
251 |
+
|
252 |
+
fig_cash_flow = plot_cash_flow(ticker, cash_flow_statement)
|
253 |
+
|
254 |
+
cash_flow, total_debt, cash_and_ST_investments = get_statements_data(final_cash_flow_statement, q_balance_statement)
|
255 |
+
|
256 |
+
finviz_dict = get_finviz_data(ticker)
|
257 |
+
|
258 |
+
EPS_growth_5Y, EPS_growth_6Y_to_10Y, long_term_growth_rate, beta, shares_outstanding, current_price = parse_finviz_dict(finviz_dict)
|
259 |
+
|
260 |
+
discount_rate = estimate_discount_rate(beta)
|
261 |
+
|
262 |
+
forecast_cash_flows_df, terminal_value, intrinsic_value, margin_of_safety = calculate_intrinsic_value(latest_year, cash_flow, total_debt, cash_and_ST_investments,
|
263 |
+
EPS_growth_5Y, EPS_growth_6Y_to_10Y, long_term_growth_rate,
|
264 |
+
shares_outstanding, discount_rate, current_price)
|
265 |
+
|
266 |
+
fig_cash_forecast = plot_forecasted_cash_flows(ticker, forecast_cash_flows_df)
|
267 |
+
|
268 |
+
return q_cash_flow_statement.reset_index(), final_cash_flow_statement.reset_index(), q_balance_statement.reset_index(), fig_cash_flow, \
|
269 |
+
str(EPS_growth_5Y) + '%' , str(EPS_growth_6Y_to_10Y) + '%', str(long_term_growth_rate) + '%', \
|
270 |
+
beta, shares_outstanding, current_price, \
|
271 |
+
discount_rate, forecast_cash_flows_df.reset_index(), terminal_value, intrinsic_value, fig_cash_forecast, margin_of_safety
|
272 |
+
|
273 |
+
|
274 |
+
# Gradio App and UI
|
275 |
+
with gr.Blocks() as app:
|
276 |
+
with gr.Row():
|
277 |
+
gr.HTML("<h1>Bohmian's Stock Intrinsic Value Calculator</h1>")
|
278 |
+
|
279 |
+
with gr.Row():
|
280 |
+
ticker = gr.Textbox("AAPL", label='Enter stock ticker to calculate its intrinsic value e.g. "AAPL"')
|
281 |
+
btn = gr.Button("Calculate Intrinsic Value")
|
282 |
+
|
283 |
+
# Show intrinsic value calculation results
|
284 |
+
with gr.Row():
|
285 |
+
gr.HTML("<h2>Calculated Intrinsic Value</h2>")
|
286 |
+
|
287 |
+
with gr.Row():
|
288 |
+
intrinsic_value = gr.Text(label="Intrinsic Value")
|
289 |
+
current_price = gr.Text(label="Actual Stock Price")
|
290 |
+
margin_of_safety = gr.Text(label="Margin of Safety")
|
291 |
+
|
292 |
+
# Show metrics obtained and estimated from FinViz website that were essential for calculations
|
293 |
+
with gr.Row():
|
294 |
+
gr.HTML("<h2>Metrics Obtained (and Estimated) from FinViz Website</h2>")
|
295 |
+
with gr.Row():
|
296 |
+
gr.HTML("<h3>https://finviz.com/</h3>")
|
297 |
+
|
298 |
+
with gr.Row():
|
299 |
+
EPS_growth_5Y = gr.Text(label="EPS Next 5Y (Estimated EPS growth for next 5 years)")
|
300 |
+
EPS_growth_6Y_to_10Y = gr.Text(label="EPS growth for 6th to 10th year (estimated as half of above)")
|
301 |
+
long_term_growth_rate = gr.Text(label="Long Term Growth Rate (estimated as half of above or 3%, whichever is lower)")
|
302 |
+
|
303 |
+
with gr.Row():
|
304 |
+
beta = gr.Text(label="Beta (Measures volatility of stock)")
|
305 |
+
discount_rate = gr.Text(label="Discount Rate (estimated from beta)")
|
306 |
+
shares_outstanding = gr.Text(label="Shares Outstanding")
|
307 |
+
|
308 |
+
|
309 |
+
# Show detailed actual historical financial statements
|
310 |
+
with gr.Row():
|
311 |
+
gr.HTML("<h2>Actual Historical Financial Statements Data</h2>")
|
312 |
+
with gr.Row():
|
313 |
+
gr.HTML("<h3>IMPORTANT NOTE: DCF model works best only if the free cash flows are POSITIVE, STABLE and STEADILY INCREASING. Check if this is the case.</h3>")
|
314 |
+
|
315 |
+
with gr.Row():
|
316 |
+
fig_cash_flow = gr.Plot(label="Historical Cash Flows")
|
317 |
+
|
318 |
+
with gr.Row():
|
319 |
+
q_cash_flow_statement = gr.DataFrame(label="Last 4 Quarterly Cash Flow Statements")
|
320 |
+
|
321 |
+
with gr.Row():
|
322 |
+
final_cash_flow_statement = gr.DataFrame(label="TTM + Annual Cash Flow Statements")
|
323 |
+
|
324 |
+
with gr.Row():
|
325 |
+
q_balance_statement = gr.DataFrame(label="Quarterly Balance Statements")
|
326 |
+
|
327 |
+
|
328 |
+
# Show forecasted cash flows and terminal value
|
329 |
+
with gr.Row():
|
330 |
+
gr.HTML("<h2>Forecasted Cash Flows for Next 10 Years</h2>")
|
331 |
+
|
332 |
+
with gr.Row():
|
333 |
+
fig_cash_forecast = gr.Plot(label="Forecasted Cash Flows")
|
334 |
+
forecast_cash_flows_df = gr.DataFrame(label="Forecasted Cash Flows")
|
335 |
+
|
336 |
+
with gr.Row():
|
337 |
+
terminal_value = gr.Text(label="Terminal Value (after 10th year)")
|
338 |
+
|
339 |
+
|
340 |
+
btn.click(fn=run_all_steps, inputs=[ticker],
|
341 |
+
outputs=[q_cash_flow_statement, final_cash_flow_statement, q_balance_statement, fig_cash_flow, \
|
342 |
+
EPS_growth_5Y, EPS_growth_6Y_to_10Y, long_term_growth_rate, beta, shares_outstanding, current_price, \
|
343 |
+
discount_rate, forecast_cash_flows_df, terminal_value, intrinsic_value, fig_cash_forecast, margin_of_safety])
|
344 |
+
|
345 |
+
app.launch()
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
pandas
|
2 |
+
plotly
|
3 |
+
bs4
|