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.
Exercise the unit boundary in a working interface
The independent Volume Unit Workbook makes the input-side problem visible. It is a separate teaching model, not this comparison function and not the proprietary Planner engine.
Try three observations:
- Load Base quantity: 1,000 declared units at 40 USD per unit produce an approximate 40,000 USD proxy. Load Quote amount: a declared 40,000 USD amount stays 40,000; multiplying it by price again would change the dimension.
- Load Contracts, Tick activity or Unit unverified. An unknown contract specification remains unresolved, tick counts remain nonmonetary activity, and unverified units produce no estimate. No multiplier or monetary unit is guessed.
- Load Another currency. The example retains 40,000 JPY and rejects comparison with the declared USD threshold. A matching number is not matching purchasing power. Then clear a quantity after calculating: the prior result disappears. An observed zero and an empty input remain separate states.
The repository source and tests include 20 bounded model tests for this worksheet. Eleven separate Chrome checks covered its six cases, zero, blank quantity, threshold equality, absent threshold and reset. These results do not validate real feeds, trusted metadata, a calendar policy, production runtime or the original comparison function in this article. The inputs are invented and remain in browser memory.
For the author-maintained reading context, the turnover and volume-unit guide explains why a declared quantity needs its instrument convention; the global stock currency and session guide explains why a basket also needs its currency and clock context. A reviewed source adapter must establish those facts before populating the comparison contract above.
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.
Four places to inspect a unit boundary
These author-maintained reading resources help frame a review question. They do not validate the JavaScript contract or provide a personal recommendation.
- ATR-percent screening — keep a percentage distinct from a raw price distance.
- Risk/reward after fees — retain the declared cost assumptions alongside a comparison.
- BMI calculator — inspect the height and weight units before interpreting a result.
- Growth-percentile calculator — read the age and measurement context on the destination page.
Top comments (0)