The Investment Dashboard I Built Because Nothing Taught and Calculated at the Same Time
A product case study on the decisions behind a stock and ETF dashboard built for Swiss investors: scoping, health signals, tax logic, and knowing when to stop.
I moved to Switzerland and started investing. Took some courses, read some books, started to understand which KPIs actually matter when evaluating a stock or ETF. Knowledge was available. But everything was scattered. One source for fundamentals, another for technicals, a third for tax implications. None of them talked to each other.
What’s worse… I kept forgetting which thresholds mattered. Is an ROE of 8% good? What does a Debt-to-Equity of 1.5 mean in practice? Every time I sat down to evaluate something, I was back to reading and re-learning the same lessons. I needed a tool that reminded me while I’m exploring. Just the answer, right next to the number.
Then there were the Swiss-specific guidelines. Most investments I was looking at were priced in USD or EUR, which meant every return I saw was a half-truth until I factored in currency conversion to CHF. On top of that, dividends from foreign companies get taxed before they reach you, and whether you can reclaim that tax depends on a treaty with different countries. A US stock’s 4% yield? Fully reclaimable via the DA-1 form on your Swiss tax return. A German stock’s 4%? Quietly becomes ~3.4%.
I looked for a tool that handled all of this. So I built it. A side project called FinXBoard, using Python, Dash, and AI-assisted development. This is the story of every product decision along the way.
Two categories, one screen
Early on, I made a structural decision that shaped a lot of what came after. All KPIs live in a single sidebar, but split into two categories.
Investment Health answers: ”How fit is this business?” Think of it like a doctor’s checkup. EPS answers the most basic question: is this company making money? Free Cash Flow checks whether that profit is real cash or just accounting. Revenue Growth and ROE tell you if the business is expanding and using capital well. Debt-to-Equity flags over-leverage. Dividend Yield shows whether it pays you to hold.
Trading Signals answers a different question: ”What’s the market doing with this stock right now?” RSI flags overbought or oversold conditions. P/E checks whether the price makes sense relative to earnings. Beta measures volatility, MACD shows momentum direction, and Bollinger Bands tell you if the price has stretched beyond its normal range.
The split mirrors how experienced investors see things. A company can be a great business with strong fundamentals but a terrible buy today because the trading indicators are overheated. Or it can be a weak business trading at a steep discount. The two categories force you to consider both perspectives.
Health dots and the learning curve
Every KPI shows a colored dot: green, gray, or red. Giving the dashboard the possibility to be read fast, specifically for beginners.
The temptation was to show raw numbers and let users interpret them. But that assumes knowledge most investors don’t have, not even mentioning the experinece of reading those numbers into insights. Is an ROE of 8% good? It’s gray. Acceptable but not strong. A Debt-to-Equity of 1.5? Also gray, elevated but within range. An RSI of 75? Red. Overbought.
The dots are where beginners start. You don’t need to memorize that ROE above 10% is healthy. The green dot tells you the standard go-to first glance information.
But the numbers are there because that’s where professional understand better. Over time, a user starts reading an ROE of 9% alongside +22% revenue growth and low Debt-to-Equity and thinks: “they’re reinvesting heavily in growth, so that gray dot doesn’t worry me.” The dots teach the basics. The numbers let you develop judgment.
Tooltips that teach as you explore
Hover over any KPI and you get a plain-language tooltip with an everyday analogy, not a textbook definition. Something like ”Think of it like a rental property: if you put in $200K and earn $20K/year in net rent, that’s a 10% return on your money.”
You learn each metric in context, while looking at real data for a real stock. Not in a classroom disconnected from any ticker. Over time, you stop needing the tooltips. The tool has done its job.
Designing for context: the Swiss tax module
Many tools stop at the gross dividend yield because they’re built for a global audience, not a Swiss one. For a Swiss investor, the raw yield is a half-truth.
I needed a dedicated tax module with a treaty-rate table covering 15 countries. Each entry stores two things: the withholding rate and the reclaimability classification: `full`, `partial`, or `none`.
The US withholds 30% on dividends by default. However, thanks to the US-Switzerland tax treaty, Swiss residents get a reduced rate of 15% at source. That reduced 15% is then fully reclaimable through the DA-1 form on the Swiss tax return.
Now compare that with a German stock. SAP also withholds 15%, but the reclaim process is partial. How much you recover depends on your canton and tax rate. Conservatively, about 50% of that withholding is permanently lost. A 4.0% gross yield becomes approximately 3.7% net.
The dashboard displays this as `15% Partial` with an amber badge in the header. When there’s no drag (US, UK, Ireland, Japan), it simply shows `X% reclaimable` with a green badge. When the country isn’t in the treaty table, it shows a gray “check treaty” badge. Honest about what it doesn’t know.
A lookup table, a multiplication, and a formatting function. But the product value is out of proportion to the engineering effort. It shows information that directly affects the user’s actual return, and that many other consumer tools don’t bother to include.
Connecting the KPIs: the signal engine
Individual KPIs tell you fragments. EPS is positive, great. But what if Free Cash Flow is negative? The company is profitable on paper but not generating actual cash. You’d only catch that by looking at both numbers and knowing they’re connected. Most people don’t.
That’s what led to a design-intensive feature in the project: a rule engine with 26 rules, each combining two or three indicators to name a specific pattern. The dashboard shows these as clickable pills: short labels like “Paper Profits” or “Cash Machine” that summarize what the combination of KPIs is saying about this stock.
The pills teach what the connection between KPIs might mean. “Paper Profits” doesn’t say “don’t buy.” It says: earnings look good on paper but cash isn’t following. Here’s why that matters, here’s the research behind it. The user decides.
Three examples
Paper Profits fires when EPS is positive but Free Cash Flow is negative. The analogy: “a shop that records lots of sales on credit but nobody’s actually paying.” This gap between reported earnings and cash flow is a well-documented warning sign. Richard Sloan’s 1996 Accrual Anomaly research found that a hedge strategy exploiting this gap returned roughly 10% annually. A finding in academic finance, and it’s completely invisible if you look at EPS and FCF in isolation.
Strong Business on Sale. Five or more investment KPIs are green, but the stock is technically oversold (RSI below 30 or price near the lower Bollinger Band). A quality business at a discount. This rule bridges fundamentals and technicals, which is where useful signals tend to live. The catch, as the pill explains: the sell-off might know something the fundamentals haven’t captured yet.
Then there’s Calm Before the Storm, which is a particularly tricky pattern for beginners. Fundamentals are weak, but the trading signals look stable. The calm price feels reassuring while the floor is rotting underneath. The pill puts it as “a building with a cracked foundation that still looks fine from the street”. Of course the explanation tells the user which KPIs are involved and what to be aware of or what to search for.
The engine has three categories. Investment Health rules combine fundamental KPIs. Trading Signal rules combine technical indicators. Cross-Category rules bridge both, and are particularly useful because they connect questions that most investors answer separately.
The engine also handles deduplication. “Triple Negative” (EPS negative, Revenue declining, FCF negative) is more specific than “Double Bleeding” (EPS negative, FCF negative). If both fire, only Triple Negative shows, because it tells a more complete story. The engine manages its own noise.
The signal engine currently works for stocks only. ETF-specific insight rules are on the roadmap.
The philosophy: teach users to think in systems, not isolated numbers. Over time, he starts seeing the patterns before he clicks.
ETF detection: same screen, different content
When someone searches for SPY instead of AAPL, the dashboard hits a branching problem. EPS, ROE, Debt-to-Equity, Free Cash Flow: none of these mean anything for an ETF. A fund doesn’t have earnings per share. Showing “N/A” across half the Investment Health category would be a failure of information design.
So when the dashboard detects an ETF, the entire Investment Health category swaps to ETF-relevant metrics: Fund Size (AUM), Expense Ratio, NAV Premium/Discount, 52-Week Range, Dividend Yield, and 3-Year Average Return. The Trading Signals category stays identical. RSI, MACD, and Bollinger Bands work on any price series.
Each ETF metric has its own researched health thresholds. Fund Size uses $500M as the green threshold because funds under $100M face elevated closure risk and wider bid-ask spreads. Expense Ratio is calibrated for the broad-market index ETFs that most Swiss passive investors start with: green at 0.30% or below. NAV Premium flags anything above 2% as red, premiums at that level are unusual for liquid ETFs and typically signal market stress, illiquid underlying assets, or a data error.
The NAV Premium calculation needed a specific guard. yfinance sometimes reports NAV in the fund’s base currency (USD) while the market price is in the trading currency (CHF for Swiss-listed ETFs). The raw math produces nonsense, like a -20% “premium” that’s actually just a currency mismatch. The fix: discard any NAV premium beyond +/-5%. Values that extreme almost always indicate a data error rather than a real market condition.
The header adapts too. ETFs get a purple “ETF” type badge and a green fund family badge (“Vanguard Group (Ireland) Limited”), a quiet hint about fund domicile, which matters for withholding tax.
Knowing what can’t be build (yet)
I maintain a document of every metric I considered and didn’t build (and every feature as well), with a reason next to each one.
Quick wins I haven’t built yet. 52-week high/low for stocks is trivial; the data is always populated. Market cap is one field and gives immediate context on company size. Forward P/E is available but based on analyst consensus, which can be stale or missing for smaller companies. These aren’t in because every metric you add competes for attention. The first version needed to answer the core questions cleanly first.
Worth the effort but needs care. A CHF-adjusted price chart. This is the unbuilt feature I think about most. A stock up 15% in USD over a year might be up only 5% in CHF if the franc strengthened. The current chart shows raw-currency prices, which means every non-CHF holding’s chart is inaccurate to the Swiss investor right now. The engineering isn’t hard (yfinance provides exchange rate history), but handling multiple currency pairs dynamically is where it gets complicated.
Not feasible with yfinance alone. Whether an ETF is accumulating or distributing (yfinance has no field for distribution policy, so you’d need justETF or fund prospectus data). Sector P/E comparison requires aggregating live data across hundreds of tickers per lookup. Rich news context is too thin in yfinance to be useful.
Documenting “not now” with “because” is an underrated PM habit. Six months from now, someone (probably me) will ask “why don’t we have sector P/E?” The answer is already written. That saves a week of re-investigation.
AI as PM leverage
I built FinXBoard using AI-assisted development with Claude Code. That’s not a disclaimer. It’s the point.
A PM who can go from “I have a problem” to a working tool with 26 rules, Swiss tax logic, ETF detection, and researched health thresholds in days instead of months is a PM who can validate ideas at a speed that wasn’t possible before. The iteration cycle between “what if we tried this” and “here’s what it looks like with real data” shrinks from weeks to hours. And if I didn’t have to learn about investments as I was building it, the whole project could have been released in 3 hours.
The real point is simple:
The AI didn’t make the product decisions. It didn’t decide to split KPIs into two categories, or that NAV premium needs a cross-currency guard, or that the signal engine should teach connections rather than give buy/sell signals. That the goal of the dashboard is to replace reading books to be able to read the dashboard, because the dashboard already have easy to follow explanations baked in. Those are product, user experience and information architecture judgment calls. The AI made it possible to act on them and see immediate results.
The bottleneck for PMs has always been “I have an idea but I need engineering time to test it”.
AI-assisted development removes that bottleneck for a PM with technical fluency. The skill was never coding. It was knowing what to build, and why.
What building this taught me
The gap between “data available” and “data useful” is larger than I expected.
yfinance gives you `dividendYield` as a decimal. That’s data available. Showing `15%` with an amber “partial reclaim” badge because the stock is German-domiciled? That’s data useful. The raw field took zero effort to fetch. Making it mean something to a Swiss investor required understanding the tax treaty system, modeling the reclaim scenarios, picking a conservative estimate for partial reclaim, and designing a visual that communicates the answer in under a second.
Same thing with `trailingEps` and `freeCashflow`. Two separate numbers in an API response. Combine them into a “Paper Profits” warning backed by Sloan’s Accrual Anomaly research, and suddenly they tell a story that neither tells alone.
You can scope a feature by how many API fields it needs, and you’ll know the cost. You can also scope it by whether it changes what the user does next. I’ve learned those are very different questions.
FinXBoard is an open-source project built with Python, Dash, and yfinance. The code, specs, and every product decision documented above are in the repository.
FinXBoard uses yfinance, a free unofficial data source that may be delayed, occasionally inaccurate, or temporarily unavailable. This app is an educational/explorational tool. Always verify numbers and decisions with your broker before making investment decisions.
