Asset types
Multi-currency architecture
Every holding has acurrency field (the currency it’s traded in). The app displays everything in your chosen display currency (SGD, INR, or USD) using live exchange rates.
The effectiveCurrency pattern
Crypto is the edge case: CoinGecko always returns prices in USD regardless of what’s in thecurrency field. So the provider overrides it:
displayCurrency == effectiveCurrency, the rate key resolves to e.g. "SGDSGD" which returns 1.0 — no conversion needed.
Shared forex rates provider
All portfolio providers share a single forex fetch per render cycle:Format helpers
format(), per-holding tiles use formatConverted().
Live price fetching
Caching and deduplication
TheMarketDataService has two layers of deduplication:
1. TTL cache (60 seconds)
Batch endpoint
The/market/batch endpoint combines stocks + crypto + forex into a single call:
holdingsWithPricesProvider to hydrate the full portfolio in one round trip.
Asset-specific price logic
Fixed Deposits — accrual formula:getMetalPrice() maps semantic names:
bitcoin, ethereum, solana). The holding’s symbol field is stored in uppercase by convention. The service normalises:
Portfolio calculations
Cost basis
avgPrice is stored in the holding’s original currency. FX conversion applied at display time.
Market value
currentPrice comes from the live price fetch. Falls back to avgPrice on fetch failure.
Return
Unrealised P&L per holding
Historical charts
The asset detail screen fetches OHLCV history for period selector tabs (1W / 1M / 3M / 6M / 1Y / ALL):
Crypto history uses CoinGecko’s
/coins/{id}/market_chart endpoint with equivalent day ranges.
Portfolio sparkline (14-day)
The dashboard hero sparkline aggregates the last 14 days of portfolio value:Heatmap
The heatmap widget sizes each tile by portfolio allocation weight and colours by day change %:
Tile size is proportional to
currentValue / totalPortfolioValue.