Portfolio
Your financial snapshot
Overview
This is the screen you land on every time you open the app. At the top you get the big number, your total portfolio value, updated in real time. Right below that is the day change. There is a time period chart (day, week, month, year, all time) that shows how your portfolio has moved. Below the chart you will find your holdings list with each asset showing its current price, your position size, and the gain or loss. You can switch between a list view and a pie chart view to see your allocation visually. There is also a top movers section, and an AI insight snippet powered by Claude.
How it works
When the screen loads, it pulls the active portfolio from the Zustand store (usePortfolioStore). The store holds all your portfolios, assets, and the currently selected portfolio ID.
For stocks and ETFs, we use React Query (useBulkQuotes) to batch fetch prices from our Supabase Edge Function, which proxies Alpha Vantage. This runs every 60 seconds automatically.
Crypto, forex, and commodities use a separate hook (useMultiAssetQuotes) because they need different API endpoints. These also refresh every 60 seconds.
All the prices get merged into a single prices map. That map gets passed to usePortfolioCalculations which computes the total value, day change, allocation percentages, and top movers.
The chart data comes from usePortfolioHistory, which fetches historical prices for each holding and combines them into a single portfolio timeline. The data gets downsampled to keep rendering smooth.
Pull to refresh triggers a refetch of all price data. The widget updater also runs here, pushing the latest portfolio data to iOS widgets whenever prices update.
Key decisions
React Query over manual fetching
We tried managing price fetching with useEffect and local state early on. It was a mess. Stale data, race conditions, no caching. React Query solved all of that with built in refetch intervals, deduplication, and background updates. The code got simpler and the UX got better.
Splitting bulk and individual quotes
Alpha Vantage has a batch endpoint for stocks and ETFs but not for crypto or commodities. So we split the fetching into two hooks. Stocks and ETFs go through useBulkQuotes (one API call for all of them), while crypto, forex, and commodities each get their own individual call through useMultiAssetQuotes.
Zustand for local state, not Context
We needed the portfolio store to be accessible both inside and outside React components (for the sync service, widget updater, etc). Zustand lets you call usePortfolioStore.getState() from anywhere. With Context you are stuck inside the React tree. That alone made the decision easy.
Pie chart vs list toggle
Some people want to see exact numbers. Others want a visual feel for their allocation. Instead of picking one, we added a toggle. The pie chart uses a custom SVG component that renders a donut chart with smooth animations.