A dashboard can display two valid numbers and still make an invalid comparison.
Consider three synthetic observations: 500 shares, 500 futures contracts and 500 tick events. They all fit in a JavaScript number. They do not measure the same thing.
The engineering problem starts when an adapter discards metadata and hands the UI only a numeric value. A formatter adds a compact suffix, a table sorts descending, and the screen makes unlike measurements look equivalent.
This article introduces a small comparison contract. It is a standalone educational JavaScript example, not the implementation of a TradingView script or a live market feed.
A metric is more than its number
Carry the measurement definition through the ingestion, validation and rendering layers:
| Field | What the consumer needs to know |
|---|---|
| metric | What was measured: turnover, volume, count or something else |
| unit | Shares, contracts, quote currency, tick events, etc. |
| currency | The denomination, or an explicit non-applicable marker |
| interval | The aggregation window |
| session | The session coverage used by that observation |
| basisId | A trusted identifier for the measurement methodology |
| freshness | Whether a separate freshness policy has established currentness |
The basis identifier matters. Two sources can both say “contracts” while referring to different contract specifications. Two providers can use the same display label for different aggregation methods. A label is necessary metadata; it is not evidence of equivalent semantics.
Your adapter should assign the basis from a reviewed source contract. Do not let arbitrary user input or an untrusted payload declare two methods equivalent.
Return a state before returning a difference
The UI needs to distinguish missing evidence from a valid difference. This function returns one of three states:
- unavailable: a number, metadata or freshness evidence is missing or invalid;
- incomparable: both records are populated, but their declared contracts differ;
- comparable: the declared contract matches and a finite difference can be calculated.
function compareMetric(a, b) {
const keys = [
"metric", "unit", "currency", "interval", "session", "basisId"
];
for (const x of [a, b]) {
if (!x || typeof x.value !== "number" ||
!Number.isFinite(x.value)) {
return { state: "unavailable", reason: "invalid-number" };
}
if (keys.some(k => typeof x[k] !== "string" || !x[k].trim())) {
return { state: "unavailable", reason: "missing-metadata" };
}
if (x.freshness !== "fresh") {
return { state: "unavailable", reason: "freshness-not-established" };
}
}
const different = keys.filter(k => a[k] !== b[k]);
if (different.length) {
return { state: "incomparable", fields: different };
}
const delta = a.value - b.value;
return Number.isFinite(delta)
? { state: "comparable", delta }
: { state: "unavailable", reason: "numeric-overflow" };
}
A real adapter must also enforce allowed metric/unit combinations and verify that the declared basis is trustworthy. This example deliberately does not fetch data, infer units or convert currencies.
Try a synthetic fixture
const baseline = {
value: 100,
metric: "turnover",
unit: "quote-currency",
currency: "USD",
interval: "1h",
session: "regular",
basisId: "synthetic:quote-turnover-v1",
freshness: "fresh"
};
compareMetric({ ...baseline, value: 120 }, baseline);
// { state: "comparable", delta: 20 }
compareMetric({ ...baseline, currency: "EUR" }, baseline);
// { state: "incomparable", fields: ["currency"] }
compareMetric({ ...baseline, freshness: "unknown" }, baseline);
// { state: "unavailable", reason: "freshness-not-established" }
The freshness flag is an input to this contract, not a freshness detector. Production code still needs an explicit timestamp, clock-skew tolerance, calendar/session policy and age threshold. Never substitute the browser's latest refresh time for the source observation time.
The isolated example passed 11 synthetic checks: a matching basis, different currency, different unit, different methodology, different interval, different session, unknown freshness, missing metadata, null value, non-finite value and subtraction overflow. Those checks do not validate a vendor feed or prove a production dashboard is correct.
Rendering rules that preserve meaning
When the state is unavailable, show a text reason rather than a fabricated zero. When it is incomparable, retain the original values and explain the differing fields. Do not calculate a ranking from the rejected comparison.
Keep the raw value and its provenance available for inspection. Format a copy for display; rounding should not silently rewrite the measurement used by the model. A cached record should retain its original source metadata and observation time.
A compatible contract establishes only this narrow arithmetic comparison. It does not establish liquidity, execution quality, investment suitability or predictive value.
Apply this to a market-review interface
Commodity feed selection provides a practical example: cash quotes, continuous futures, dated contracts and ETFs can need different source contracts. Our commodity screening guide explains the instrument and volume-unit checks from the user side. Our relative volume versus liquidity guide covers another common interpretation error.
Disclosure: I am the founder of AGProLabs. Crypto Setup Planner is our TradingView candidate-screening product; this article's JavaScript is a separate educational example, not its source code. The article and example were prepared with AI assistance. Trading involves risk; analytical outputs do not guarantee outcomes.
Top comments (0)