Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 45 additions & 10 deletions apps/insights/src/components/LivePrices/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,17 @@ const LiveAggregatePrice = ({
if (current === undefined) {
return <Price />;
} else if (current.status === PriceStatus.Trading) {
return <Price current={current.price} prev={prev?.price} />;
return (
<Price
current={current.price}
prev={prev?.price}
exponent={current.exponent}
/>
);
} else {
return <Price current={current.previousPrice} />;
return (
<Price current={current.previousPrice} exponent={current.exponent} />
);
}
};

Expand All @@ -58,20 +66,28 @@ const LiveComponentPrice = ({
publisherKey: string;
cluster: Cluster;
}) => {
const { prev, current } = useLivePriceComponent(
const { prev, current, exponent } = useLivePriceComponent(
cluster,
feedKey,
publisherKey,
);
return <Price current={current?.latest.price} prev={prev?.latest.price} />;
return (
<Price
current={current?.latest.price}
prev={prev?.latest.price}
exponent={exponent}
/>
);
};

const Price = ({
prev,
current,
exponent,
}: {
prev?: number | undefined;
current?: number | undefined;
exponent?: number | undefined;
}) =>
current === undefined ? (
<Skeleton width={SKELETON_WIDTH} />
Expand All @@ -80,7 +96,7 @@ const Price = ({
className={styles.price}
data-direction={prev ? getChangeDirection(prev, current) : "flat"}
>
<FormattedPriceValue n={current} />
<FormattedPriceValue n={current} exponent={exponent} />
</span>
);

Expand Down Expand Up @@ -114,6 +130,7 @@ const LiveAggregateConfidence = ({
? current.confidence
: current.previousConfidence)
}
exponent={current?.exponent}
/>
);
};
Expand All @@ -128,24 +145,42 @@ const LiveComponentConfidence = ({
cluster: Cluster;
}) => {
const { current } = useLivePriceComponent(cluster, feedKey, publisherKey);
return <Confidence confidence={current?.latest.confidence} />;
const { current: priceData } = useLivePriceData(cluster, feedKey);
return (
<Confidence
confidence={current?.latest.confidence}
exponent={priceData?.exponent}
/>
);
};

const Confidence = ({ confidence }: { confidence?: number | undefined }) => (
const Confidence = ({
confidence,
exponent,
}: {
confidence?: number | undefined;
exponent?: number | undefined;
}) => (
<span className={styles.confidence}>
<PlusMinus className={styles.plusMinus} />
{confidence === undefined ? (
<Skeleton width={SKELETON_WIDTH} />
) : (
<span>
<FormattedPriceValue n={confidence} />
<FormattedPriceValue n={confidence} exponent={exponent} />
</span>
)}
</span>
);

const FormattedPriceValue = ({ n }: { n: number }) => {
const formatter = usePriceFormatter();
const FormattedPriceValue = ({
n,
exponent,
}: {
n: number;
exponent?: number | undefined;
}) => {
const formatter = usePriceFormatter(exponent);

return useMemo(() => formatter.format(n), [n, formatter]);
};
Expand Down
13 changes: 12 additions & 1 deletion apps/insights/src/components/PriceFeed/Chart/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ const useChartElem = (symbol: string, feedId: string) => {
const chartContainerRef = useRef<HTMLDivElement | null>(null);
const chartRef = useRef<ChartRefContents | undefined>(undefined);
const isBackfilling = useRef(false);
const priceFormatter = usePriceFormatter();
const abortControllerRef = useRef<AbortController | undefined>(undefined);
// Lightweight charts has [a
// bug](https://github.com/tradingview/lightweight-charts/issues/1649) where
Expand All @@ -79,6 +78,7 @@ const useChartElem = (symbol: string, feedId: string) => {
const whitespaceData = useRef<Set<WhitespaceData>>(new Set());

const { current: livePriceData } = useLivePriceData(Cluster.Pythnet, feedId);
const priceFormatter = usePriceFormatter(livePriceData?.exponent);

const didResetVisibleRange = useRef(false);
const didLoadInitialData = useRef(false);
Expand Down Expand Up @@ -370,6 +370,17 @@ const useChartElem = (symbol: string, feedId: string) => {
});
}, [quickSelectWindow, resolution, fetchHistoricalData]);

// Update the chart's price formatter when the exponent becomes available
useEffect(() => {
if (chartRef.current && livePriceData?.exponent !== undefined) {
chartRef.current.chart.applyOptions({
localization: {
priceFormatter: priceFormatter.format,
},
});
}
}, [livePriceData?.exponent, priceFormatter]);

return { chartRef, chartContainerRef };
};

Expand Down
1 change: 1 addition & 0 deletions apps/insights/src/hooks/use-live-price-data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const useLivePriceComponent = (
prev: prev?.priceComponents.find((component) =>
component.publisher.equals(publisherKey),
),
exponent: current?.exponent,
};
};

Expand Down
56 changes: 27 additions & 29 deletions apps/insights/src/hooks/use-price-formatter.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
import { useCallback, useMemo } from "react";
import { useNumberFormatter } from "react-aria";

export const usePriceFormatter = () => {
export const usePriceFormatter = (exponent?: number) => {
// Calculate the number of decimal places based on the exponent
// The exponent represents the power of 10, so -8 means 8 decimal places
const decimals = exponent === undefined ? undefined : Math.abs(exponent);

const bigNumberFormatter = useNumberFormatter({ maximumFractionDigits: 2 });
const smallNumberFormatter = useNumberFormatter({
maximumSignificantDigits: 6,
});
const exponentBasedFormatter = useNumberFormatter({
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
});

const format = useCallback(
(n: number) =>
n >= 1000
? bigNumberFormatter.format(n)
: formatToSubscriptNumber(smallNumberFormatter.format(n)),
[bigNumberFormatter, smallNumberFormatter],
(n: number) => {
// If we have an exponent, use exponent-based formatting
if (decimals !== undefined) {
return exponentBasedFormatter.format(n);
}
// Otherwise, fall back to the old behavior
if (n >= 1000) {
return bigNumberFormatter.format(n);
}
return smallNumberFormatter.format(n);
},
[
bigNumberFormatter,
smallNumberFormatter,
exponentBasedFormatter,
decimals,
],
);
return useMemo(() => ({ format }), [format]);
};

const formatToSubscriptNumber = (numString: string) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should consider keeping this formatter, for some cryptos the pricing & CI are very very small fractions and you can have very long streams of zeroes which are very hard to read. This formatter resolves that issue quite nicely and can be applied on top of the exponentBasedFormatter.

screenshot-2025-10-17-095310

const parts = numString.split(".");

const [integerPart, decimalPart] = parts;
if (integerPart && decimalPart) {
const zerosCount =
decimalPart.length - decimalPart.replace(/^0+/, "").length;

return zerosCount < 5
? numString
: integerPart +
"." +
"0" +
(zerosCount > 9
? String.fromCodePoint(0x20_80 + Math.floor(zerosCount / 10))
: "") +
String.fromCodePoint(0x20_80 + (zerosCount % 10)) +
decimalPart.replace(/^0+/, "");
} else {
return numString;
}
};
Loading