Use a monotonic clock for elapsed request budgets and a synchronized wall clock for authenticated epoch timestamps. A monotonic reading has a local origin; it is not the UTC time an exchange expects. Keep both measurements because a clock adjustment can make a request appear young locally while its signed timestamp is already stale at the exchange.
A client needs to answer two different questions: how long has this attempt been waiting, and what time does the signed request claim it was created? Recording only one clock makes those questions harder to separate during an incident.
Assign each clock a job
A wall clock supplies calendar time, commonly represented as milliseconds since the Unix epoch. It can be corrected when the computer's time is wrong. A monotonic clock measures progression without moving backward because of a wall-clock correction. The W3C High Resolution Time working draft describes this distinction and the limited contexts within which its monotonic readings can be compared.
| Client operation | Clock or evidence to use | Reason |
|---|---|---|
| Measure one request's round trip | Same monotonic source at both ends | A calendar correction should not distort elapsed time |
| Enforce an in-process attempt budget | Monotonic deadline, rechecked before work | Waiting consumes the budget even if UTC moves backward |
| Populate an exchange authentication timestamp | Synchronized epoch time in the documented unit | The exchange compares against its own time |
| Correlate an incident across services | UTC records plus request identity and synchronization status | Different processes do not necessarily share a monotonic origin |
| Recover after a restart | Durable request/order records and fresh clock state | An old local timer is not automatically meaningful in the new process |
In Node.js, performance.now() reports milliseconds relative to the current process's start. Sending that value directly as an exchange timestamp would confuse elapsed process time with an epoch instant. The Node.js performance API reference also defines performance.timeOrigin, the process's epoch-related starting point.
Adding those two values can produce an estimate in epoch units, but it does not establish current synchronization with the exchange. Keep the distinction between a convenient time representation and a verified current clock.
Authentication checks do not measure your timer
Binance Spot requires a current timestamp on signed requests and documents a receive window for request validity. Its logic checks both excessive age and a timestamp too far ahead, with another age check during processing. Those are exchange acceptance conditions; a client-side stopwatch cannot satisfy them by itself. Units and rules remain specific to the API. Binance Spot timing security.
Bybit's V5 guidance separately specifies a UTC millisecond header and recommends keeping local device time synchronized with NTP. That is a useful reminder to inspect the actual signing machine, which may be a remote backend rather than the user's laptop. Bybit authenticated request timing.
Generate the timestamp close to transmission, after any application queue, using the venue's supported approach. Once the timestamp enters the signed representation, keep the transmitted representation consistent. Changing its timestamp afterward requires reconstructing authentication correctly; the URL encoding and signature guide explains why the exact request bytes matter.
For error-code diagnosis and receive-window boundaries, use the existing timestamp versus signature troubleshooting guide. The issue here is which clock produced the evidence, rather than another recipe for replacing credentials.
A backward jump can break two checks differently
Consider this hypothetical incident. The exchange and client initially agree on UTC. A request attempt has an invented 800 ms local budget. After 600 ms of actual elapsed time, the client wall clock is stepped backward by 2,000 ms. The monotonic clock continues normally. These values illustrate arithmetic, not a measured outage or recommended budget.
| Observation | Client wall time, UTC | Monotonic reading |
|---|---|---|
| Attempt begins | 12:00:00.000 | 50,000 ms |
| Timestamp created after the adjustment | 11:59:58.600 | 50,600 ms |
The same two observations produce very different results:
| Calculation | Result | Interpretation |
|---|---|---|
| Monotonic difference | 50,600 − 50,000 = 600 ms | The attempt has used 600 ms |
| Wall-clock difference | 11:59:58.600 − 12:00:00.000 = −1,400 ms | This cannot represent the actual wait |
| Monotonic budget remaining | 800 − 600 = 200 ms | Only 200 ms remains |
| Wall deadline minus current wall time | 12:00:00.800 − 11:59:58.600 = 2,200 ms | A wall-based deadline wrongly appears much farther away |
Now suppose the client signs with 11:59:58.600 and transmission takes 150 ms. The exchange evaluates it at 12:00:00.750. The signed timestamp is 2,150 ms old at the exchange even though only 150 ms passed since signing.
Under a hypothetical 2,000 ms receive window, that request fails the modeled age comparison by 150 ms. Its modeled arrival occurs 50 ms before the local duration deadline. The two checks disagree because they answer different questions. A forward clock step can produce the opposite timing symptom: a future-dated authentication timestamp and an apparently exhausted wall deadline.
Keep a small clock ledger
A useful diagnostic records paired wall and monotonic observations near the beginning and end of an operation. Their difference of differences estimates the wall-clock change relative to elapsed time over that interval:
w = wall1 - wall0
m = mono1 - mono0
change = w - m
In the incident, change = -1400 - 600 = -2000 milliseconds. This exposes the backward adjustment. It does not identify the clock service responsible, prove the exchange clock correct or estimate one-way network latency. Separate clock reads also introduce a small sampling gap; avoid presenting the result as infinitely precise.
Use this worksheet when reviewing a client or incident:
| Record | What to retain |
|---|---|
| Clock scope | Host, process generation, runtime and monotonic source |
| Attempt identity | Request ID and original order identity, where applicable |
| Duration evidence | Start/end monotonic readings and budget used |
| Signing evidence | Timestamp unit, UTC value and delay from signing to send |
| Synchronization evidence | Last supported time check, its age and observed uncertainty |
| Discontinuity evidence | Paired clock differences and any restart or resume event |
| Outcome evidence | Provider response or an explicitly unresolved exchange state |
Keep the identifiers exact when attaching this ledger to an order. The large integer identifier guide covers why converting a long exchange ID to an imprecise number can detach otherwise useful timing evidence from the correct order.
Revalidate after resume, restart or a bad time sample
Do not persist a process-relative deadline and subtract a new process's timer from it. Do not assume all runtimes count suspended time identically. Python, for example, documents the platform clock implementations behind time.monotonic() and exposes information about adjustability and resolution. Verify the selected runtime and operating system rather than inferring behavior from the name alone. Python clock documentation.
For a client that caches a server-time correction or maps an epoch sample onto monotonic elapsed time, give that state an explicit expiry and scope. Refresh it after a detected discontinuity, restart or resume under the client's defined policy. A one-time server-time response contains network uncertainty and cannot prove the mapping stays accurate indefinitely.
A timer callback can also run late because the process was busy or paused. Recheck the deadline and clock readiness when execution resumes, before sending work. Market observations also need a separate source-time comparison; the market-data freshness guide distinguishes that age from time spent waiting locally. An elapsed-time budget limits willingness to continue; it cannot undo an order already sent.
If the response to that order is missing, preserve its unresolved status and follow order timeout reconciliation. Correcting the clock gives subsequent requests a better timing basis. It does not reveal what the previous request did at the exchange.
This AI-assisted educational article uses official API and runtime documentation reviewed on 23 October 2026. The incident and worksheet are original constructions. They describe client design and diagnostic choices, without claiming that KLINEO exposes these controls or implements every policy shown.
