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 →Pull gold and silver spot prices in a single async call, divide them, and display the ratio with a working JavaScript example.
The gold-to-silver ratio is the spot price of gold divided by the spot price of silver. A ratio of 80 means one troy ounce of gold buys 80 troy ounces of silver. Traders watch this ratio as a relative-value signal: when it is historically high, silver is cheap versus gold; when it is low, gold is cheap versus silver. For the market context behind why traders watch this, see The gold-to-silver ratio, explained. Computing it requires pulling both prices simultaneously and dividing — straightforward with the API.
Silver requires a paid tier on goldprice.dev. Gold spot is available on the free tier. To follow the code below, sign up at goldprice.dev/onboarding and upgrade to access XAG-USD-SPOT.
The /v1/prices endpoint accepts multiple symbols in a single request, which is the right approach here. Two separate calls would introduce a timing gap between the gold and silver prices, making the ratio less accurate. One call returns both at the same server-side timestamp.
const API_KEY = process.env.GOLDPRICE_API_KEY;
async function fetchSpotPrices(symbols) {
const url = new URL("https://api.goldprice.dev/v1/prices");
symbols.forEach((s) => url.searchParams.append("symbol", s));
const res = await fetch(url.toString(), {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!res.ok) {
throw new Error(`API error ${res.status}: ${await res.text()}`);
}
const data = await res.json();
return data.symbols; // array of { symbol, price, currency, unit, timestamp }
}
The response looks like this:
{
"symbols": [
{
"symbol": "XAU-USD-SPOT",
"price": 2387.45,
"currency": "USD",
"unit": "troy_oz",
"timestamp": "2026-06-19T08:32:11Z"
},
{
"symbol": "XAG-USD-SPOT",
"price": 29.84,
"currency": "USD",
"unit": "troy_oz",
"timestamp": "2026-06-19T08:32:11Z"
}
]
}
async function getGoldSilverRatio() {
const prices = await fetchSpotPrices(["XAU-USD-SPOT", "XAG-USD-SPOT"]);
const bySymbol = Object.fromEntries(prices.map((p) => [p.symbol, p]));
const gold = bySymbol["XAU-USD-SPOT"];
const silver = bySymbol["XAG-USD-SPOT"];
if (!gold || !silver) {
throw new Error("Missing one or both symbols in response");
}
if (silver.price <= 0) {
throw new Error("Invalid silver price");
}
const ratio = gold.price / silver.price;
return {
ratio: parseFloat(ratio.toFixed(2)),
gold: gold.price,
silver: silver.price,
timestamp: gold.timestamp,
};
}
getGoldSilverRatio().then((result) => {
console.log(`Gold: $${result.gold}/oz`);
console.log(`Silver: $${result.silver}/oz`);
console.log(`Gold/Silver ratio: ${result.ratio}`);
console.log(`As of: ${result.timestamp}`);
});
Sample output:
Gold: $2387.45/oz
Silver: $29.84/oz
Gold/Silver ratio: 79.97
As of: 2026-06-19T08:32:11Z
The ratio moves across a wide historical range. Values above 80 have repeatedly preceded periods of silver outperformance relative to gold, though the timing is unpredictable — the ratio can stay elevated for months before reverting. Values below 50 tend to coincide with commodity boom conditions where industrial silver demand compounds the monetary demand.
The ratio is a comparison, not a price level. A high ratio does not mean silver will rise; it means silver is cheap relative to gold at that moment. The actual direction of both metals is determined by their independent demand drivers.
For this reason, a useful addition to the display is a simple historical context marker. If you store the ratio daily, you can show the current reading against its 30-day or 90-day average:
function classifyRatio(current, average) {
const pct = ((current - average) / average) * 100;
if (pct > 5) return "above recent average";
if (pct < -5) return "below recent average";
return "near recent average";
}
If you are building a dashboard, schedule this calculation to run every few minutes and cache the result rather than computing it live on each page load. A simple server-side cron or a background function that writes to a key-value store keeps your API call count predictable and your frontend fast.
// Example: update every 5 minutes with setInterval (Node.js server process)
let latestRatio = null;
async function updateRatio() {
try {
latestRatio = await getGoldSilverRatio();
} catch (err) {
console.error("Ratio update failed:", err.message);
// keep serving the last known value
}
}
updateRatio();
setInterval(updateRatio, 5 * 60 * 1000);
// Expose latestRatio via an HTTP handler in your server framework of choice
The gold-to-silver ratio is one of the oldest cross-asset comparisons in metals trading. With two API calls collapsed into one request, you have the data and the arithmetic to display it with a single async function. If you need to cache this efficiently to stay inside rate limits, see Caching gold prices and staying inside rate limits.
// 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 →How to convert a USD per troy ounce gold price into other currencies and per-gram units, with a working JavaScript example.
Read →Read per-source prices from the API response, compute the spread in basis points, and flag when sources disagree beyond your tolerance threshold.
Read →// goldprice.dev
Live gold prices, historical OHLC, and multi-source aggregation — available via REST and SSE.