Track data age separately from request success, and give every retry a limit.
Separate two clocks
A response arriving now does not necessarily contain a price observed now. MetaTrader’s tick data includes a price-update timestamp. Keep the upstream observation time separate from the time your application received the response.
Our recommended model records both. Observation age helps describe the data on screen; receipt age helps you investigate the delivery path. Use a synchronized clock, and treat timestamps unexpectedly in the future as a diagnostic signal rather than displaying a negative age. [1]
Model freshness as a visible state
Design explicit states for loading, available, stale, and unavailable. Define a freshness threshold for your application and display the last observation time. A successful HTTP response alone should not turn an old quote into a fresh one.
A lack of new observations can have several causes, including a market pause or a feed problem. Do not claim to know which from the timestamp alone. Combine the source’s session information and any available feed-health signals before explaining the cause to users.
Respect the rate-limit response
HTTP 429 indicates that too many requests were made in a given period. RFC 6585 allows the server to include Retry-After to indicate when a client can try again. The standard does not require every server to use the same counting method.
When Retry-After is supplied, honor it. Otherwise, our recommended fallback is bounded exponential backoff with jitter: increase the delay after repeated failures, add randomness so clients do not retry together, and stop after a defined attempt or time budget. Keep authentication failures out of that retry loop. [2]
Make polling a shared responsibility
Avoid giving every widget an independent polling loop. A shared data layer can fetch a quote once and distribute it to several components. Schedule the next poll after the previous request settles so slow responses do not create an expanding queue.
Use request timeouts, discard older responses that arrive after newer ones, and pause unnecessary work when the view is inactive. Test a timeout, a 429, an expired credential, and a successful response with an old observation time. These cases reveal more about the user experience than a happy-path request alone.
References
Primary sources for the technical details in this article. Implementation suggestions are our own.