DCF-app / app.py
vikramlingam's picture
Upload 5 files
d98f7af verified
import gradio as gr
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from data_fetcher import DataFetcher
from valuation import DCFValuation
from utils import (format_number, format_metrics_table, create_price_chart,
format_financial_statement, create_financial_chart, create_spider_chart,
prepare_financial_table, create_key_metrics_chart, create_growth_chart,
create_margin_chart, create_multi_year_growth_chart, create_ratio_chart)
# Initialize classes
data_fetcher = DataFetcher()
dcf_valuation = DCFValuation()
def analyze_stock(ticker, growth_rate, discount_rate, projection_years, format_type):
# Close any existing matplotlib figures to prevent memory issues
plt.close('all')
try:
# Validate inputs
if not ticker:
return {"error": "Please enter a ticker symbol"}, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None
ticker = ticker.upper().strip()
# Fetch data
metrics = data_fetcher.get_key_metrics(ticker)
price_history = data_fetcher.get_price_history(ticker)
financial_statements = data_fetcher.get_financial_statements(ticker)
# Get currency symbol
currency_symbol = metrics.get('Currency Symbol', '$')
# Format metrics for display
formatted_metrics = format_metrics_table(metrics)
# Calculate DCF valuation
try:
fcf = data_fetcher.get_free_cash_flow(ticker)
shares_outstanding = metrics.get('Shares Outstanding', None)
if fcf is not None and shares_outstanding and shares_outstanding != 'N/A':
company_value = dcf_valuation.calculate_dcf(
fcf=fcf,
growth_rate=growth_rate/100, # Convert percentage to decimal
discount_rate=discount_rate/100, # Convert percentage to decimal
years=int(projection_years)
)
# Format valuation results
valuation_results = {
"Company Value": format_number(company_value, currency_symbol=currency_symbol, format_type=format_type),
"Current Market Cap": formatted_metrics.get("Market Cap", "N/A"),
"Free Cash Flow": format_number(fcf, currency_symbol=currency_symbol, format_type=format_type),
"Growth Rate": f"{growth_rate:.1f}%",
"Discount Rate": f"{discount_rate:.1f}%",
"Projection Years": int(projection_years)
}
if shares_outstanding:
per_share_value = dcf_valuation.calculate_per_share_value(company_value, shares_outstanding)
current_price = metrics.get('Current Price', None)
valuation_results["Estimated Share Value"] = f"{currency_symbol}{per_share_value:.2f}"
valuation_results["Current Share Price"] = f"{currency_symbol}{current_price:.2f}" if current_price else "N/A"
if current_price:
upside = (per_share_value / current_price - 1) * 100
valuation_results["Potential Upside"] = f"{upside:.1f}%"
else:
valuation_results = {"error": f"Insufficient data for DCF valuation. FCF: {fcf}, Shares: {shares_outstanding}"}
except Exception as e:
valuation_results = {"error": f"Valuation error: {str(e)}"}
# Create price chart
price_fig = create_price_chart(price_history)
# Create spider chart with enhanced metrics
spider_fig = create_spider_chart(metrics, f"{ticker} Financial Metrics")
# Prepare financial statements for display - Annual
annual_income_table = prepare_financial_table(
financial_statements['income_stmt'],
currency_symbol=currency_symbol,
format_type=format_type
)
annual_balance_table = prepare_financial_table(
financial_statements['balance_sheet'],
currency_symbol=currency_symbol,
format_type=format_type
)
annual_cash_flow_table = prepare_financial_table(
financial_statements['cash_flow'],
currency_symbol=currency_symbol,
format_type=format_type
)
# Prepare financial statements for display - Quarterly
quarterly_income_table = prepare_financial_table(
financial_statements['quarterly_income_stmt'],
currency_symbol=currency_symbol,
format_type=format_type
)
quarterly_balance_table = prepare_financial_table(
financial_statements['quarterly_balance_sheet'],
currency_symbol=currency_symbol,
format_type=format_type
)
quarterly_cash_flow_table = prepare_financial_table(
financial_statements['quarterly_cash_flow'],
currency_symbol=currency_symbol,
format_type=format_type
)
# Create financial charts with error handling
try:
income_fig = create_financial_chart(financial_statements['income_stmt'],
f"{ticker} Income Statement", 'bar')
except Exception as e:
income_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Error creating income statement chart: {str(e)}",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
balance_fig = create_financial_chart(financial_statements['balance_sheet'],
f"{ticker} Balance Sheet", 'bar')
except Exception as e:
balance_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Error creating balance sheet chart: {str(e)}",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
cash_flow_fig = create_financial_chart(financial_statements['cash_flow'],
f"{ticker} Cash Flow", 'bar')
except Exception as e:
cash_flow_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Error creating cash flow chart: {str(e)}",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
# Create quarterly financial charts with error handling
try:
q_income_fig = create_financial_chart(financial_statements['quarterly_income_stmt'],
f"{ticker} Quarterly Income Statement", 'bar')
except Exception as e:
q_income_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Quarterly income data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
q_balance_fig = create_financial_chart(financial_statements['quarterly_balance_sheet'],
f"{ticker} Quarterly Balance Sheet", 'bar')
except Exception as e:
q_balance_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Quarterly balance sheet data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
q_cash_flow_fig = create_financial_chart(financial_statements['quarterly_cash_flow'],
f"{ticker} Quarterly Cash Flow", 'bar')
except Exception as e:
q_cash_flow_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Quarterly cash flow data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
# Create additional analysis charts with error handling
try:
revenue_growth_fig = create_growth_chart(
financial_statements['income_stmt'],
'Total Revenue',
f"{ticker} Revenue Growth"
)
except Exception as e:
revenue_growth_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Revenue growth data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
margin_fig = create_margin_chart(
financial_statements['income_stmt'],
f"{ticker} Margin Analysis"
)
except Exception as e:
margin_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Margin analysis data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
# Create key metrics charts with error handling
try:
key_metrics_income = create_key_metrics_chart(
financial_statements['income_stmt'],
f"{ticker} Key Income Metrics",
['Total Revenue', 'Gross Profit', 'Operating Income', 'Net Income'],
currency_symbol
)
except Exception as e:
key_metrics_income = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Income metrics data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
key_metrics_balance = create_key_metrics_chart(
financial_statements['balance_sheet'],
f"{ticker} Key Balance Sheet Metrics",
['Total Assets', 'Total Liabilities Net Minority Interest', 'Total Equity Gross Minority Interest'],
currency_symbol
)
except Exception as e:
key_metrics_balance = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Balance sheet metrics data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
key_metrics_cash = create_key_metrics_chart(
financial_statements['cash_flow'],
f"{ticker} Key Cash Flow Metrics",
['Operating Cash Flow', 'Free Cash Flow', 'Capital Expenditures'],
currency_symbol
)
except Exception as e:
key_metrics_cash = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Cash flow metrics data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
# Create ratio charts with error handling
try:
profitability_fig = create_ratio_chart(
financial_statements['income_stmt'],
f"{ticker} Profitability Ratios",
'profitability'
)
except Exception as e:
profitability_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Profitability ratio data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
try:
efficiency_fig = create_ratio_chart(
financial_statements['balance_sheet'],
f"{ticker} Efficiency Ratios",
'efficiency'
)
except Exception as e:
efficiency_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Efficiency ratio data not available",
horizontalalignment='center', verticalalignment='center', fontsize=12)
plt.axis('off')
return (formatted_metrics, valuation_results, price_fig,
annual_income_table, annual_balance_table, annual_cash_flow_table,
quarterly_income_table, quarterly_balance_table, quarterly_cash_flow_table,
income_fig, balance_fig, cash_flow_fig,
q_income_fig, q_balance_fig, q_cash_flow_fig,
spider_fig, revenue_growth_fig, margin_fig,
key_metrics_income, key_metrics_balance, key_metrics_cash,
profitability_fig)
except Exception as e:
error_msg = {"error": f"Error: {str(e)}"}
# Create empty figures for all plots
empty_fig = plt.figure(figsize=(10, 6))
plt.text(0.5, 0.5, f"Error: {str(e)}",
horizontalalignment='center', verticalalignment='center', fontsize=14)
plt.axis('off')
return (error_msg, {"error": str(e)}, empty_fig,
{"error": "Data unavailable"}, {"error": "Data unavailable"}, {"error": "Data unavailable"},
{"error": "Data unavailable"}, {"error": "Data unavailable"}, {"error": "Data unavailable"},
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig, empty_fig)
# Create Gradio interface
with gr.Blocks(title="Stock DCF Valuation Tool") as app:
gr.Markdown("# Stock DCF Valuation Tool")
gr.Markdown("Enter a stock ticker and DCF assumptions to get a valuation")
with gr.Row():
with gr.Column(scale=1):
ticker_input = gr.Textbox(label="Stock Ticker (e.g., AAPL, RELIANCE.NS)", placeholder="Enter ticker...")
with gr.Row():
growth_rate = gr.Slider(minimum=0, maximum=250, value=15, step=1, label="Growth Rate (%)")
discount_rate = gr.Slider(minimum=5, maximum=20, value=10, step=0.1, label="Discount Rate (%)")
projection_years = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Projection Years")
format_type = gr.Radio(
["auto", "comma", "millions", "billions"],
label="Number Format",
value="millions"
)
analyze_button = gr.Button("Analyze Stock", variant="primary")
with gr.Column(scale=2):
with gr.Tabs():
with gr.TabItem("Key Metrics"):
metrics_output = gr.JSON(label="Key Metrics")
spider_chart = gr.Plot(label="Financial Metrics Radar")
with gr.TabItem("DCF Valuation"):
valuation_output = gr.JSON(label="DCF Valuation Results")
price_chart = gr.Plot(label="Price History")
with gr.TabItem("Annual Financials"):
with gr.Tabs():
with gr.TabItem("Income Statement"):
income_chart = gr.Plot(label="Income Statement Chart")
annual_income_output = gr.JSON(label="Annual Income Statement")
with gr.TabItem("Balance Sheet"):
balance_chart = gr.Plot(label="Balance Sheet Chart")
annual_balance_output = gr.JSON(label="Annual Balance Sheet")
with gr.TabItem("Cash Flow"):
cash_flow_chart = gr.Plot(label="Cash Flow Chart")
annual_cash_flow_output = gr.JSON(label="Annual Cash Flow")
with gr.TabItem("Quarterly Financials"):
with gr.Tabs():
with gr.TabItem("Income Statement"):
q_income_chart = gr.Plot(label="Quarterly Income Statement Chart")
quarterly_income_output = gr.JSON(label="Quarterly Income Statement")
with gr.TabItem("Balance Sheet"):
q_balance_chart = gr.Plot(label="Quarterly Balance Sheet Chart")
quarterly_balance_output = gr.JSON(label="Quarterly Balance Sheet")
with gr.TabItem("Cash Flow"):
q_cash_flow_chart = gr.Plot(label="Quarterly Cash Flow Chart")
quarterly_cash_flow_output = gr.JSON(label="Quarterly Cash Flow")
with gr.TabItem("Financial Analysis"):
with gr.Tabs():
with gr.TabItem("Revenue & Growth"):
revenue_growth_chart = gr.Plot(label="Revenue Growth")
key_metrics_income_chart = gr.Plot(label="Key Income Metrics")
with gr.TabItem("Profitability"):
margin_chart = gr.Plot(label="Margin Analysis")
profitability_chart = gr.Plot(label="Profitability Ratios")
with gr.TabItem("Balance Sheet Analysis"):
key_metrics_balance_chart = gr.Plot(label="Key Balance Sheet Metrics")
efficiency_chart = gr.Plot(label="Efficiency Ratios")
with gr.TabItem("Cash Flow Analysis"):
key_metrics_cash_chart = gr.Plot(label="Key Cash Flow Metrics")
# Define function to clear figures when app is closed
def on_close():
plt.close('all')
# Register the function to be called when the app is closed
app.load(on_close)
analyze_button.click(
analyze_stock,
inputs=[ticker_input, growth_rate, discount_rate, projection_years, format_type],
outputs=[
metrics_output,
valuation_output,
price_chart,
annual_income_output,
annual_balance_output,
annual_cash_flow_output,
quarterly_income_output,
quarterly_balance_output,
quarterly_cash_flow_output,
income_chart,
balance_chart,
cash_flow_chart,
q_income_chart,
q_balance_chart,
q_cash_flow_chart,
spider_chart,
revenue_growth_chart,
margin_chart,
key_metrics_income_chart,
key_metrics_balance_chart,
key_metrics_cash_chart,
profitability_chart
]
)
# Launch the app
if __name__ == "__main__":
app.launch()