Forráskód Böngészése

feat: make price formatting feed-exponent aware

Filip Hallqvist 1 hónapja
szülő
commit
4c1f7a2ead

+ 45 - 10
apps/insights/src/components/LivePrices/index.tsx

@@ -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} />
+    );
   }
 };
 
@@ -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} />
@@ -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>
   );
 
@@ -114,6 +130,7 @@ const LiveAggregateConfidence = ({
           ? current.confidence
           : current.previousConfidence)
       }
+      exponent={current?.exponent}
     />
   );
 };
@@ -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]);
 };

+ 14 - 1
apps/insights/src/components/PriceFeed/Chart/chart.tsx

@@ -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
@@ -79,6 +78,9 @@ 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, {
+    subscriptZeros: false,
+  });
 
   const didResetVisibleRange = useRef(false);
   const didLoadInitialData = useRef(false);
@@ -370,6 +372,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 };
 };
 

+ 1 - 0
apps/insights/src/hooks/use-live-price-data.tsx

@@ -72,6 +72,7 @@ export const useLivePriceComponent = (
     prev: prev?.priceComponents.find((component) =>
       component.publisher.equals(publisherKey),
     ),
+    exponent: current?.exponent,
   };
 };
 

+ 34 - 6
apps/insights/src/hooks/use-price-formatter.ts

@@ -1,17 +1,45 @@
 import { useCallback, useMemo } from "react";
 import { useNumberFormatter } from "react-aria";
 
-export const usePriceFormatter = () => {
+export const usePriceFormatter = (
+  exponent?: number,
+  { subscriptZeros = true }: { subscriptZeros?: boolean } = {},
+) => {
+  // 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) {
+        const formatted = exponentBasedFormatter.format(n);
+        return subscriptZeros ? formatToSubscriptNumber(formatted) : formatted;
+      }
+      // Otherwise, fall back to the old behavior
+      if (n >= 1000) {
+        const formatted = bigNumberFormatter.format(n);
+        return subscriptZeros ? formatToSubscriptNumber(formatted) : formatted;
+      }
+      const formatted = smallNumberFormatter.format(n);
+      return subscriptZeros ? formatToSubscriptNumber(formatted) : formatted;
+    },
+    [
+      bigNumberFormatter,
+      smallNumberFormatter,
+      exponentBasedFormatter,
+      decimals,
+      subscriptZeros,
+    ],
   );
   return useMemo(() => ({ format }), [format]);
 };