@pear-protocol/hyperliquid-sdk 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ export interface UseBasketCandlesReturn {
3
3
  fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
4
4
  fetchPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval, symbol: string) => Promise<CandleData[]>;
5
5
  fetchOverallPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
6
+ getEffectiveDataBoundary: (interval: CandleInterval) => number | null;
6
7
  isLoading: boolean;
7
8
  addRealtimeListener: (cb: RealtimeBarsCallback) => string;
8
9
  removeRealtimeListener: (id: string) => void;
@@ -4,6 +4,7 @@ export interface UseHistoricalPriceDataReturn {
4
4
  fetchHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval, callback?: (data: Record<string, CandleData[]>) => void) => Promise<Record<string, CandleData[]>>;
5
5
  hasHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => boolean;
6
6
  getHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => Record<string, CandleData[]>;
7
+ getEffectiveDataBoundary: (interval: CandleInterval) => number | null;
7
8
  getAllHistoricalPriceData(): Promise<Record<string, TokenHistoricalPriceData>>;
8
9
  isLoading: (symbol?: string) => boolean;
9
10
  clearCache: () => void;
package/dist/index.d.ts CHANGED
@@ -1069,6 +1069,7 @@ interface TokenHistoricalPriceData {
1069
1069
  oldestTime: number | null;
1070
1070
  latestTime: number | null;
1071
1071
  requestedRanges: HistoricalRange[];
1072
+ noDataBefore: number | null;
1072
1073
  }
