Space58 / app.py
QuantumLearner's picture
Update app.py
2efb42a verified
import streamlit as st
import pandas as pd
import plotly.express as px
import requests
import os
# Optional environment key
API_KEY = os.getenv("FMP_API_KEY")
# Page config
st.set_page_config(page_title="Financial Growth Metrics", layout="wide")
# ----------------------------
# Caching function with session_state
# ----------------------------
def fetch_data(url, cache_key):
"""Load data from session_state if cached, else fetch from URL."""
if cache_key in st.session_state:
return st.session_state[cache_key]
try:
resp = requests.get(url)
resp.raise_for_status()
data = resp.json()
st.session_state[cache_key] = data
return data
except requests.exceptions.RequestException:
st.session_state[cache_key] = []
return []
# ----------------------------
# Helper for interpretations
# ----------------------------
def interpret_growth_metrics(df, metric_list, section_title):
existing_cols = [m for m in metric_list if m in df.columns]
if not existing_cols or df.empty:
return f"**{section_title}**: Data not available."
df_valid = df[['date'] + existing_cols].dropna(subset=existing_cols, how='all')
if df_valid.empty:
return f"**{section_title}**: No valid data entries."
df_valid = df_valid.sort_values("date")
latest_row = df_valid.iloc[-1]
latest_date = latest_row['date']
if len(df_valid) > 1:
prior_row = df_valid.iloc[-2]
prior_date = prior_row['date']
else:
prior_row = None
prior_date = None
# Basic stats
values_only = df_valid[existing_cols].astype(float)
mean_vals = values_only.mean()
min_vals = values_only.min()
max_vals = values_only.max()
std_vals = values_only.std()
text = f"##### {section_title}\n\n"
text += "**Recent Data:**\n"
text += f"- **Latest Record Date:** {latest_date.date()}\n"
for col in existing_cols:
latest_val = latest_row[col]
if pd.isna(latest_val):
text += f"- **{col}:** Missing in latest record.\n"
else:
text += f"- **{col}:** {latest_val:.2f}\n"
if prior_row is not None:
text += f"\n**Comparison with previous record ({prior_date.date()}):**\n"
for col in existing_cols:
latest_val = latest_row[col]
prior_val = prior_row[col]
if pd.isna(latest_val) or pd.isna(prior_val):
text += f"- **{col}:** No comparison (missing data).\n"
else:
diff = latest_val - prior_val
if diff > 0:
text += f"- **{col}:** Increased by {diff:.2f}.\n"
elif diff < 0:
text += f"- **{col}:** Decreased by {abs(diff):.2f}.\n"
else:
text += f"- **{col}:** No change.\n"
text += "\n**Historical Summary:**\n"
for col in existing_cols:
text += (f"- **{col}:** Mean={mean_vals[col]:.2f}, "
f"Min={min_vals[col]:.2f}, Max={max_vals[col]:.2f}, "
f"StdDev={std_vals[col]:.2f}\n")
text += "\n**Final Interpretation:**\n"
text += "- Track these changes over time.\n"
return text
# ----------------------------
# Page Functions
# ----------------------------
def show_financial_growth(symbol, period):
url = f"https://financialmodelingprep.com/api/v3/financial-growth/{symbol}?period={period}&apikey={API_KEY}"
data = fetch_data(url, f"financial_growth_{symbol}_{period}")
if not data:
st.error("No data returned. Check symbol or period.")
return
df = pd.DataFrame(data)
if "date" in df.columns:
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df.sort_values("date", inplace=True)
st.success("Data loaded successfully.")
st.write("Below are key growth metrics. Expand each section for interpretation.")
# 1. Profitability
st.subheader("1. Profitability")
profitability_vars = ["revenueGrowth", "grossProfitGrowth", "ebitgrowth",
"operatingIncomeGrowth", "netIncomeGrowth"]
try:
fig1 = px.line(df, x="date", y=profitability_vars, title="Profitability Metrics")
fig1.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig1, use_container_width=True)
except Exception:
st.error("Could not plot Profitability Metrics.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, profitability_vars, "Profitability Metrics"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in profitability_vars if c in df.columns]
st.dataframe(df[cols])
# 2. EPS
st.subheader("2. Earnings Per Share")
eps_vars = ["epsgrowth", "epsdilutedGrowth"]
try:
fig2 = px.line(df, x="date", y=eps_vars, title="EPS Metrics")
fig2.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig2, use_container_width=True)
except Exception:
st.error("Could not plot EPS Metrics.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, eps_vars, "EPS Metrics"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in eps_vars if c in df.columns]
st.dataframe(df[cols])
# 3. Share Count
st.subheader("3. Share Count")
share_vars = ["weightedAverageSharesGrowth", "weightedAverageSharesDilutedGrowth"]
try:
fig3 = px.line(df, x="date", y=share_vars, title="Share Count Adjustments")
fig3.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig3, use_container_width=True)
except Exception:
st.error("Could not plot Share Count.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, share_vars, "Share Count Adjustments"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in share_vars if c in df.columns]
st.dataframe(df[cols])
# 4. Dividend
st.subheader("4. Dividend per Share")
div_vars = ["dividendsperShareGrowth"]
try:
fig4 = px.line(df, x="date", y=div_vars, title="Dividend Growth")
fig4.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig4, use_container_width=True)
except Exception:
st.error("Could not plot Dividend Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, div_vars, "Dividend Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in div_vars if c in df.columns]
st.dataframe(df[cols])
# 5. Cash Flow
st.subheader("5. Cash Flow")
cashflow_vars = ["operatingCashFlowGrowth", "freeCashFlowGrowth"]
try:
fig5 = px.line(df, x="date", y=cashflow_vars, title="Cash Flow Metrics")
fig5.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig5, use_container_width=True)
except Exception:
st.error("Could not plot Cash Flow Metrics.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, cashflow_vars, "Cash Flow Metrics"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in cashflow_vars if c in df.columns]
st.dataframe(df[cols])
# 6. Multi-Year Growth (Per Share)
st.subheader("6. Multi-Year Growth (Per Share)")
multi_year_groups = {
"Revenue Growth": [
"tenYRevenueGrowthPerShare", "fiveYRevenueGrowthPerShare",
"threeYRevenueGrowthPerShare"
],
"Operating Cash Flow Growth": [
"tenYOperatingCFGrowthPerShare", "fiveYOperatingCFGrowthPerShare",
"threeYOperatingCFGrowthPerShare"
],
"Net Income Growth": [
"tenYNetIncomeGrowthPerShare", "fiveYNetIncomeGrowthPerShare",
"threeYNetIncomeGrowthPerShare"
],
"Shareholders’ Equity Growth": [
"tenYShareholdersEquityGrowthPerShare", "fiveYShareholdersEquityGrowthPerShare",
"threeYShareholdersEquityGrowthPerShare"
],
"Dividend per Share Growth": [
"tenYDividendperShareGrowthPerShare", "fiveYDividendperShareGrowthPerShare",
"threeYDividendperShareGrowthPerShare"
]
}
for subgroup, vars_list in multi_year_groups.items():
st.markdown(f"**{subgroup}**")
try:
fig = px.line(df, x="date", y=vars_list, title=subgroup)
fig.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig, use_container_width=True)
except Exception:
st.error(f"Could not plot chart for {subgroup}.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, vars_list, subgroup))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in vars_list if c in df.columns]
st.dataframe(df[cols])
# 7. Balance Sheet
st.subheader("7. Balance Sheet")
balance_vars = ["receivablesGrowth", "inventoryGrowth", "assetGrowth",
"bookValueperShareGrowth", "debtGrowth"]
try:
fig7 = px.line(df, x="date", y=balance_vars, title="Balance Sheet Metrics")
fig7.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig7, use_container_width=True)
except Exception:
st.error("Could not plot Balance Sheet Metrics.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, balance_vars, "Balance Sheet Metrics"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in balance_vars if c in df.columns]
st.dataframe(df[cols])
# 8. Expense
st.subheader("8. Expense")
expense_vars = ["rdexpenseGrowth", "sgaexpensesGrowth"]
try:
fig8 = px.line(df, x="date", y=expense_vars, title="Expense Metrics")
fig8.update_layout(xaxis_title="Date", yaxis_title="Growth Rate", legend_title="Metric")
st.plotly_chart(fig8, use_container_width=True)
except Exception:
st.error("Could not plot Expense Metrics.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, expense_vars, "Expense Metrics"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in expense_vars if c in df.columns]
st.dataframe(df[cols])
def show_balance_sheet_growth(symbol, period):
url = f"https://financialmodelingprep.com/api/v3/balance-sheet-statement-growth/{symbol}?period={period}&apikey={API_KEY}"
data = fetch_data(url, f"balance_sheet_growth_{symbol}_{period}")
if not data:
st.error("No data returned. Check symbol or period.")
return
df = pd.DataFrame(data)
if "date" in df.columns:
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df.sort_values("date", inplace=True)
st.success("Data loaded successfully.")
st.write("These sections show balance sheet growth metrics.")
# 1. Asset Growth
st.subheader("1. Asset Growth")
asset_vars = [
"growthCashAndCashEquivalents", "growthShortTermInvestments",
"growthCashAndShortTermInvestments", "growthNetReceivables",
"growthInventory", "growthTotalCurrentAssets",
"growthPropertyPlantEquipmentNet", "growthTotalNonCurrentAssets",
"growthTotalAssets"
]
try:
fig_a = px.line(df, x="date", y=asset_vars, title="Asset Growth")
fig_a.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_a, use_container_width=True)
except Exception:
st.error("Could not plot Asset Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, asset_vars, "Asset Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in asset_vars if c in df.columns]
st.dataframe(df[cols])
# 2. Liability Growth
st.subheader("2. Liability Growth")
liability_vars = [
"growthAccountPayables", "growthShortTermDebt", "growthTaxPayables",
"growthTotalCurrentLiabilities", "growthLongTermDebt",
"growthTotalNonCurrentLiabilities", "growthTotalLiabilities"
]
try:
fig_l = px.line(df, x="date", y=liability_vars, title="Liability Growth")
fig_l.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_l, use_container_width=True)
except Exception:
st.error("Could not plot Liability Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, liability_vars, "Liability Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in liability_vars if c in df.columns]
st.dataframe(df[cols])
# 3. Equity Growth
st.subheader("3. Equity Growth")
equity_vars = [
"growthCommonStock", "growthRetainedEarnings",
"growthAccumulatedOtherComprehensiveIncomeLoss",
"growthTotalStockholdersEquity"
]
try:
fig_e = px.line(df, x="date", y=equity_vars, title="Equity Growth")
fig_e.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_e, use_container_width=True)
except Exception:
st.error("Could not plot Equity Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, equity_vars, "Equity Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in equity_vars if c in df.columns]
st.dataframe(df[cols])
# 4. Debt Metrics
st.subheader("4. Debt Metrics")
debt_vars = ["growthTotalDebt", "growthNetDebt"]
try:
fig_d = px.line(df, x="date", y=debt_vars, title="Debt Metrics")
fig_d.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_d, use_container_width=True)
except Exception:
st.error("Could not plot Debt Metrics.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, debt_vars, "Debt Metrics"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in debt_vars if c in df.columns]
st.dataframe(df[cols])
def show_income_growth(symbol, period):
url = f"https://financialmodelingprep.com/api/v3/income-statement-growth/{symbol}?period={period}&apikey={API_KEY}"
data = fetch_data(url, f"income_growth_{symbol}_{period}")
if not data:
st.error("No data returned. Check symbol or period.")
return
df = pd.DataFrame(data)
if "date" in df.columns:
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df.sort_values("date", inplace=True)
st.success("Data loaded successfully.")
st.write("These sections show income statement growth metrics.")
# 1. Profitability
st.subheader("1. Profitability")
profitability_vars = [
"growthRevenue", "growthGrossProfit", "growthOperatingIncome",
"growthNetIncome", "growthEBITDA"
]
try:
fig_p = px.line(df, x="date", y=profitability_vars, title="Profitability Growth")
fig_p.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_p, use_container_width=True)
except Exception:
st.error("Could not plot Profitability Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, profitability_vars, "Profitability Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in profitability_vars if c in df.columns]
st.dataframe(df[cols])
# 2. Expense
st.subheader("2. Expense")
expense_vars = [
"growthCostOfRevenue", "growthOperatingExpenses",
"growthResearchAndDevelopmentExpenses", "growthSellingAndMarketingExpenses"
]
try:
fig_e = px.line(df, x="date", y=expense_vars, title="Expense Growth")
fig_e.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_e, use_container_width=True)
except Exception:
st.error("Could not plot Expense Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, expense_vars, "Expense Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in expense_vars if c in df.columns]
st.dataframe(df[cols])
# 3. Net and Tax Metrics
st.subheader("3. Net and Tax Metrics")
net_tax_vars = ["growthIncomeBeforeTax", "growthIncomeTaxExpense",
"growthNetIncome", "growthNetIncomeRatio"]
try:
fig_n = px.line(df, x="date", y=net_tax_vars, title="Net Income and Tax Growth")
fig_n.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_n, use_container_width=True)
except Exception:
st.error("Could not plot Net Income/Tax Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, net_tax_vars, "Net Income/Tax Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in net_tax_vars if c in df.columns]
st.dataframe(df[cols])
# 4. EPS Growth
st.subheader("4. EPS Growth")
eps_vars = ["growthEPS", "growthEPSDiluted"]
try:
fig_eps = px.line(df, x="date", y=eps_vars, title="EPS Growth")
fig_eps.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_eps, use_container_width=True)
except Exception:
st.error("Could not plot EPS Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, eps_vars, "EPS Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in eps_vars if c in df.columns]
st.dataframe(df[cols])
def show_cashflow_growth(symbol, period):
url = f"https://financialmodelingprep.com/api/v3/cash-flow-statement-growth/{symbol}?period={period}&apikey={API_KEY}"
data = fetch_data(url, f"cashflow_growth_{symbol}_{period}")
if not data:
st.error("No data returned. Check symbol or period.")
return
df = pd.DataFrame(data)
if "date" in df.columns:
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df.sort_values("date", inplace=True)
st.success("Data loaded successfully.")
st.write("These sections show cash flow statement growth metrics.")
# 1. Operating Activities
st.subheader("1. Operating Activities")
operating_vars = [
"growthNetIncome", "growthDepreciationAndAmortization",
"growthChangeInWorkingCapital", "growthNetCashProvidedByOperatingActivites",
"growthOperatingCashFlow"
]
try:
fig_op = px.line(df, x="date", y=operating_vars, title="Operating Cash Flow Growth")
fig_op.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_op, use_container_width=True)
except Exception:
st.error("Could not plot Operating CF Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, operating_vars, "Operating CF Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in operating_vars if c in df.columns]
st.dataframe(df[cols])
# 2. Investing Activities
st.subheader("2. Investing Activities")
investing_vars = [
"growthInvestmentsInPropertyPlantAndEquipment", "growthAcquisitionsNet",
"growthPurchasesOfInvestments", "growthSalesMaturitiesOfInvestments",
"growthNetCashUsedForInvestingActivites"
]
try:
fig_inv = px.line(df, x="date", y=investing_vars, title="Investing Cash Flow Growth")
fig_inv.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_inv, use_container_width=True)
except Exception:
st.error("Could not plot Investing CF Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, investing_vars, "Investing CF Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in investing_vars if c in df.columns]
st.dataframe(df[cols])
# 3. Financing Activities
st.subheader("3. Financing Activities")
financing_vars = [
"growthDebtRepayment", "growthCommonStockRepurchased",
"growthDividendsPaid", "growthNetCashUsedProvidedByFinancingActivities"
]
try:
fig_fin = px.line(df, x="date", y=financing_vars, title="Financing Cash Flow Growth")
fig_fin.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_fin, use_container_width=True)
except Exception:
st.error("Could not plot Financing CF Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, financing_vars, "Financing CF Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in financing_vars if c in df.columns]
st.dataframe(df[cols])
# 4. Free Cash Flow
st.subheader("4. Free Cash Flow")
fcf_vars = ["growthFreeCashFlow"]
try:
fig_fcf = px.line(df, x="date", y=fcf_vars, title="Free Cash Flow Growth")
fig_fcf.update_layout(xaxis_title="Date", yaxis_title="Growth", legend_title="Metric")
st.plotly_chart(fig_fcf, use_container_width=True)
except Exception:
st.error("Could not plot Free Cash Flow Growth.")
with st.expander("Interpretation"):
st.markdown(interpret_growth_metrics(df, fcf_vars, "Free Cash Flow Growth"))
with st.expander("DataFrame"):
cols = ["date"] + [c for c in fcf_vars if c in df.columns]
st.dataframe(df[cols])
# ----------------------------
# Main
# ----------------------------
st.title("Financial Growth Metrics")
st.markdown("""
This dashboard shows key financial growth metrics across balance sheet,
income statement, and cash flow statement.
Use the sidebar to set inputs, then press **Run Analysis**.
After that, you can switch pages without re-running.
""")
# Sidebar Navigation
st.sidebar.header("Navigation")
page = st.sidebar.radio(
"Select Page",
["Financial Growth", "Balance Sheet Growth", "Income Growth", "Cash Flow Growth"],
index=0
)
st.sidebar.header("Inputs")
symbol = st.sidebar.text_input("Company Symbol", value="AAPL")
period = st.sidebar.selectbox("Period", options=["annual", "quarter"])
# Here is the run button
run_button = st.sidebar.button("Run Analysis")
# If user hasn't clicked "Run Analysis," do not load data
if not run_button and f"{page.lower().replace(' ', '_')}_{symbol}_{period}" not in st.session_state:
st.warning("Press 'Run Analysis' to fetch data and see the results.")
else:
# If user clicked "Run", or data is cached from a previous run, show the selected page
if page == "Financial Growth":
show_financial_growth(symbol, period)
elif page == "Balance Sheet Growth":
show_balance_sheet_growth(symbol, period)
elif page == "Income Growth":
show_income_growth(symbol, period)
elif page == "Cash Flow Growth":
show_cashflow_growth(symbol, period)
# Hide Streamlit default style
hide_streamlit_style = """
<style>
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
</style>
"""
st.markdown(hide_streamlit_style, unsafe_allow_html=True)