aboutsummaryrefslogtreecommitdiff
path: root/README.html
blob: cfeedf3f8a1a69889d24f61b9ea555a582ec6908 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    max-width: 900px;
    line-height: 1.7;
    color: #333;
    background: #fafafa;
    padding: 2rem;
    margin: 0 auto;
  }
  h1, h2, h3, h4 { color: #0f2346; margin-top: 1.5em; margin-bottom: 0.5em; font-weight: 700; }
  h1 { font-size: 2.2em; margin-top: 0; }
  h2 { font-size: 1.6em; border-bottom: 2px solid #c9a84c; padding-bottom: 0.5em; }
  h3 { font-size: 1.2em; color: #1a3560; }
  p { margin-bottom: 1em; }
  ul, ol { margin-left: 1.5em; margin-bottom: 1em; }
  li { margin-bottom: 0.5em; }
  hr { border: none; border-top: 1px solid #ddd; margin: 2em 0; }
  a { color: #234a8a; text-decoration: none; font-weight: 500; }
  a:hover { text-decoration: underline; }
  blockquote {
    border-left: 4px solid #c9a84c;
    padding-left: 1em;
    margin-left: 0;
    color: #666;
    font-style: italic;
    background: #f5f5f5;
    padding: 0.75em 1em;
  }
  code {
    font-family: 'Courier New', Courier, monospace;
    background: #f5f5f5;
    padding: 0.2em 0.4em;
    border-radius: 3px;
    color: #d73a49;
    font-size: 0.9em;
  }
  pre {
    background: #1e1e1e;
    color: #e0e0e0;
    padding: 1em;
    border-radius: 5px;
    overflow-x: auto;
    margin-bottom: 1em;
    border-left: 4px solid #c9a84c;
  }
  pre code {
    background: none;
    padding: 0;
    color: #e0e0e0;
    font-size: 0.95em;
  }
  table {
    border-collapse: collapse;
    width: 100%;
    margin-bottom: 1.5em;
    border: 1px solid #ddd;
  }
  th, td {
    border: 1px solid #ddd;
    padding: 0.75em;
    text-align: left;
  }
  th {
    background: #0f2346;
    color: #fff;
    font-weight: 600;
  }
  tr:nth-child(even) { background: #f9f9f9; }
  tr:hover { background: #f0f0f0; }
</style>
</head>
<body>
<h1>🔷 Prism</h1>
<p>A local financial analysis dashboard. Enter any stock ticker to get a formatted view of financial statements, valuation metrics, a DCF model, and a news feed — all in your browser.</p>
<hr />
<h2>Features</h2>
<ul>
<li><strong>Market Bar</strong> — Live S&amp;P 500, NASDAQ, DOW, and VIX at the top of every page</li>
<li><strong>Overview</strong> — Price chart (1M / 3M / 6M / 1Y / 5Y), key stats (market cap, P/E, 52W range, beta)</li>
<li><strong>Financials</strong> — Annual and quarterly Income Statement, Balance Sheet, and Cash Flow Statement with year-over-year % change columns</li>
<li><strong>Valuation</strong> — Key ratios grid (P/E, EV/EBITDA, margins, ROE, etc.), DCF model with adjustable WACC/growth/years, EV/EBITDA implied price, comparable companies table, analyst price targets, and earnings history (EPS actual vs. estimate)</li>
<li><strong>News</strong> — Recent articles with heuristic Bullish / Bearish / Neutral tags and a 7-day sentiment summary</li>
</ul>
<hr />
<h2>Setup</h2>
<h3>1. Clone / navigate to the project</h3>
<pre><code class="language-bash">cd ~/Work/prism
</code></pre>
<h3>2. Activate the virtual environment</h3>
<pre><code class="language-bash">source .venv/bin/activate
</code></pre>
<h3>3. Add API keys</h3>
<pre><code class="language-bash">cp .env.example .env
</code></pre>
<p>Open <code>.env</code> and fill in your keys:</p>
<pre><code>FMP_API_KEY=your_key_here
FINNHUB_API_KEY=your_key_here
</code></pre>
<p>Both are <strong>free</strong>:
- <strong>FMP</strong> (Financial Modeling Prep) — <a href="https://financialmodelingprep.com/developer/docs">financialmodelingprep.com</a> — 250 requests/day
- <strong>Finnhub</strong> — <a href="https://finnhub.io">finnhub.io</a> — 60 requests/minute</p>
<blockquote>
<p><strong>No keys?</strong> The app still works. Price data, financials, and market indices are sourced from <code>yfinance</code> (no key required). Ratios, comps, and news won't load until keys are added.</p>
</blockquote>
<h3>4. Run the app</h3>
<pre><code class="language-bash">streamlit run app.py
</code></pre>
<p>Opens at <code>http://localhost:8501</code></p>
<hr />
<h2>Daily Usage</h2>
<pre><code class="language-bash">cd ~/Work/prism
source .venv/bin/activate
streamlit run app.py
</code></pre>
<hr />
<h2>Project Structure</h2>
<pre><code>prism/
├── app.py                    # Entry point
├── requirements.txt
├── .env                      # Your API keys (not committed)
├── .env.example              # Key template
├── .streamlit/
│   └── config.toml           # Dark theme + layout settings
├── services/
│   ├── data_service.py       # yfinance — price, financials, indices
│   ├── fmp_service.py        # FMP API — ratios, peers
│   ├── news_service.py       # Finnhub — news + sentiment
│   └── valuation_service.py  # DCF engine (Gordon Growth Model)
├── components/
│   ├── market_bar.py         # Index metrics row
│   ├── overview.py           # Company header + price chart
│   ├── financials.py         # Statement tables
│   ├── valuation.py          # Ratios, DCF, comps
│   └── news.py               # News feed
└── utils/
    └── formatters.py         # Number formatting helpers
</code></pre>
<hr />
<h2>DCF Model Notes</h2>
<p>The DCF model uses historical <strong>Free Cash Flow</strong> from yfinance, computes a capped median growth rate from valid positive-FCF periods, and then projects forward using your chosen assumptions:</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Default</th>
<th>Range</th>
</tr>
</thead>
<tbody>
<tr>
<td>WACC</td>
<td>10%</td>
<td>5–20%</td>
</tr>
<tr>
<td>Terminal Growth Rate</td>
<td>2.5%</td>
<td>0.5–5%</td>
</tr>
<tr>
<td>Projection Years</td>
<td>5</td>
<td>3–10</td>
</tr>
<tr>
<td>FCF Growth Rate</td>
<td>Historical median</td>
<td>-20–30%</td>
</tr>
</tbody>
</table>
<p>The model uses the <strong>Gordon Growth Model</strong> for terminal value. It first estimates <strong>enterprise value</strong>, then bridges to <strong>equity value</strong> using debt and cash before calculating value per share. Terminal growth must remain below WACC. The FCF growth slider defaults to the historical median but can be freely overridden.</p>
<p>The <strong>EV/EBITDA</strong> tab derives an implied price by applying a target multiple to trailing EBITDA, subtracting net debt, and dividing by shares outstanding. The slider defaults to the company's current market multiple.</p>
<hr />
<h2>API Rate Limits</h2>
<table>
<thead>
<tr>
<th>Source</th>
<th>Limit</th>
<th>Used For</th>
</tr>
</thead>
<tbody>
<tr>
<td>yfinance</td>
<td>None</td>
<td>Price, financials, indices</td>
</tr>
<tr>
<td>FMP (free)</td>
<td>250 req/day</td>
<td>Ratios, comps, news</td>
</tr>
<tr>
<td>Finnhub (free)</td>
<td>60 req/min</td>
<td>News, sentiment</td>
</tr>
</tbody>
</table>
<p>Data is cached in-memory per session to minimize API calls (financials: 1h, news: 10min, indices: 5min).</p>
</body>
</html>