1073
1074
  interface HistoricalPriceDataState {
1074
1075
  historicalPriceData: Record<string, TokenHistoricalPriceData>;
@@ -1076,6 +1077,7 @@ interface HistoricalPriceDataState {
1076
1077
  addHistoricalPriceData: (symbol: string, interval: CandleInterval, candles: CandleData[], range: HistoricalRange) => void;
1077
1078
  hasHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => boolean;
1078
1079
  getHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => CandleData[];
1080
+ getEffectiveDataBoundary: (symbols: string[], interval: CandleInterval) => number | null;
1079
1081
  setTokenLoading: (symbol: string, loading: boolean) => void;
1080
1082
  isTokenLoading: (symbol: string) => boolean;
1081
1083
  removeTokenPriceData: (symbol: string, interval: CandleInterval) => void;
@@ -1087,6 +1089,7 @@ interface UseHistoricalPriceDataReturn {
1087
1089
  fetchHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval, callback?: (data: Record<string, CandleData[]>) => void) => Promise<Record<string, CandleData[]>>;
1088
1090
  hasHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => boolean;
1089
1091
  getHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => Record<string, CandleData[]>;
1092
+ getEffectiveDataBoundary: (interval: CandleInterval) => number | null;
1090
1093
  getAllHistoricalPriceData(): Promise<Record<string, TokenHistoricalPriceData>>;
1091
1094
  isLoading: (symbol?: string) => boolean;
1092
1095
  clearCache: () => void;
@@ -1097,6 +1100,7 @@ interface UseBasketCandlesReturn {
1097
1100
  fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
1098
1101
  fetchPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval, symbol: string) => Promise<CandleData[]>;
1099
1102
  fetchOverallPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
1103
+ getEffectiveDataBoundary: (interval: CandleInterval) => number | null;
1100
1104
  isLoading: boolean;
1101
1105
  addRealtimeListener: (cb: RealtimeBarsCallback) => string;
1102
1106
  removeRealtimeListener: (id: string) => void;
package/dist/index.js CHANGED
@@ -1845,6 +1845,8 @@ const useHistoricalPriceDataStore = create((set, get) => ({
1845
1845
  if (!existing) {
1846
1846
  // Create new entry
1847
1847
  const sortedCandles = [...candles].sort((a, b) => a.t - b.t);
1848
+ // If first fetch returns empty, mark that there's no data before the requested end time
1849
+ const noDataBefore = sortedCandles.length === 0 ? range.end : null;
1848
1850
  return {
1849
1851
  historicalPriceData: {
1850
1852
  ...state.historicalPriceData,
@@ -1854,7 +1856,8 @@ const useHistoricalPriceDataStore = create((set, get) => ({
1854
1856
  candles: sortedCandles,
1855
1857
  oldestTime: sortedCandles.length > 0 ? sortedCandles[0].t : null,
1856
1858
  latestTime: sortedCandles.length > 0 ? sortedCandles[sortedCandles.length - 1].t : null,
1857
- requestedRanges: [range]
1859
+ requestedRanges: [range],
1860
+ noDataBefore
1858
1861
  }
1859
1862
  }
1860
1863
  };
@@ -1868,6 +1871,14 @@ const useHistoricalPriceDataStore = create((set, get) => ({
1868
1871
  const latestTime = mergedCandles.length > 0 ? mergedCandles[mergedCandles.length - 1].t : null;
1869
1872
  // Merge requested ranges
1870
1873
  const mergedRanges = mergeRanges(existing.requestedRanges || [], range);
1874
+ // Update noDataBefore boundary:
1875
+ // If we fetched a range older than our current oldest data and got no new candles,
1876
+ // it means there's no data before our current oldest time
1877
+ let noDataBefore = existing.noDataBefore;
1878
+ if (candles.length === 0 && existing.oldestTime !== null && range.end <= existing.oldestTime) {
1879
+ // We tried to fetch older data and got nothing - set boundary to our oldest known data
1880
+ noDataBefore = existing.oldestTime;
1881
+ }
1871
1882
  return {
1872
1883
  historicalPriceData: {
1873
1884
  ...state.historicalPriceData,
@@ -1876,7 +1887,8 @@ const useHistoricalPriceDataStore = create((set, get) => ({
1876
1887
  candles: mergedCandles,
1877
1888
  oldestTime,
1878
1889
  latestTime,
1879
- requestedRanges: mergedRanges
1890
+ requestedRanges: mergedRanges,
1891
+ noDataBefore
1880
1892
  }
1881
1893
  }
1882
1894
  };
@@ -1888,16 +1900,22 @@ const useHistoricalPriceDataStore = create((set, get) => ({
1888
1900
  const tokenData = historicalPriceData[key];
1889
1901
  if (!tokenData)
1890
1902
  return false;
1891
- // Check if we've already attempted to fetch this range (prevents infinite loops for tokens with no data)
1903
+ // Check if we've hit the "no data before" boundary
1904
+ // If the requested range ends before or at the boundary, we know there's no data
1905
+ if (tokenData.noDataBefore !== null && endTime <= tokenData.noDataBefore) {
1906
+ return true; // No point fetching - we know there's no data before this point
1907
+ }
1908
+ // Check if we've already attempted to fetch this range
1892
1909
  const requestedRanges = tokenData.requestedRanges || [];
1893
1910
  for (const range of requestedRanges) {
1894
1911
  if (range.start <= startTime && range.end >= endTime) {
1895
1912
  return true; // Already attempted this fetch
1896
1913
  }
1897
1914
  }
1898
- // Fallback: check actual data coverage
1899
- if (tokenData.oldestTime === null || tokenData.latestTime === null)
1915
+ // Check actual data coverage
1916
+ if (tokenData.oldestTime === null || tokenData.latestTime === null) {
1900
1917
  return false;
1918
+ }
1901
1919
  const intervalMilisecond = getIntervalSeconds(interval) * 1000;
1902
1920
  const hasStartCoverage = tokenData.oldestTime <= startTime;
1903
1921
  const hasEndCoverage = tokenData.latestTime >= endTime ||
@@ -1912,6 +1930,27 @@ const useHistoricalPriceDataStore = create((set, get) => ({
1912
1930
  return [];
1913
1931
  return tokenData.candles.filter(candle => candle.t >= startTime && candle.t < endTime);
1914
1932
  },
1933
+ getEffectiveDataBoundary: (symbols, interval) => {
1934
+ var _a;
1935
+ const { historicalPriceData } = get();
1936
+ if (symbols.length === 0)
1937
+ return null;
1938
+ let maxBoundary = null;
1939
+ for (const symbol of symbols) {
1940
+ const key = createKey(symbol, interval);
1941
+ const tokenData = historicalPriceData[key];
1942
+ if (!tokenData)
1943
+ continue;
1944
+ // Use noDataBefore if set, otherwise use oldestTime
1945
+ const boundary = (_a = tokenData.noDataBefore) !== null && _a !== void 0 ? _a : tokenData.oldestTime;
1946
+ if (boundary !== null) {
1947
+ if (maxBoundary === null || boundary > maxBoundary) {
1948
+ maxBoundary = boundary;
1949
+ }
1950
+ }
1951
+ }
1952
+ return maxBoundary;
1953
+ },
1915
1954
  setTokenLoading: (symbol, loading) => {
1916
1955
  set(state => {
1917
1956
  const newLoadingTokens = new Set(state.loadingTokens);
@@ -6042,7 +6081,7 @@ const useHistoricalPriceData = () => {
6042
6081
  const shortTokens = useUserSelection$1((state) => state.shortTokens);
6043
6082
  const candleInterval = useUserSelection$1((state) => state.candleInterval);
6044
6083
  // Historical price data store
6045
- const { addHistoricalPriceData, hasHistoricalPriceData: storeHasData, getHistoricalPriceData: storeGetData, setTokenLoading, isTokenLoading, removeTokenPriceData, clearData, } = useHistoricalPriceDataStore();
6084
+ const { addHistoricalPriceData, hasHistoricalPriceData: storeHasData, getHistoricalPriceData: storeGetData, getEffectiveDataBoundary: storeGetBoundary, setTokenLoading, isTokenLoading, removeTokenPriceData, clearData, } = useHistoricalPriceDataStore();
6046
6085
  // Track previous tokens and interval to detect changes
6047
6086
  const prevTokensRef = useRef(new Set());
6048
6087
  const prevIntervalRef = useRef(null);
@@ -6095,6 +6134,11 @@ const useHistoricalPriceData = () => {
6095
6134
  const getAllHistoricalPriceData = useCallback(async () => {
6096
6135
  return useHistoricalPriceDataStore.getState().historicalPriceData;
6097
6136
  }, []);
6137
+ const getEffectiveDataBoundary = useCallback((interval) => {
6138
+ const allTokens = getAllTokens();
6139
+ const symbols = allTokens.map(t => t.symbol);
6140
+ return storeGetBoundary(symbols, interval);
6141
+ }, [getAllTokens, storeGetBoundary]);
6098
6142
  const fetchHistoricalPriceData = useCallback(async (startTime, endTime, interval, callback) => {
6099
6143
  const allTokens = getAllTokens();
6100
6144
  if (allTokens.length === 0) {
@@ -6152,6 +6196,7 @@ const useHistoricalPriceData = () => {
6152
6196
  hasHistoricalPriceData,
6153
6197
  getAllHistoricalPriceData,
6154
6198
  getHistoricalPriceData,
6199
+ getEffectiveDataBoundary,
6155
6200
  isLoading,
6156
6201
  clearCache,
6157
6202
  };
@@ -6348,7 +6393,7 @@ const useBasketCandles = () => {
6348
6393
  const longTokens = useUserSelection$1((state) => state.longTokens);
6349
6394
  const shortTokens = useUserSelection$1((state) => state.shortTokens);
6350
6395
  const candleData = useHyperliquidData((s) => s.candleData);
6351
- const { fetchHistoricalPriceData, isLoading: tokenLoading, getAllHistoricalPriceData } = useHistoricalPriceData();
6396
+ const { fetchHistoricalPriceData, isLoading: tokenLoading, getAllHistoricalPriceData, getEffectiveDataBoundary } = useHistoricalPriceData();
6352
6397
  const fetchBasketCandles = useCallback(async (startTime, endTime, interval) => {
6353
6398
  const tokenCandles = await fetchHistoricalPriceData(startTime, endTime, interval);
6354
6399
  const basket = computeBasketCandles(longTokens, shortTokens, tokenCandles);
@@ -6548,6 +6593,7 @@ const useBasketCandles = () => {
6548
6593
  fetchBasketCandles,
6549
6594
  fetchPerformanceCandles,
6550
6595
  fetchOverallPerformanceCandles,
6596
+ getEffectiveDataBoundary,
6551
6597
  isLoading,
6552
6598
  addRealtimeListener,
6553
6599
  removeRealtimeListener,
@@ -10,6 +10,7 @@ interface TokenHistoricalPriceData {
10
10
  oldestTime: number | null;
11
11
  latestTime: number | null;
12
12
  requestedRanges: HistoricalRange[];
13
+ noDataBefore: number | null;
13
14
  }
14
15
  interface HistoricalPriceDataState {
15
16
  historicalPriceData: Record<string, TokenHistoricalPriceData>;
@@ -17,6 +18,7 @@ interface HistoricalPriceDataState {
17
18
  addHistoricalPriceData: (symbol: string, interval: CandleInterval, candles: CandleData[], range: HistoricalRange) => void;
18
19
  hasHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => boolean;
19
20
  getHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => CandleData[];
21
+ getEffectiveDataBoundary: (symbols: string[], interval: CandleInterval) => number | null;
20
22
  setTokenLoading: (symbol: string, loading: boolean) => void;
21
23
  isTokenLoading: (symbol: string) => boolean;
22
24
  removeTokenPriceData: (symbol: string, interval: CandleInterval) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/hyperliquid-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "React SDK for Pear Protocol Hyperliquid API integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",