diff --git a/apps/insights/src/components/PriceFeed/Chart/chart.tsx b/apps/insights/src/components/PriceFeed/Chart/chart.tsx index 7a4690d369..a6e4806c1d 100644 --- a/apps/insights/src/components/PriceFeed/Chart/chart.tsx +++ b/apps/insights/src/components/PriceFeed/Chart/chart.tsx @@ -160,12 +160,17 @@ const useChartElem = (symbol: string, feedId: string) => { return; } isBackfilling.current = true; - const url = new URL("/historical-prices", globalThis.location.origin); + + const url = new URL( + "https://benchmarks.pyth.network/v1/shims/tradingview/history", + ); url.searchParams.set("symbol", symbol); url.searchParams.set("from", from.toString()); url.searchParams.set("to", to.toString()); - url.searchParams.set("resolution", resolution); - url.searchParams.set("cluster", "pythnet"); + url.searchParams.set( + "resolution", + mapResolutionToBenchmarksApi(resolution), + ); abortControllerRef.current = new AbortController(); abortControllerRef.current.signal.addEventListener("abort", () => { @@ -179,7 +184,7 @@ const useChartElem = (symbol: string, feedId: string) => { return; } - const data = historicalDataSchema.parse(jsonData); + const data = benchmarksApiResponseSchema.parse(jsonData); // Get the current historical price data // Note that .data() returns (WhitespaceData | LineData)[], hence the type cast. @@ -196,16 +201,17 @@ const useChartElem = (symbol: string, feedId: string) => { value: d.price, }), })); + // we have no confidence data, set confidence bands to match the price const newHistoricalConfidenceHighData = data.map((d) => ({ time: d.time, ...(d.status === PriceStatus.Trading && { - value: d.price + d.confidence, + value: d.price, }), })); const newHistoricalConfidenceLowData = data.map((d) => ({ time: d.time, ...(d.status === PriceStatus.Trading && { - value: d.price - d.confidence, + value: d.price, }), })); @@ -394,21 +400,24 @@ type ChartRefContents = { price: ISeriesApi<"Line">; }; -const historicalDataSchema = z.array( - z - .strictObject({ - timestamp: z.number(), - price: z.number(), - confidence: z.number(), - status: z.nativeEnum(PriceStatus), - }) - .transform((d) => ({ - time: Number(d.timestamp) as UTCTimestamp, - price: d.price, - confidence: d.confidence, - status: d.status, +const benchmarksApiResponseSchema = z + .object({ + s: z.string(), + t: z.array(z.number()), + o: z.array(z.number()), + h: z.array(z.number()), + l: z.array(z.number()), + c: z.array(z.number()), + v: z.array(z.number()), + }) + .transform((data) => + data.t.map((timestamp, i) => ({ + time: timestamp as UTCTimestamp, + price: data.c[i], // Use close price for now + confidence: 0, // No confidence data from benchmarks API + status: PriceStatus.Trading, })), -); + ); const priceFormat = { type: "price", precision: 5, @@ -421,6 +430,30 @@ const confidenceConfig = { lineWidth: 1, } as const; +/** + * Map our internal resolution format to the benchmarks API resolution format + */ +function mapResolutionToBenchmarksApi(resolution: string): string { + switch (resolution) { + case "1s": + case "1m": { + return "1"; + } + case "5m": { + return "5"; + } + case "1H": { + return "60"; + } + case "1D": { + return "1D"; + } + default: { + throw new Error(`Unknown resolution: ${resolution}`); + } + } +} + const useChartResize = ( chartContainerRef: RefObject, chartRef: RefObject,