Skip to content
Docs
Get API Access
Browse the Documentation

Decimals and Precision

Every price, amount and ratio is an exact decimal string. Parse, compare, format and compute with them without losing a digit.

Why Strings

A JSON number is read into a 64-bit float by almost every parser, which keeps about 16 significant digits and cannot hold most decimal fractions exactly. Canton Coin carries ten decimal places, supplies run to billions of units and ratios to 18 fractional digits, so a float would silently change the figure. Every price, amount, volume, supply, FDV, rate and ratio in the API is therefore a decimal string:

JSON
{
  "price": "0.1584",
  "fdv": "715482911.36",
  "liquidity_to_fdv_ratio": "0.005758709342091255",
  "total_supply": "4517356203.5"
}

The strings are plain decimals: digits, at most one point, a leading minus only on fields that can be negative (changes), and never an exponent. Counts, durations, positions and ranks are ordinary JSON integers.

What a Float Does to a Figure

JavaScript
const exact = "123456789012345678901234567890.123456789";

new Intl.NumberFormat("en-US", { maximumFractionDigits: 9 }).format(exact);
// "123,456,789,012,345,678,901,234,567,890.123456789"   every digit kept

new Intl.NumberFormat("en-US").format(Number(exact));
// "123,456,789,012,345,680,000,000,000,000"             wrong from the 17th digit

0.1 + 0.2;           // 0.30000000000000004
Number("0.1584") * 3; // 0.47520000000000007

Parse with a Decimal Type

Keep values as strings until you need arithmetic, then use an exact decimal type. In JavaScript, decimal.js or big.js; in Python, the standard decimal module; in Java, BigDecimal; in Go, shopspring/decimal; in Rust, rust_decimal. Never call parseFloat or Number() on a figure.

JavaScript (decimal.js)
import Decimal from "decimal.js";

const { data } = await response.json();
const quote = data[0].quotes.USD;

const price = new Decimal(quote.price);            // 0.1584, exactly
const position = price.times("125000");            // value of 125,000 CC
const fdvCheck = price.times(asset.total_supply);  // compare with quote.fdv

position.toFixed(2);                               // "19800.00"
price.gt("0.15");                                  // true: compare decimals, not floats
Python (decimal)
from decimal import Decimal, ROUND_HALF_EVEN

quote = response.json()["data"][0]["quotes"]["USD"]

price = Decimal(quote["price"])               # Decimal('0.1584'), exactly
position = price * Decimal("125000")          # Decimal('19800.0000')
print(position.quantize(Decimal("0.01"), rounding=ROUND_HALF_EVEN))  # 19800.00

# Parse the whole body with Decimal so no float ever appears:
body = response.json(parse_float=Decimal)
Python
json.loads and requests' .json() only turn JSON numbers into floats. The API's figures are strings, so they arrive as str; wrap each in Decimal before arithmetic.

Display Without Losing Digits

Modern JavaScript engines format a decimal string directly with Intl.NumberFormat, without converting it to a number first. Round for display only, at the last step:

JavaScript
const usd = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  maximumFractionDigits: 4,
});
usd.format("0.1584");          // "$0.1584"

const compact = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 2 });
compact.format("715482911.36"); // "715.48M"

Percentages and Ratios

FieldUnit"1.5" meansDisplay
price_changes_pctPercentage points+1.5%Append %: 1.5 becomes 1.5%
price_change_24h_pctPercentage points+1.5%Append %
volume.change_24h_pctPercentage points+1.5%Append %
liquidity_to_fdv_ratioRaw ratio150%Multiply by 100: 0.025 becomes 2.5%
volume_24h_to_fdv_ratioRaw ratio150%Multiply by 100
spread_bpsBasis points0.015%Divide by 100 for %
JavaScript
// Percentage points: append the sign, do not multiply.
const change = new Decimal(quote.price_changes_pct["24h"]);   // "1.25"
const label = `${change.isNegative() ? "\u2212" : "+"}${change.abs().toFixed(2)}%`; // "+1.25%"

// Raw ratio: multiply by 100 for a percentage.
const ratio = new Decimal(listing.liquidity_to_fdv_ratio);     // "0.005758709342091255"
ratio.times(100).toFixed(2) + "%";                              // "0.58%"

Nulls Are Not Zeros

A figure the API does not know is null, and a measured zero is "0". Check for null before parsing, and show an absence (a dash or "n/a") rather than 0. market_cap, for example, is null for every asset. See Responses.

Python
fdv = quote["fdv"]
fdv_text = "n/a" if fdv is None else f"{Decimal(fdv):,.0f}"

Sums and Comparisons

  • Add decimals as decimals. Summing a column of floats drifts; summing Decimal values does not.
  • Compare with the decimal type's own comparison, not with strings: "10" < "9" is true as text.
  • Do not add figures across currencies or units. Market volumes in base or quote units differ per market; use the _usd fields to compare markets.
Esc
navigateopenEscclose