Onzas troy, gramos y kilogramos: cómo convertir bien los precios de los metales preciosos
Onza troy frente a onza avoirdupois, factores exactos para gramos y kilogramos, el parámetro unit de la API, el redondeo y los errores que desvían los precios casi un 10 %.
Por qué importa la unidad
Los metales preciosos se cotizan por onza troy casi en todas partes: en los mercados mayoristas, en las listas de precios de los distribuidores de lingotes y en las API de precios. En cambio, quienes compran y venden metal piensan en gramos, kilogramos, tolas o taeles, según dónde vivan y qué negocien. Por eso, cualquier producto que muestre un precio de metal a las personas contiene al menos una conversión de unidades, y esa conversión es una fuente habitual de errores silenciosos y de apariencia verosímil.
El error clásico es tratar una onza troy como una onza normal. Las dos difieren casi un 10 %, lo bastante para importar en cada factura, pero lo bastante poco para que nadie lo note en una demo. Este artículo cubre las definiciones exactas, los factores de conversión, cómo dejar que la API convierta por ti, cómo redondear y mostrar los resultados, y una lista de errores para los que vale la pena escribir pruebas.
Onza troy frente a onza avoirdupois
Ambas onzas se definen en granos, y el grano tiene una definición métrica exacta: 1 grano = 64,79891 miligramos. Todo lo demás se deduce de ahí:
- Una onza troy son 480 granos, exactamente 31,1034768 gramos. Es la unidad en la que se cotizan el oro, la plata, el platino y el paladio.
- Una onza avoirdupois, la onza cotidiana para alimentos y paquetes en Estados Unidos y el Reino Unido, son 437,5 granos, exactamente 28,349523125 gramos.
- Una libra troy tiene 12 onzas troy (373,2417216 g), mientras que la libra avoirdupois tiene 16 onzas avoirdupois (453,59237 g). Así que la onza troy es la onza más pesada, pero la libra troy es la libra más ligera.
| Unidad | Granos | Gramos (exactos) | Onzas troy |
|---|---|---|---|
| Grano | 1 | 0,06479891 | 0,0020833… |
| Pennyweight (dwt) | 24 | 1,55517384 | 0,05 |
| Onza avoirdupois | 437,5 | 28,349523125 | 0,9114583… |
| Onza troy | 480 | 31,1034768 | 1 |
| Libra troy | 5760 | 373,2417216 | 12 |
| Libra avoirdupois | 7000 | 453,59237 | 14,5833… |
Una onza troy es aproximadamente un 9,7 % más pesada que una onza avoirdupois (480 ÷ 437,5 ≈ 1,0971). Esa proporción es exactamente el tamaño del error que se produce cuando se confunden las dos.
Salvo que una fuente diga lo contrario, la onza de un precio de metales preciosos es una onza troy, a menudo escrita oz t u ozt. En MetalAPI la unidad por defecto es troy_oz, y todos los precios de los metales son por onza troy a menos que pidas otra cosa.
Factores de conversión exactos
Como todas estas unidades tienen una definición exacta, las conversiones no necesitan aproximaciones. Para convertir un precio por onza troy en un precio por otra unidad, multiplica por el número de onzas troy que contiene esa unidad:
precio por unidad = precio por onza troy × gramos por unidad ÷ 31,1034768
| Precio por | Gramos en una unidad | Multiplica el precio por onza troy por |
|---|---|---|
| Gramo | 1 | 0,0321507466 |
| Kilogramo | 1000 | 32,1507466 |
| Onza avoirdupois | 28,349523125 | 0,9114583333 |
| Libra avoirdupois | 453,59237 | 14,5833333 |
| Tonelada métrica | 1.000.000 | 32.150,7466 |
| Tonelada corta (2000 lb) | 907.184,74 | 29.166,6667 |
| Tola | 11,6638038 | 0,375 |
| Pennyweight | 1,55517384 | 0,05 |
La tola, todavía muy usada para el oro en el sur de Asia y el Golfo, se define como 180 granos: exactamente 11,6638038 g, o tres octavos de onza troy. El tael es menos regular, porque su peso depende del mercado: unos 37,4 g en el comercio de oro de Hong Kong, 37,5 g en Taiwán y 50 g en China continental. Si admites taeles, haz que el peso en gramos sea un valor de configuración e indica a qué tael te refieres.
Los lingotes de un kilo son una comprobación rápida muy práctica. Un kilogramo son unas 32,15 onzas troy, así que un precio por kilo siempre debería ser aproximadamente 32 veces el precio por onza. Si se acerca más a 35 veces, alguien ha usado el factor avoirdupois.
Convertir a mano
Si ya tienes un precio por onza troy, convertirlo tú mismo es una sola multiplicación. Guarda las constantes exactas en un único módulo y convierte pasando por los gramos, para que cualquier par de unidades funcione igual:
// Gramos en una unidad de cada tipo. Todos exactos: 1 grano = 64.79891 mg.
const GRAMS_PER_UNIT = {
troy_oz: 31.1034768, // 480 granos
gram: 1,
kilogram: 1000,
ounce: 28.349523125, // avoirdupois, 437.5 granos
pound: 453.59237, // avoirdupois, 7,000 granos
metric_ton: 1_000_000,
short_ton: 907_184.74, // 2,000 lb
tola: 11.6638038, // 180 granos
pennyweight: 1.55517384, // 24 granos
};
/** Convierte un precio por unidad `from` en un precio por unidad `to`. */
export function convertPrice(price, from, to) {
const a = GRAMS_PER_UNIT[from];
const b = GRAMS_PER_UNIT[to];
if (a === undefined || b === undefined) throw new Error(`Unknown unit: ${a === undefined ? from : to}`);
return (price / a) * b;
}
console.log(convertPrice(3997.89, "troy_oz", "gram")); // 128.535148…
console.log(convertPrice(3997.89, "troy_oz", "kilogram")); // 128535.148…
console.log(convertPrice(3997.89, "troy_oz", "tola")); // 1499.20875En Python, usa Decimal cuando el resultado acabe en una factura o en un libro contable. requests pasa parse_float al analizador de JSON, así que los precios nunca pasan por un número de coma flotante binario:
import os
from decimal import Decimal, ROUND_HALF_UP
import requests
GRAMS_PER_TROY_OZ = Decimal("31.1034768")
CENT = Decimal("0.01")
r = requests.get(
"https://metalapi.com/api/v1/latest",
params={"currencies": "XAU"},
headers={"X-API-Key": os.environ["METALAPI_KEY"]},
timeout=10,
)
data = r.json(parse_float=Decimal)
if not data["success"]:
raise RuntimeError(data["error"])
per_oz = data["rates"]["USDXAU"] # p. ej., Decimal("3997.89")
per_gram = per_oz / GRAMS_PER_TROY_OZ
per_kg = per_gram * 1000
print(per_gram.quantize(CENT, rounding=ROUND_HALF_UP)) # 128.54 con el precio de ejemplo
print(per_kg.quantize(CENT, rounding=ROUND_HALF_UP)) # 128535.15Las cotizaciones inversas requieren la operación contraria. rates.XAU son onzas troy por cada unidad de la divisa base, así que los gramos por unidad de divisa son rates.XAU × 31,1034768, no ÷. Esa trampa es un motivo más para trabajar con las claves de precio con prefijo, como USDXAU, y dejar de lado las claves inversas.
Dejar que la API convierta: el parámetro unit
También puedes pedir a MetalAPI la unidad que necesitas. /latest, los endpoints históricos, /timeframe, /ohlc, /convert y /carat aceptan un parámetro unit: troy_oz (por defecto), gram, kilogram, ounce, pound, metric_ton o short_ton. Esta solicitud devuelve el oro y la plata en euros por gramo:
curl "https://metalapi.com/api/v1/latest?base=EUR¤cies=XAU,XAG&unit=gram" \
-H "X-API-Key: $METALAPI_KEY"Cuando la unidad no es la predeterminada, la respuesta la repite en un campo unit de nivel superior. Los valores siguientes son un ejemplo de la documentación, no precios en tiempo real:
{
"success": true,
"timestamp": 1792765800,
"date": "2026-10-23",
"base": "EUR",
"unit": "gram",
"rates": {
"XAU": 0.009057444725,
"EURXAU": 110.4064149,
"XAG": 0.6713138244,
"EURXAG": 1.489616277
}
}La API usa los mismos factores exactos que las tablas anteriores, y la clave inversa también sigue la unidad: con unit=gram, rates.XAU son gramos de oro por euro. Algunas reglas que conviene conocer:
- Se aceptan formas abreviadas como
g,kg,lbytonne.ozsignifica la onza avoirdupois, así que nunca la uses como abreviatura de onza troy. - Una unidad desconocida devuelve el error
209(invalid_unit). unitsolo se aplica a los metales preciosos e industriales. La energía sigue cotizándose por barril, MMBtu o galón, y las divisas y las criptomonedas no se ven afectadas, así que mezclar símbolos en una misma solicitud es seguro.- Los metales industriales también se cotizan por onza troy de forma predeterminada, así que todos los metales se pueden comparar directamente. Pasa
unit=poundpara el cobre,unit=metric_tonpara el aluminio y el zinc, yunit=short_tonpara el acero, y obtendrás las unidades en las que se negocian esos mercados.
/convert también acepta unit, lo que convierte un peso en dinero en un solo paso. Esto valora 250 gramos de oro en dólares estadounidenses:
curl "https://metalapi.com/api/v1/convert?from=XAU&to=USD&amount=250&unit=gram" \
-H "X-API-Key: $METALAPI_KEY"info.rate es el precio de un gramo en dólares estadounidenses y result es el valor de la cantidad completa. Con el precio del oro de ejemplo, la respuesta tiene este aspecto:
{
"success": true,
"query": { "from": "XAU", "to": "USD", "amount": 250, "unit": "gram" },
"info": { "timestamp": 1792834892, "rate": 128.5351482, "quote": 128.5351482 },
"date": "2026-10-24",
"result": 32133.78705
}Redondeo y presentación
Las cotizaciones llegan como números JSON con hasta 10 cifras significativas. Esa precisión existe para que los valores derivados sean exactos, así que consérvala hasta el último momento posible:
- Convierte primero, redondea al final. Redondear el precio por gramo a céntimos y después multiplicarlo por 1000 para un lingote de un kilo convierte un error de redondeo de medio céntimo en un error de hasta cinco unidades monetarias.
- Redondea según la divisa. La mayoría de las divisas usan dos decimales, el yen japonés ninguno y el dinar kuwaití tres. Deja que
Intl.NumberFormato tu biblioteca de localización elijan los valores predeterminados en lugar de fijar dos a mano. - Admite más decimales en los precios pequeños. Con el precio de ejemplo de 53,94 USD por onza troy, la plata cuesta unos 1,73 USD por gramo, y con dos decimales se pierde la mayor parte de su movimiento diario.
- Usa tipos decimales para el dinero.
Decimalen Python,BigDecimalen Java, o unidades monetarias mínimas enteras en tu base de datos para todo lo que se facture o se contabilice. Los números de coma flotante binarios sirven para los gráficos. - Indica la unidad. Pon “por onza troy”, “por gramo” o “por kg” junto a cada precio. Un simple “por onza” resulta ambiguo para muchos lectores.
Una pequeña función auxiliar que toma de Intl los decimales estándar de la divisa y, opcionalmente, añade algunos más:
function formatPrice(value, currency, locale = "en-US", extraDigits = 0) {
const { maximumFractionDigits } = new Intl.NumberFormat(locale, { style: "currency", currency }).resolvedOptions();
const digits = maximumFractionDigits + extraDigits;
return new Intl.NumberFormat(locale, {
style: "currency",
currency,
minimumFractionDigits: digits,
maximumFractionDigits: digits,
}).format(value);
}
formatPrice(128.53514819925212, "USD"); // "$128.54" oro por gramo
formatPrice(1.7342112699117933, "USD", "en-US", 2); // "$1.7342" plata por gramo
formatPrice(110.4064149, "EUR", "de-DE"); // "110,41 €"Tabla de conversión de un vistazo
La tabla convierte los precios de ejemplo que se usan en la documentación de MetalAPI, 3997,89 USD por onza troy para el oro y 53,94 USD por onza troy para la plata. Ilustran la aritmética y no son precios de mercado actuales:
| Precio por | Oro (USD) | Plata (USD) |
|---|---|---|
| Onza troy | 3997,89 | 53,94 |
| Gramo | 128,54 | 1,7342 |
| Kilogramo | 128.535,15 | 1734,21 |
| Tola (11,6638 g) | 1499,21 | 20,23 |
| Pennyweight (1,5552 g) | 199,89 | 2,697 |
| Libra troy (12 oz t) | 47.974,68 | 647,28 |
| Onza avoirdupois | 3643,91 | 49,16 |
Fíjate en la última fila. Si una página presenta la cifra avoirdupois como el precio por onza, subestima el precio del lingote en casi un 9 %. El error contrario, dividir un precio por onza troy entre 28,35 para obtener un precio por gramo, lo sobrestima en un 9,7 % aproximadamente: 141,02 en lugar de 128,54 por gramo de oro.
Errores de conversión habituales y cómo detectarlos con pruebas
La mayoría de los errores de unidades siguen unos pocos patrones:
- Dividir entre 28,35. Usar el factor avoirdupois para un precio por onza troy. Usa 31,1034768.
- Tratar `oz` como onza troy. En MetalAPI, como en la mayoría de las bibliotecas de unidades,
ozes la onza avoirdupois. Los precios de lingotes necesitantroy_oz, o ningúnunit. - Convertir la clave inversa.
rates.XAUson onzas por unidad de divisa, no un precio. Convertirla a gramos significa multiplicar por 31,1034768, lo que parece un error a cualquiera acostumbrado a dividir. - Convertir dos veces. Pedir
unit=gramy después volver a dividir entre 31,1034768 da un precio unas 31 veces demasiado pequeño. Decide si la conversión se hace en la API o en tu código, nunca en ambos. - Redondear demasiado pronto. Redondea una sola vez, al mostrar el valor.
- Compartir la caché entre unidades. Si la clave de tu caché ignora la cadena de consulta, se puede servir una respuesta por gramo donde se esperaba un precio por onza. Incluye
unitybaseen la clave. - Aplicar unidades de peso a la energía.
unitno tiene efecto sobre el petróleo ni el gas, y dividir un precio por barril entre 31,1 no tiene sentido. Limita las conversiones según la categoría, que/symbols?details=1devuelve para cada símbolo.
Unas pocas pruebas de propiedades detectan la mayoría de estos errores antes de que lleguen a producción. Usan el ejecutor de pruebas integrado de Node y la función convertPrice de arriba; ejecútalas con node --test:
import { test } from "node:test";
import assert from "node:assert/strict";
import { convertPrice } from "./units.mjs";
const PER_OZ = 3997.89; // precio de ejemplo, USD por onza troy
test("a kilogram price is 1,000 gram prices", () => {
const g = convertPrice(PER_OZ, "troy_oz", "gram");
const kg = convertPrice(PER_OZ, "troy_oz", "kilogram");
assert.ok(Math.abs(kg - g * 1000) < 1e-6);
});
test("converting there and back returns the original price", () => {
const g = convertPrice(PER_OZ, "troy_oz", "gram");
assert.ok(Math.abs(convertPrice(g, "gram", "troy_oz") - PER_OZ) < 1e-9);
});
test("an avoirdupois ounce costs less than a troy ounce", () => {
assert.ok(convertPrice(PER_OZ, "troy_oz", "ounce") < PER_OZ);
});
test("a kilogram holds about 32.15 troy ounces", () => {
const kg = convertPrice(PER_OZ, "troy_oz", "kilogram");
assert.ok(Math.abs(kg / PER_OZ - 32.1507466) < 1e-6);
});Si pones precio a joyas, el siguiente paso es la pureza: Precios del oro por quilate construye los precios de 22K y 18K sobre estas conversiones. La guía de formatos de datos y la sección de unidades de la documentación de la API documentan todos los valores de unidad, y la página de símbolos muestra la unidad en la que se negocia cada mercado.
Pruébalo con tus propios datos
Crea una cuenta gratuita y haz tu primera solicitud en menos de dos minutos. 100 solicitudes al mes, sin tarjeta de crédito.
Sigue leyendo
API de precios del oro: la guía completa para desarrolladores
Cómo usar una API de precios del oro: obtén una clave, llámala desde curl, JavaScript y Python, lee bien las cotizaciones y gestiona historial, errores, cuotas y caché.
Precios del oro por quilate: 24K, 22K, 18K y cómo calcularlos
Qué significan 24K, 22K y 18K, cómo se relacionan con leyes como 916 y 750, cómo calcular el precio por gramo del oro por quilate y cómo obtenerlo de una API.
Precios históricos del oro y la plata por API: 25 años de datos diarios
Obtén precios diarios del oro y la plata desde 2000 con /historical, /timeframe, /change y /ohlc, divide los rangos largos por años, guarda los datos y crea gráficos.