Skip to content

Latest commit

 

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StackEmAll

A single-file, no-build portfolio ledger for stocks and crypto. Open index.html directly in a browser — there's no server, no bundler, and no backend. Holdings are stored in the browser's localStorage, so your data stays on the machine you added it on.

Running it

Open index.html in a browser (double-click, or run open.bat on Windows). That's the whole setup.

If you'd rather serve it over http://, any static file server works, e.g. from the repo root:

npx serve .

What it does

  • Add stock and crypto tickers with a quantity, an optional average cost basis, and an optional free-text tag for where it's held (e.g. "Cold storage", "Coinbase", "Nordnet"). The same symbol can appear multiple times under different tags, tracked as separate lots that still roll up into the shared totals.
  • The add dialog has a Ticker/Crypto/Metal/Cash/Other type toggle. Crypto is the same search as Ticker but narrowed to crypto matches only, so it isn't buried under "Ticker" with no indication crypto lives there too. Metal picks from a fixed list (gold, silver, platinum, palladium) instead of a search — both still get a live quote, sparkline, and news attempt like any other ticker, and roll up into the existing "Bitcoin & crypto" stat card or their own "Metals" card respectively.
  • Cash holdings are a currency (DKK/EUR/GBP/SEK/NOK/USD) and an amount rather than a ticker — no live quote (Price shows "—"), no daily-change badge, no cost basis, no news/sparkline (its card says so instead of the usual "Listening for headlines…"). They roll into the same USD/local totals as everything else, and get their own "Cash" stat card once you have one.
  • Other holdings cover anything with no live price — property, vehicles, collectibles, and the like. Each one gets a free-text name (e.g. "Summer house", "1967 Mustang"), a currency, and a current value you update by hand whenever you reappraise it; an optional total original cost enables a P/L figure the same way a ticker's average cost does. No live quote, daily-change badge, or news/sparkline, same as Cash. They get their own "Other" stat card once you have one.
  • A per-tag value breakdown (shown in your local currency) sits above the holdings list whenever more than one tag is in use. Clicking a tag filters the list to it (multiple tags OR together); with none selected, everything shows. Each tag gets a color derived from its text, used consistently everywhere it appears.
  • A Sort control next to Refresh/Add holding orders the list by Value (default), Today's %, P/L, or Ticker. The choice persists across reloads.
  • Live price refresh every 30 seconds (Yahoo Finance for stocks, CoinGecko/Binance for crypto), with totals in USD plus your chosen local currency. The Total Value card carries a "Today" figure (USD + local, stacked like the ticker cards) and a day-change % badge top-right — the same layout every holding card uses. The 🪙📈💵🥇🏺 Bitcoin & crypto / Stocks / Cash / Metals / Other stat cards follow suit: a %-of-portfolio badge top-right, USD value, local-currency value stacked below it, then the position count.
  • Each holding card shows quantity, price, USD/local value, and P/L, plus a faded 30-day price sparkline behind the card and the day's % change next to the symbol. A holding flags itself "stale" if its price hasn't refreshed in a while. Quantities and prices are formatted in whatever locale your chosen local currency implies (da-DK's "." thousands / "," decimal for DKK, and so on) — not hardcoded to US notation.
  • The total-value card shows a value-over-time trend line, built from one snapshot per day. Alongside "Today" (the live day-over-day change reported by each holding's own quote), it shows a "Since yesterday" figure computed from your own snapshots — genuinely from the prior calendar day, falling back to the actual date if the app sat unopened for a few days — and, once there's a third snapshot to compare against, a separate "Since <first date>" figure covering everything since you started tracking.
  • A scrolling "Wire" headline ticker, plus up to 3 headlines per holding with icons where available. A holding with no headlines to show ("Listening for headlines…", or "No wire for…" on Cash/Other) drops that empty section on narrow screens rather than taking up a row for nothing — holdings that actually have headlines still show them. A "Show news wire" setting turns the whole thing off (ticker and every holding's news section) for anyone who'd rather not fetch or see it — with news off, holdings drop their now-empty second column and lay out as a multi-column grid instead of one wide stacked column, using however many columns comfortably fit.
  • Settings let you pick a local currency (DKK/EUR/GBP/SEK/NOK/USD, with the current USD/local exchange rate shown right there), a 12/24-hour clock, and a timezone — independent of USD, which is always the base currency. Export/Import lets you carry holdings, settings, and history between browsers or URLs, and doubles as a manual backup.
  • Precious metals (gold, silver, platinum, palladium) are priced per troy ounce and picked from the add dialog's Metal type, or found by name through the regular ticker search.
  • A Privacy toggle (top right, next to Settings) blurs everything that reveals position size or net worth — quantities, USD/local values, P/L — while leaving composition fully readable: symbols, tags, allocation %, day-change %, and per-share price all stay visible. Meant for sharing a screenshot of what you hold and how it's divided without revealing how much it's worth. Hover a blurred figure to peek at it without leaving privacy mode. The on/off state persists across reloads.
  • A "Save image" button (next to Privacy) exports the entire ledger — including holdings below the fold that don't fit in the window — as a downloaded PNG. If Privacy is on, the exported image redacts the same figures with solid bars rather than blur, so the file itself never contains the underlying numbers.
  • Every currency figure in the app draws its cents/øre dimmer than the whole-number part (a darker version of whatever color that figure already is — muted white normally, a darker green/red inside a colored P/L number).

How it's built

Plain HTML/CSS/JS, no framework, no build step:

  • index.html — page shell with three containers inside #app (#app-head, #app-tape, #app-body).
  • app.js — all application logic: state, rendering, price/news fetching, event handling.
  • styles.css — styling.
  • html2canvas.min.js — the one vendored third-party file, used only by "Save image" to rasterize the ledger to PNG. No CDN calls; it ships in the repo.

render() rebuilds #app-head and #app-body from the in-memory state object on every change — no diffing, just innerHTML replacement. The scrolling wire ticker lives in its own #app-tape container and only re-renders when its content actually changes, so its CSS animation isn't restarted by unrelated updates.

Data sources

  • Crypto quotes — CoinGecko (BTC/ETH/SOL resolve directly; anything else resolves via CoinGecko's coin search first), with a Binance fallback for BTC.
  • Stock quotes & ticker search — Yahoo Finance, reached through public CORS relays since Yahoo doesn't send CORS headers itself. Ticker search checks a small built-in directory of common tickers first (instant, no network dependency), then merges in a live Yahoo result if one arrives.
  • Sparkline history (per-holding 30-day price line) — fetched separately from the price quote, on a 6-hour cadence rather than every 30 seconds. Crypto sparklines resolve the coin the same way crypto quotes do (not limited to BTC/ETH/SOL).
  • News — tried in order per holding: Yahoo Finance's news search, then Google News RSS, then Hacker News (Algolia), filtered to results that actually mention the company/asset and are less than 14 days old.
  • FX rates — open.er-api.com, with frankfurter.dev as a fallback.
  • Cash and Other holdings — no data source at all. A synthetic quote (price: 1 in the chosen currency) plugs into the same value/P&L/history math as everything else, with no network call. For Other holdings, the value you type in is itself the current price of the position.

Known limitations

  • No build tooling, no tests, no TypeScript — a single hand-editable file by design.
  • Price/news freshness depends on third-party API availability; there's no server-side caching layer.
  • The local ticker directory covers common US large-caps/ETFs, a handful of Nordic tickers, and precious metals — anything else depends on the live Yahoo search or the typed symbol resolving directly.
  • Settings only offer a curated set of currencies and timezones, not every ISO code / IANA zone.
  • Value history is one point per calendar day, capped at 365 points — a trend indicator, not an intraday chart.

About

Simple dashboard for overview of holdings

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages