Thalex: where its trading screen loses time, and what to fix

Measured from the Netherlands in a logged-in Chrome, October 2026.

In short. On a warm reload the screen is trade-ready after 2.4 s (median of 5 loads), 1 of 27 perpetual trading screens, possible rank 1 to 2; after an uncached reload 2.6 s. The largest bottleneck: Market data is on the socket 2 s before it is on screen. First change to try: Profile the 2 s between the first socket message and the first price paint, starting with the translation runtime (vue-i18n) set-up; render price and book from the first snapshot before the remaining layout mounts.

Three measurements appear on this page, and their times differ. Rank and results come from the campaign's timed reloads. The diagnostic capture and the recorded reload are single loads made with recording switched on, which slows the page: read them for the order of events and the gaps, not for totals.

Resultscampaign: 5 warm and 5 uncached reloads

Warm reloadmedian 2.4 s, range 2.4 s–2.8 s; loads: 2.5 s, 2.4 s, 2.8 s, 2.4 s, 2.4 s
Uncached reloadmedian 2.6 s, range 2.5 s–2.9 s; loads: 2.9 s, 2.5 s, 2.8 s, 2.5 s, 2.6 s
Standing1 of 27 by median; possible rank 1 to 2. The fastest in its group. The possible rank is the range the measurements leave open: it counts only the exchanges that clearly beat this one and those it clearly beats. Exchanges whose ranges overlap cannot be told apart.
Loads ready5 of 5 warm, 5 of 5 uncached

Where the time goescampaign medians, warm reload

Panels in the order they first showed real, usable data on a warm reload. The coloured part of each row is the time that panel added after the one before it. The last row is trade-ready: every panel is ready and the page has stopped moving.

0 s1 s2 s
Price1.4 s
Order form1.4 s +0.0 s
Recent trades1.7 s +0.3 s
Order book1.7 s +0.0 s
Chart1.8 s +0.1 s
Trade-ready2.4 s +0.7 s settling

Stack

Vue; TradingView chart library (library.js) from thalex.com; no third-party scripts at all.

Delivery

thalex.com through Cloudflare over HTTP/2; the HTML is marked no-cache and re-checked on each load (30 ms to the first byte); app files cached for ten years. In the 1 October capture only 14 KB was transferred, so although that capture was meant to be uncached, most files did not come over the network.

HostRoleCDN edge seenConnectResponse
thalex.compageCloudflare Amsterdam13 ms25 ms

Median of up to 10 attempts from the test machine. Response time includes the server's own time, so it is not a distance.

What happened, in orderdiagnostic capture 1 October, uncached

From one uncached diagnostic load recorded on 1 October 2026 (cache disabled, browser extensions active), so totals are slower than the campaign's timed loads; file names, sizes, headers, order of events and main-thread times are what the findings rely on. A main-thread time given for a script counts all the work that starts in that script, including code it calls in other files, so it shows where start-up work begins, not what one library costs. Endpoint paths were masked when the capture was saved.

WhenWhat
0.03 sHTML arrives.
0.09–0.47 sindex-CKxRR9q7.js (1.5 MB unpacked), from cache.
0.55 sThe market socket opens; handshake at 0.72 s; first message at 0.80 s.
0.71 sFirst paint.
2.03 sPage header shows the market.
2.77 sPrice and order book show, 2.0 s after the first feed message.
2.86 sChart drawn: trade-ready in this load.

Recorded warm reload, 3 October

One warm reload recorded with Chrome's performance trace. Recording slows the page, so read the order and the gaps, not the total.

WhenWhat
0.0 sHTML arrives
0.3 sFirst market-data request
0.4 sFirst frame sent on a live feed
0.4 sFirst frame received on a live feed
2.7 sPrice ready
2.7 sOrder form ready
3.3 sChart ready
3.3 sOrder book ready
3.3 sRecent trades ready
3.9 sTrade-ready

235 requests before trade-ready; 6 long main-thread tasks (over 50 ms) before trade-ready, longest 253 ms; 125 script requests before the first panel; 0 requests over HTTP/1.1.

Request waterfalldiagnostic capture 1 October, uncached

70 of the 134 requests (the page itself, the longest and the largest) started before market data was ready in the 1 October uncached capture, in start order. The outlined part of a bar is waiting for the server; the solid part is downloading. Rows are numbered so a request can be pointed to. The numbers on the right are the size received and the total time. Vertical lines mark when a panel had data in this capture.

PageScriptFont, media, other fileData requestwaiting for the serverdownloading

0 s0 s1 s1 s2 s2 s1thalex.com311 B21 ms2thalex.com/index-CKxRR9q7…376 ms3thalex.com/rolldown-runti…376 ms4thalex.com/runtime-core.e…377 ms5thalex.com/webApi-COfZ-cA…402 ms6thalex.com/usePortal-BDVO…379 ms7thalex.com/useApi-CROJJdh…379 ms8thalex.com/Link-Bx7Rf7bX.…381 ms9thalex.com/usePrimitiveEl…380 ms10thalex.com/Collection-DGb…380 ms11thalex.com/isValueEqualOr…380 ms12thalex.com/useFormControl…381 ms13thalex.com/useForwardScop…381 ms14thalex.com/VisuallyHidden…381 ms15thalex.com/utils-D9yJ7Gon…384 ms16thalex.com/RovingFocusGro…381 ms17thalex.com/RovingFocusIte…382 ms18thalex.com/Label-C2s1QEmT…382 ms19thalex.com/Checkbox-BZSbQ…383 ms20thalex.com/useArrowNaviga…382 ms21thalex.com/PopperArrow-BU…384 ms22thalex.com/CollapsibleTri…382 ms23thalex.com/AccordionTrigg…383 ms24thalex.com/useComposing-D…383 ms25thalex.com/ComboboxVirtua…388 ms26thalex.com/useNonce-Ch6X-…383 ms27thalex.com/overlay-CAPmPw…384 ms28thalex.com/namespaced-BVO…401 ms29thalex.com/Kbd-LbvXYQd7.js384 ms30thalex.com/Button-BJElhnx…385 ms31thalex.com/Tooltip-CZNEVW…386 ms32thalex.com/pinia-DqpR53zF…385 ms33thalex.com/types-Dy6y8GzX…388 ms34thalex.com/routeNames-DI3…385 ms35thalex.com/userStore-BAE8…386 ms36thalex.com/mainStore-CtOf…386 ms37thalex.com/usePermissions…386 ms38thalex.com/Badge-CNAqpPxN…389 ms39thalex.com/Popover-CgU4XJ…386 ms40thalex.com/useNotificatio…387 ms41thalex.com/useFilteredRou…390 ms42thalex.com/useLocale-DVmI…387 ms43thalex.com/Progress-CifIn…388 ms44thalex.com/Select-eE0xtpW…390 ms45thalex.com/Switch-CB9c-y-…388 ms46thalex.com/useOverlay-DgI…388 ms47thalex.com/Card-DvkIABcT.…390 ms48thalex.com/useFilter-BYux…390 ms49thalex.com/Input-Dh3wBEbw…391 ms50thalex.com/SelectMenu-C8t…392 ms51thalex.com/Logo-B-_5kbNP.…391 ms52thalex.com/_plugin-vue_ex…392 ms53thalex.com/DialogTrigger-…391 ms54thalex.com/Slideover-DKgY…393 ms55thalex.com/vue.BHyNcdic-B…395 ms56thalex.com/AppRouterTrans…392 ms57thalex.com/Modal-DUzwRUF-…393 ms58thalex.com/documentLinks-…396 ms59thalex.com/useRefreshMe-6…394 ms60thalex.com/preload-helper…393 ms61thalex.com/useOnboarding-…394 ms62thalex.com/onboardingStep…393 ms63thalex.com/dayjs.min-BwWo…394 ms64thalex.com/regle-core.min…396 ms65thalex.com54 B185 ms66thalex.com158 B103 ms67thalex.com747 B106 ms68thalex.com104 B77 ms69thalex.com77 B35 ms70thalex.com13 kB103 msprice 2.8 sorder book 2.8 schart 2.9 s
Download this figure as an image:

Bottlenecks and fixes, largest firstdiagnostic capture 1 October, uncached

TH-1Market data is on the socket 2 s before it is on screen.grade C
Evidence
First message at 0.80 s, price and book at 2.77 s on 1 October. 3 October recorded load: first frame received at 0.38 s, price at 2.73 s, book at 3.28 s. The fastest page in the test still spends most of its load between data and paint. About 1.0 s of main-thread script time in the 1 October capture is not attributed to any script. A lead from the same app's options screen, recorded logged out with a CPU profile: a 437 ms task at 0.60 s with about 107 ms sampled inside the translation runtime (vue-i18n.runtime-ByYFhQH0.js), in both of its two recordings. The perpetuals screen shares that code, so it is the first place to look.
Gap observed
2.0 s between the first socket message and the price on 1 October; 2.3 s on 3 October
Holds back
Price (median 1.4 s in the timed loads), book (median 1.7 s in the timed loads).
Fix
Profile the 2 s between the first socket message and the first price paint, starting with the translation runtime (vue-i18n) set-up; render price and book from the first snapshot before the remaining layout mounts.
Where
Vue app start-up and the trading layout; the largest start-up scripts are index-CKxRR9q7.js (1.5 MB unpacked), namespaced-BVOXSsx0.js (0.2 MB) and webApi-COfZ-cAG.js (0.2 MB).
Verify
DevTools → Performance: price paint within 200 ms of the first ticker message.
TH-2Trade-ready comes 0.7 s after the last panel has its data: the chart is still animating.grade B
Evidence
In the campaign the last panel (the chart in 4 of 5 warm loads, the order book in 1) has data at a median 1.76 s on a warm reload, and trade-ready follows at 2.45 s. The median wait before trade-ready, counted from the moment the page's main parts are in place, is 0.67 s, a quarter of Thalex's whole load time. In the slowest warm load the order book passed its check, failed it again for 0.5 s and passed once more, which delayed that load. In the recorded load and in all 10 timed loads we could replay, the readiness condition still failing during this wait is an animation running inside the chart panel; the panels do not move. Our records count the animated elements (3 in the recorded load) but do not keep their names. In 5 of the 10 timed loads the fonts were also still loading during the wait.
Gap observed
0.67 s median wait before trade-ready, counted from when the main parts are in place
Holds back
Trade-ready itself: the page counts as ready only when nothing in a panel is still animating or loading.
Fix
Record a reload with DevTools → Animations and find what still animates in the chart after the candles are drawn, for example a toolbar loading spinner or a fade-in; end it when the data is in. Also check that the fonts are loaded before the panels show.
Where
The chart panel and its loading states.
Verify
DevTools → Animations during a reload: nothing in the chart container animates after the candles appear.
TH-3125 script requests go out before the first panel.grade C
Evidence
The 3 October recorded warm load made 154 script requests, 125 of them before the price showed at 2.73 s. Almost all came from the browser's cache (209 of 263 requests), so download time is not the cost here. The longest main-thread task, 253 ms, starts at 0.45 s. All 10 timed loads show the same first second: 69 script requests in the first half second and 52 in the second.
Gap observed
0.253 s of main-thread time in the longest task
Holds back
Every panel: nothing is shown before this ends.
Fix
Combine the start-up chunks the trading screen needs into a few files, and load the rest after the first price paint.
Where
Bundler chunking for the trading route.
Verify
DevTools → Network: script requests before the first price paint.

Grade B: the capture shows the problem directly. Grade C: the order of events in the capture points to it; the dependency is for the team to confirm. The order is our judgement of each finding's effect on trade-ready, largest first; it is not sorted by gap. A gap is the time between two observed events or the time one piece of work takes; gaps overlap and do not add up. Where a finding is about size or count and no time was measured, the row says what was measured instead. Holds back names the panel the finding delays. Nothing here is graded higher, because no fix was confirmed by changing a page and measuring again.

How this was measured

Timings: 5 warm and 5 uncached reloads in a seeded random order across all exchanges, each judged against a checklist frozen for this page before the campaign; trade-ready is the first moment every checklist panel shows real data, nothing is still loading, and the layout holds still for 0.5 s. The findings on this page come from separate recorded loads, which are never part of the timings. Full method.