bohmian commited on
Commit
d3a0b5f
Β·
verified Β·
1 Parent(s): 4ca82c3

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +155 -3
src/streamlit_app.py CHANGED
@@ -6,7 +6,7 @@ import streamlit as st
6
 
7
  st.set_page_config(layout="wide")
8
 
9
- # you need to save your FMP API Key into the respective environment variable to let it work
10
  apikey = os.environ["FMP_API_KEY"]
11
 
12
  def parse_json(url):
@@ -294,6 +294,145 @@ def draw_income_sankey(income_statement, symbol, height, font_size):
294
  )
295
  return fig
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  st.title("Financial Sankeys")
298
 
299
  symbol = st.sidebar.text_input("Ticker symbol", "AMZN").upper()
@@ -303,6 +442,8 @@ bs_height = st.sidebar.slider("Balance Sheet height", 500, 1500, 800)
303
  bs_font = st.sidebar.slider("Balance Sheet font size", 5, 15, 10)
304
  is_height = st.sidebar.slider("Income Statement height", 500, 1500, 600)
305
  is_font = st.sidebar.slider("Income Statement font size", 5, 15, 10)
 
 
306
 
307
  # where the data came from
308
  st.sidebar.markdown("## [Financial Modeling Prep API](https://site.financialmodelingprep.com/?utm_source=medium&utm_medium=medium&utm_campaign=damian8)\
@@ -319,7 +460,7 @@ if symbol:
319
  fig_bs = draw_balance_sankey(balance_sheet, symbol.upper(), bs_height, bs_font)
320
  st.plotly_chart(fig_bs, use_container_width=True)
321
  except Exception as e:
322
- st.error(f"Failed to fetch balance sheet: {e}")
323
 
324
  # Income Statement
325
  st.header(f"Income Statement β€” {symbol}")
@@ -329,4 +470,15 @@ if symbol:
329
  fig_is = draw_income_sankey(income_statement, symbol.upper(), is_height, is_font)
330
  st.plotly_chart(fig_is, use_container_width=True)
331
  except Exception as e:
332
- st.error(f"Failed to fetch income statement: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  st.set_page_config(layout="wide")
8
 
9
+ # get your API key from env
10
  apikey = os.environ["FMP_API_KEY"]
11
 
12
  def parse_json(url):
 
294
  )
295
  return fig
296
 
297
+ def draw_cashflow_sankey(cash_flow, symbol, height, font_size):
298
+ flows = [
299
+ # Operating Activities (Inflow)
300
+ ("Net Income", "Operating Activities", cash_flow["netIncome"]),
301
+ ("Depreciation & Amortization", "Operating Activities", cash_flow["depreciationAndAmortization"]),
302
+ ("Deferred Income Tax", "Operating Activities", cash_flow["deferredIncomeTax"]),
303
+ ("Stock-Based Compensation", "Operating Activities", cash_flow["stockBasedCompensation"]),
304
+ ("Change in Working Capital", "Operating Activities", cash_flow["changeInWorkingCapital"]),
305
+ ("Accounts Receivables Ξ”", "Operating Activities", cash_flow["accountsReceivables"]),
306
+ ("Inventory Ξ”", "Operating Activities", cash_flow["inventory"]),
307
+ ("Accounts Payable Ξ”", "Operating Activities", cash_flow["accountsPayables"]),
308
+ #("Other Working Capital Ξ”", "Operating Activities", cash_flow["otherWorkingCapital"]), # overlap with some lines
309
+ ("Other Non-Cash Items", "Operating Activities", cash_flow["otherNonCashItems"]),
310
+ ("Operating Activities", "Net Cash Inflow (Operating)", cash_flow["netCashProvidedByOperatingActivities"]),
311
+
312
+ # Investing Activities (Outflow)
313
+ ("Investments in PP&E", "Investing Activities", cash_flow["investmentsInPropertyPlantAndEquipment"]),
314
+ ("Acquisitions, Net", "Investing Activities", cash_flow["acquisitionsNet"]),
315
+ ("Purchases of Investments", "Investing Activities", cash_flow["purchasesOfInvestments"]),
316
+ ("Sales/Maturities of Investments", "Investing Activities", cash_flow["salesMaturitiesOfInvestments"]),
317
+ ("Other Investing Activities", "Investing Activities", cash_flow["otherInvestingActivities"]),
318
+ ("Investing Activities", "Net Cash Outflow (Investing)", cash_flow["netCashProvidedByInvestingActivities"]),
319
+
320
+ # Financing Activities (Outflow)
321
+ ("Net Debt Issuance", "Financing Activities", cash_flow["netDebtIssuance"]),
322
+ #("Long-Term Net Debt Issuance", "Financing Activities", cash_flow["longTermNetDebtIssuance"]), # already under net debt
323
+ #("Short-Term Net Debt Issuance", "Financing Activities", cash_flow["shortTermNetDebtIssuance"]), # already under net debt
324
+ #("Net Stock Issuance", "Financing Activities", cash_flow["netStockIssuance"]),
325
+ ("Net Common Stock Issuance", "Financing Activities", cash_flow["netCommonStockIssuance"]),
326
+ #("Common Stock Issuance", "Financing Activities", cash_flow["commonStockIssuance"]), # already under net common stock issuance
327
+ #("Common Stock Repurchased", "Financing Activities", cash_flow["commonStockRepurchased"]), # already under net common stock issuance
328
+ ("Net Preferred Stock Issuance", "Financing Activities", cash_flow["netPreferredStockIssuance"]),
329
+ ("Net Dividends Paid", "Financing Activities", cash_flow["netDividendsPaid"]),
330
+ #("Common Dividends Paid", "Financing Activities", cash_flow["commonDividendsPaid"]), # already under net dividends paid
331
+ #("Preferred Dividends Paid", "Financing Activities", cash_flow["preferredDividendsPaid"]), # already under net dividends paid
332
+ ("Other Financing Activities", "Financing Activities", cash_flow["otherFinancingActivities"]),
333
+ ("Financing Activities", "Net Cash Outflow (Financing)", cash_flow["netCashProvidedByFinancingActivities"]),
334
+
335
+ # Combine In and Out Flows
336
+ ("Net Cash Inflow (Operating)", "Net Change in Cash", cash_flow["netCashProvidedByOperatingActivities"]),
337
+ ("Net Cash Outflow (Investing)", "Net Change in Cash", cash_flow["netCashProvidedByInvestingActivities"]),
338
+ ("Net Cash Outflow (Financing)", "Net Change in Cash", cash_flow["netCashProvidedByFinancingActivities"]),
339
+ ("Effect of Forex on Cash", "Net Change in Cash", cash_flow["effectOfForexChangesOnCash"]),
340
+
341
+ # Beginning & Change β†’ Ending Balance
342
+ ("Cash at Beginning of Period", "Cash at End of Period", cash_flow["cashAtBeginningOfPeriod"]),
343
+ ("Net Change in Cash", "Cash at End of Period", cash_flow["netChangeInCash"]),
344
+ ]
345
+
346
+ adjusted_flows = []
347
+ for src, tgt, val in flows:
348
+ if val >= 0:
349
+ adjusted_flows.append((src, tgt, val, 'rgba(50,200,50,0.6)'))
350
+ else:
351
+ # reverse direction for readability
352
+ adjusted_flows.append((tgt, src, -val, 'rgba(200,50,50,0.6)'))
353
+
354
+
355
+ labels = []
356
+ for s, t, _, _ in adjusted_flows:
357
+ if s not in labels: labels.append(s)
358
+ if t not in labels: labels.append(t)
359
+
360
+ node_values = { lbl: cash_flow[
361
+ {
362
+ "Net Income": "netIncome",
363
+ "Depreciation & Amortization": "depreciationAndAmortization",
364
+ "Deferred Income Tax": "deferredIncomeTax",
365
+ "Stock-Based Compensation": "stockBasedCompensation",
366
+ "Change in Working Capital": "changeInWorkingCapital",
367
+ "Accounts Receivables Ξ”": "accountsReceivables",
368
+ "Inventory Ξ”": "inventory",
369
+ "Accounts Payable Ξ”": "accountsPayables",
370
+ "Other Working Capital Ξ”": "otherWorkingCapital",
371
+ "Other Non-Cash Items": "otherNonCashItems",
372
+ "Operating Activities": "netCashProvidedByOperatingActivities",
373
+ "Investments in PP&E": "investmentsInPropertyPlantAndEquipment",
374
+ "Acquisitions, Net": "acquisitionsNet",
375
+ "Purchases of Investments": "purchasesOfInvestments",
376
+ "Sales/Maturities of Investments": "salesMaturitiesOfInvestments",
377
+ "Other Investing Activities": "otherInvestingActivities",
378
+ "Investing Activities": "netCashProvidedByInvestingActivities",
379
+ "Net Debt Issuance": "netDebtIssuance",
380
+ "Long-Term Net Debt Issuance": "longTermNetDebtIssuance",
381
+ "Short-Term Net Debt Issuance": "shortTermNetDebtIssuance",
382
+ "Net Stock Issuance": "netStockIssuance",
383
+ "Net Common Stock Issuance": "netCommonStockIssuance",
384
+ "Common Stock Issuance": "commonStockIssuance",
385
+ "Common Stock Repurchased": "commonStockRepurchased",
386
+ "Net Preferred Stock Issuance": "netPreferredStockIssuance",
387
+ "Net Dividends Paid": "netDividendsPaid",
388
+ "Common Dividends Paid": "commonDividendsPaid",
389
+ "Preferred Dividends Paid": "preferredDividendsPaid",
390
+ "Other Financing Activities": "otherFinancingActivities",
391
+ "Financing Activities": "netCashProvidedByFinancingActivities",
392
+ "Net Cash Inflow (Operating)": "netCashProvidedByOperatingActivities",
393
+ "Net Cash Outflow (Investing)": "netCashProvidedByInvestingActivities",
394
+ "Net Cash Outflow (Financing)": "netCashProvidedByFinancingActivities",
395
+ "Effect of Forex on Cash": "effectOfForexChangesOnCash",
396
+ "Net Change in Cash": "netChangeInCash",
397
+ "Cash at Beginning of Period": "cashAtBeginningOfPeriod",
398
+ "Cash at End of Period": "cashAtEndOfPeriod",
399
+ }[lbl]
400
+ ] for lbl in labels }
401
+
402
+
403
+ def fmt(val):
404
+ if abs(val) >= 1e9: return f"${val/1e9:.1f}B"
405
+ if abs(val) >= 1e6: return f"${val/1e6:.1f}M"
406
+ if abs(val) >= 1e3: return f"${val/1e3:.0f}K"
407
+ return f"${val:.0f}"
408
+
409
+
410
+ idx = { lbl:i for i,lbl in enumerate(labels) }
411
+ source = [ idx[s] for s, t, _, _ in adjusted_flows ]
412
+ target = [ idx[t] for s, t, _, _ in adjusted_flows ]
413
+ value = [ v for _, _, v, _ in adjusted_flows ]
414
+ colors = [ c for _, _, _, c in adjusted_flows ]
415
+
416
+ label_with_values = []
417
+ for lbl in labels:
418
+ val = node_values[lbl]
419
+ base = lbl
420
+ if val < 0: base += " [NEGATIVE]"
421
+ label_with_values.append(f"{base} ({fmt(val)})")
422
+
423
+ fig = go.Figure(go.Sankey(
424
+ arrangement="snap",
425
+ node = dict(label=label_with_values, pad=15, thickness=20),
426
+ link = dict(source=source, target=target, value=value, color=colors)
427
+ ))
428
+ fig.update_layout(
429
+ title_text=f"Income Statement Sankey β€” {symbol}",
430
+ height=height,
431
+ font_size=font_size
432
+ )
433
+ return fig
434
+
435
+
436
  st.title("Financial Sankeys")
437
 
438
  symbol = st.sidebar.text_input("Ticker symbol", "AMZN").upper()
 
442
  bs_font = st.sidebar.slider("Balance Sheet font size", 5, 15, 10)
443
  is_height = st.sidebar.slider("Income Statement height", 500, 1500, 600)
444
  is_font = st.sidebar.slider("Income Statement font size", 5, 15, 10)
445
+ cf_height = st.sidebar.slider("Cash Flow Statement height", 500, 1500, 800)
446
+ cf_font = st.sidebar.slider("Cash Flow Statement font size", 5, 15, 10)
447
 
448
  # where the data came from
449
  st.sidebar.markdown("## [Financial Modeling Prep API](https://site.financialmodelingprep.com/?utm_source=medium&utm_medium=medium&utm_campaign=damian8)\
 
460
  fig_bs = draw_balance_sankey(balance_sheet, symbol.upper(), bs_height, bs_font)
461
  st.plotly_chart(fig_bs, use_container_width=True)
462
  except Exception as e:
463
+ st.error(f"{e}")
464
 
465
  # Income Statement
466
  st.header(f"Income Statement β€” {symbol}")
 
470
  fig_is = draw_income_sankey(income_statement, symbol.upper(), is_height, is_font)
471
  st.plotly_chart(fig_is, use_container_width=True)
472
  except Exception as e:
473
+ st.error(f"{e}")
474
+
475
+ # Cash Flow Statement
476
+ st.header(f"Cash Flow Statement β€” {symbol}")
477
+ try:
478
+ df_cf = parse_json(f"https://financialmodelingprep.com/stable/cash-flow-statement?symbol={symbol}&apikey={apikey}")
479
+ cash_flow = df_cf.iloc[0]
480
+ fig_cf = draw_cashflow_sankey(cash_flow, symbol.upper(), cf_height, cf_font)
481
+ st.plotly_chart(fig_cf, use_container_width=True)
482
+ except Exception as e:
483
+ st.error(f"{e}")
484
+