Documentation
stockbase.xyz is a single-file, zero-build trading terminal that streams live oracle prices for tokenized US equities, crypto perpetuals and pre-IPO names. This page documents how it is built and how the data flows.
Overview
The application is a real-time market-data terminal. It renders a watchlist, an interactive candlestick chart, a depth-of-book view, a time-and-sales tape and an order ticket across 130 markets. Crypto and equity prices are sourced live from the Pyth Network oracle; pre-IPO names and out-of-hours equities are driven by a deterministic simulation layer. On-chain execution is not yet enabled, order tickets are illustrative and no funds move.
- 130 markets, 58 US equities, 58 crypto perpetuals, 14 pre-IPO names.
- Live oracle data, sub-second updates over a server-sent-events stream.
- 24/7, equities and pre-IPO names continue trading outside US market hours.
- Non-custodial, optional EVM wallet connection is read-only.
Architecture
Everything ships in one .html file with no build step, no bundler and no framework. Dependencies are loaded as UMD globals from a CDN:
| Layer | Choice |
|---|---|
| UI | Vanilla JS + CSS, hash-routed views |
| Charting | lightweight-charts v5.2.0 (UMD) |
| Web3 | ethers.js v5.7.2 (UMD), injected EVM wallet (Base) |
| Prices | Pyth Hermes (SSE) + Pyth Benchmarks (OHLC) |
| Fonts | Space Grotesk · Inter · JetBrains Mono |
State lives in two plain objects: M keyed by symbol (every market) and byId keyed by Pyth feed id (real feeds only). A market is flagged sim:true when it has no Pyth id.
Routing & views
Three views are toggled by the URL hash; a hashchange listener swaps a class on <body>.
function route(){ const h = location.hash; const app = h.includes('/app'), docs = h.includes('/docs'); document.body.className = app ? 'r-app' : docs ? 'r-docs' : 'r-landing'; if (app && !appBooted) enterApp(); // lazy-boot the terminal }
The terminal boots lazily the first time #/app is visited, so the landing page stays light.
Market types
Each market is defined as a tuple and expanded by mkMarket(). Real markets carry a Pyth feed id and a Pyth symbol; simulated markets carry only a base price.
| Type | Count | Source | Symbol form |
|---|---|---|---|
| stocks | 58 | Pyth equity feed* | Equity.US.AAPL/USD |
| perps | 58 | Pyth crypto feed | Crypto.BTC/USD |
| preipo | 14 | Simulated | - (no oracle) |
*SpaceX (SPCX) is listed under stocks but has no public Pyth feed, so it runs on the simulation layer like the pre-IPO names.
Pyth price feeds
Live prices arrive over a single EventSource subscribed to every real feed id. Each message carries a parsed price and an EMA price; the raw integer is scaled by its exponent.
const ids = Object.values(M).filter(m => m.id) .map(m => 'ids[]=0x' + m.id).join('&'); es = new EventSource( `${HERMES}/v2/updates/price/stream?${ids}&parsed=true&allow_unordered=true`); es.onmessage = ev => { const d = JSON.parse(ev.data); for (const u of d.parsed){ const m = byId[u.id]; m.price = Number(u.price.price) * 10 ** u.price.expo; // mark m.index = Number(u.ema_price.price) * 10 ** u.ema_price.expo; // index touch(m); } };
A single touch(m) function updates the watchlist cell, the ticker tape, any market card and, if the market is active, the chart, book and tape.
OHLC history
Chart history for real markets comes from the Pyth Benchmarks TradingView shim, which returns CORS-enabled OHLCV arrays:
GET ${BENCH}/v1/shims/tradingview/history
?symbol=Crypto.BTC/USD&resolution=60&from=...&to=...
→ { s:"ok", t:[…], o:[…], h:[…], l:[…], c:[…], v:[…] }
Resolutions map to the six timeframe buttons (1m 5m 15m 1h 4h 1D). Requests are bounded-concurrency with retry/backoff to absorb intermittent rate-limiting.
24/7 simulation
Pyth equity feeds only tick during US market hours, and private companies have no oracle at all. To keep every market alive around the clock, a 1.3s interval drives a random walk where the live feed is silent.
- Pre-IPO & feed-less stocks, always simulated from a seeded base price.
- Listed equities, simulated only when their last price change is older than 25 seconds (i.e. the market is closed); live oracle ticks take over instantly when they resume.
function simStep(){ const now = Date.now()/1000; for (const m of Object.values(M)){ let vol = 0; if (m.sim) vol = m.kind==='preipo' ? 7e-4 : 5e-4; else if (m.kind==='stocks' && now - m.lastChange > 25) vol = 3.5e-4; if (!vol) continue; m.price *= 1 + (Math.random()-.5) * 2 * vol; touch(m); } }
Simulated chart history is generated as a random walk that terminates exactly at the current price, so the live candle continues seamlessly from the synthetic series.
Order book & trades
Depth and time-and-sales are simulated around the real mark, there is no matching engine. The book is rebuilt from the current price with size buckets scaled by asset class, and the number of visible levels is computed from the available pixel height so the column always fills. Trade prints are seeded once, then appended on each price change with direction inferred from the tick.
Charting
The chart is a lightweight-charts candlestick series plus a volume histogram on an overlaid scale. Two correctness guards matter:
- Load token, each history load increments a token; results that return after a newer load (from fast ticker/timeframe switching) are discarded, preventing stale data from overwriting the active series.
- Monotonic updates, live candle updates only apply when the bar time is ≥ the last bar's time, so the series never moves backwards.
Leverage & liquidation
Order tickets support cross/isolated mode and 1-100× leverage. The estimated liquidation price shown on the ticket is a preview only:
liqPrice ≈ mark × (1 − (1 / leverage) × 0.95)
No position is opened and no margin is held, execution is not yet live. The leverage and liquidation fields preview the experience that ships with on-chain settlement.
Wallet (Base)
Connection uses the injected EIP-1193 provider (MetaMask and compatible wallets) and is strictly read-only: it requests accounts, prompts a switch to Base, and reads the native BNB balance. No transactions are ever requested.
const p = window.ethereum; const [addr] = await p.request({ method: 'eth_requestAccounts' }); await p.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x2105' }] }); // wei → ETH via eth_getBalance
Endpoints
| Purpose | Endpoint |
|---|---|
| Live prices | hermes.pyth.network/v2/updates/price/stream |
| Latest snapshot | hermes.pyth.network/v2/updates/price/latest |
| Feed registry | hermes.pyth.network/v2/price_feeds |
| OHLC history | benchmarks.pyth.network/v1/shims/tradingview/history |
| Base RPC | mainnet.base.org |
Pyth's public Hermes and Benchmarks endpoints are scheduled to require an API key after July 31, 2026.
Roadmap
- On-chain execution and settlement on Base.
- Token launch, the contract address appears on the home page (
LAUNCHING..until live). - Additional equity, perp and pre-IPO listings.
- User-configurable RPC endpoints for resilience.
Disclaimers
Crypto and equity prices are sourced live from the Pyth Network oracle; equities trade 24/7, with marks continuing from the last oracle print outside US market hours. Pre-IPO marks are indicative, private companies have no public oracle. Nothing here is financial advice.