Backtest a gold strategy with historical OHLC
Pull daily OHLC history from the goldprice.dev API and run a simple moving-average crossover backtest in Python to evaluate a gold trading strategy.
Read →Connect to the goldprice.dev SSE stream to receive real-time gold price updates in the browser and Node.js, with automatic reconnect handling.
Polling an API every few seconds works until it doesn't. You burn request quota, you add latency equal to half your poll interval on average, and you end up with stale prices sitting in cache right when a move happens. The stream endpoint solves all three. If you're not yet at the stage where you need streaming, Caching gold prices and staying inside rate limits covers the polling approach and when to graduate to SSE.
GET /v1/prices/stream?symbol=XAU-USD-SPOT is a Server-Sent Events connection. The server pushes each new price tick as a JSON event. Your client just listens.
Each event looks like this:
{
"symbol": "XAU-USD-SPOT",
"price": 2341.80,
"computed_at": "2026-06-19T08:14:22.411Z"
}
The computed_at timestamp tells you exactly when the price was computed server-side. You can display it directly or use it to calculate staleness.
The stream is a Pro tier feature. If you're on Free, the polling endpoint at /v1/spot/XAU-USD-SPOT gives you the same data on demand, useful for building and testing before upgrading.
EventSource is built into every modern browser. You do not need a library.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Gold Price</title>
</head>
<body>
<p>XAU/USD: <span id="price">—</span></p>
<p>Updated: <span id="ts">—</span></p>
<script>
const API_KEY = "ga_live_YOUR_KEY_HERE";
const url = `https://api.goldprice.dev/v1/prices/stream?symbol=XAU-USD-SPOT`;
const source = new EventSource(url, {
// EventSource doesn't support custom headers natively in the browser.
// Pass the key as a query param instead.
});
// Most SSE servers send named events; fall back to onmessage for unnamed ones.
source.onmessage = (event) => {
const data = JSON.parse(event.data);
document.getElementById("price").textContent =
`$${data.price.toFixed(2)}`;
document.getElementById("ts").textContent =
new Date(data.computed_at).toLocaleTimeString();
};
source.onerror = (err) => {
console.error("SSE error", err);
// The browser reconnects automatically after a short delay.
// You can close and reopen manually if you need custom backoff.
};
</script>
</body>
</html>
One limitation: the browser's EventSource API does not let you set custom headers, so the auth token goes in the query string. That is fine for client-side code where the key is already exposed to the browser. Scope the key to read-only if your dashboard allows it.
In Node.js you have two options: the eventsource npm package (which mirrors the browser API) or a raw fetch with a streaming body. The eventsource package is simpler and handles reconnect automatically.
npm install eventsource
import EventSource from "eventsource";
const API_KEY = process.env.GOLDPRICE_API_KEY;
const url = new URL("https://api.goldprice.dev/v1/prices/stream");
url.searchParams.set("symbol", "XAU-USD-SPOT");
const source = new EventSource(url.toString(), {
headers: {
Authorization: `Bearer ${API_KEY}`,
},
});
source.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(`[${data.computed_at}] XAU/USD ${data.price}`);
};
source.onerror = (err) => {
console.error("Stream error:", err);
// eventsource retries automatically with exponential backoff.
};
// Graceful shutdown
process.on("SIGINT", () => {
source.close();
process.exit(0);
});
The headers option in the Node.js eventsource package lets you send Authorization properly, unlike the browser version. Keep your key in an environment variable, not in source.
SSE reconnects automatically when the connection drops. The server sends a retry: field in the event stream to suggest a reconnect delay in milliseconds. If you need tighter control (say, you want to give up after five consecutive failures and alert an operator), track the error count yourself:
let errorCount = 0;
const MAX_ERRORS = 5;
source.onerror = (err) => {
errorCount++;
if (errorCount >= MAX_ERRORS) {
console.error("Too many stream errors, stopping.");
source.close();
// Alert, then decide whether to restart with a longer delay.
return;
}
console.warn(`Stream error #${errorCount}, will retry automatically`);
};
source.onmessage = () => {
// Reset on successful message
errorCount = 0;
};
The stream is the right choice when you need sub-second latency and you're keeping a persistent connection open: a dashboard, a price ticker, a trading interface. For background jobs that check the price once every few minutes, the plain GET /v1/spot/XAU-USD-SPOT endpoint is simpler and cheaper on your rate-limit quota.
The free tier covers 1000 calls per month at up to 30 requests per minute. If your polling frequency fits inside that budget, start there and graduate to the stream when you need it. See pricing to compare plan limits.
Get your API key via the quickstart guide.
// related guides
Pull daily OHLC history from the goldprice.dev API and run a simple moving-average crossover backtest in Python to evaluate a gold trading strategy.
Read →Pull gold and silver spot prices in a single async call, divide them, and display the ratio with a working JavaScript example.
Read →How to convert a USD per troy ounce gold price into other currencies and per-gram units, with a working JavaScript example.
Read →// goldprice.dev
Live gold prices, historical OHLC, and multi-source aggregation — available via REST and SSE.