I built and ran the platform about 20 traders use every day: a live screener, alerts, a broker-CSV trade journal and an Electron client. v1.5.0 went to production on 2026-08-27.
The desk needed one workspace for live top-gainer screening, price alerts, trade review and per-trader reporting, fed by market-data vendors and broker exports. It runs on a self-hosted server with a single engineer, and that engineer is also a user of the desk's automated trading system.
Constraints
One engineer who is also on the trading side. The users are traders, working live during market hours.
Self-hosted Windows LAN server. The plan for managed hosting (~31-36 USD/month) was never carried out.
Broker exports are EET/EEST, storage is UTC and display is US/Eastern, with a 04:00-20:00 ET session window.
Vendor data quirks: missing prices arrive as INT64_MAX rather than null, and the daily SSR exchange file is self-complete.
The PM2 daemon is shared with another user, so restarts target an app by name and never use "restart all".
Plain JavaScript, raw pg queries, no ORM and no UI library.
What I built
market-data vendorsbroker CSV exports (EET/EEST)
| |
v v
[ harvester ] --loopback HTTP/SSE--> [ Express 5 backend ] <-- 5 parser files -> reconstructed trades
| 33 models / 36 services / 27 thin routes
| 7 rate limiters, JWT + role middleware
| uploads checked by magic bytes
+-------------+-------------+
v v
[ PostgreSQL ] 44 tables [ Redis ]
node-pg-migrate
|
scheduled jobs: fundamentals 20:05 ET | candle ingest 04:00 ET
metric backfill | Discord digest
|
[ ws WebSocket ] screener ticks + alerts
v
[ Electron 33 client ] main / preload / tray
React 18 + Vite 6, 10 context+reducer domains, 17 pages
PM2: backend, 2 frontends, DB-backup cron, Discord bot, harvesterstatus page: 26 services, run-length uptime history
fig 1. Data path from vendors and broker exports to the trader's screen.
Designed and built the backend, schema, migrations, WebSocket layer, parsers, jobs and the Electron/React client.
Ran production on the self-hosted server: deploys, backups and restores, log rotation, and rate-limit hardening after a 2026-05-08 prod log audit found an IPv6 bypass and a 548 MB unrotated log.
Root-caused incidents and wrote each one up with cause and fix (outage, runaway poller, sentinel prices, order-attribution loss).
Integrated, tested and validated the desk's proprietary automated trading system (which I did not build), and onboarded colleagues onto it and onto the platform.
Built trading analytics on top: trade reconstruction from broker CSVs, leg-aware drawdown, and a spike tracker (LHF board) that follows a ticker back to the base of its move.
Outcome
date
result
2026-02-18
Phases 1-8 tested and passing: market data 47/47, screener 25/25, alerts and sharing 49/49, admin 37/37
v1.3.0 adds an admin trade dashboard and weekly DB backups
2026-08-10
Read-only mathematical audit reconciled daily reports across all 149 selectable dates
2026-08-26
Platform status page covering 26 services, with run-length uptime history
2026-08-27
v1.5.0 deployed, prod migrations 70 -> 80. An order-attribution data loss was found and backfilled the same day
Numbers and incidents
when
what
v1.2.0
44 tables, 78 migrations, 442 tests in 32 suites
2026-05-13
~6 h outage after a Windows Update reboot (PM2 had no auto-start). Fix: a boot-time scheduled task per user
2026-08-05
A poller ran ~9,600 requests/day against ~6,400 in-session because of a session-gate timer bug. The PM2 log reached 1.07 GB
2026-08-06
A vendor INT64_MAX "no value" sentinel had persisted bars priced in the billions, and a warning fired ~1,500 times/day. Fix: a 0 < price < 1e7 ingest guard
2026-08-17
Investor SVG charts were wrong on most trades. Six root causes fixed
2026-08-27
1,154 of 5,686 trades (20.3%) had lost their linked orders: the replace-on-upload delete was scoped to user+date but not account. Backfilled; 356 remain unrecoverable because the source data does not exist
fig 2. Mock workspace. Fake tickers (AAAA, BBBB) and fake prices; black bars mark fields that are redacted in the real app (accounts, P&L, trader names, hosts).
INCIDENT 2026-08-27 · order attribution
impact 1,154 / 5,686 trades (20.3%) lost their linked orders
cause replace-on-upload delete scoped to user+date, not account
fix found and backfilled the same day
residual 356 unrecoverable, because the source data does not exist