@pear-protocol/hyperliquid-sdk 0.1.4 → 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
|
@@ -1068,6 +1068,8 @@ interface TokenHistoricalPriceData {
|
|
|
1068
1068
|
candles: CandleData[];
|
|
1069
1069
|
oldestTime: number | null;
|
|
1070
1070
|
latestTime: number | null;
|
|
1071
|
+
requestedRanges: HistoricalRange[];
|
|
1072
|
+
noDataBefore: number | null;
|
|
1071
1073
|
}
|
|
1072
1074
|
interface HistoricalPriceDataState {
|
|
1073
1075
|
historicalPriceData: Record<string, TokenHistoricalPriceData>;
|
|
@@ -1075,6 +1077,7 @@ interface HistoricalPriceDataState {
|
|
|
1075
1077
|
addHistoricalPriceData: (symbol: string, interval: CandleInterval, candles: CandleData[], range: HistoricalRange) => void;
|
|
1076
1078
|
hasHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => boolean;
|
|
1077
1079
|
getHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => CandleData[];
|
|
1080
|
+
getEffectiveDataBoundary: (symbols: string[], interval: CandleInterval) => number | null;
|
|
1078
1081
|
setTokenLoading: (symbol: string, loading: boolean) => void;
|
|
1079
1082
|
isTokenLoading: (symbol: string) => boolean;
|
|
1080
1083
|
removeTokenPriceData: (symbol: string, interval: CandleInterval) => void;
|
|
@@ -1086,6 +1089,7 @@ interface UseHistoricalPriceDataReturn {
|
|
|
1086
1089
|
fetchHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval, callback?: (data: Record<string, CandleData[]>) => void) => Promise<Record<string, CandleData[]>>;
|
|
1087
1090
|
hasHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => boolean;
|
|
1088
1091
|
getHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => Record<string, CandleData[]>;
|
|
1092
|
+
getEffectiveDataBoundary: (interval: CandleInterval) => number | null;
|
|
1089
1093
|
getAllHistoricalPriceData(): Promise<Record<string, TokenHistoricalPriceData>>;
|
|
1090
1094
|
isLoading: (symbol?: string) => boolean;
|
|
1091
1095
|
clearCache: () => void;
|
|
@@ -1096,6 +1100,7 @@ interface UseBasketCandlesReturn {
|
|
|
1096
1100
|
fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
|
|
1097
1101
|
fetchPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval, symbol: string) => Promise<CandleData[]>;
|
|
1098
1102
|
fetchOverallPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
|
|
1103
|
+
getEffectiveDataBoundary: (interval: CandleInterval) => number | null;
|
|
1099
1104
|
isLoading: boolean;
|
|
1100
1105
|
addRealtimeListener: (cb: RealtimeBarsCallback) => string;
|
|
1101
1106
|
removeRealtimeListener: (id: string) => void;
|
package/dist/index.js
CHANGED
|
@@ -1819,6 +1819,22 @@ const getIntervalSeconds = (interval) => {
|
|
|
1819
1819
|
default: return 60;
|
|
1820
1820
|
}
|
|
1821
1821
|
};
|
|
1822
|
+
/**
|
|
1823
|
+
* Merges overlapping or adjacent ranges to prevent unbounded growth
|
|
1824
|
+
*/
|
|
1825
|
+
const mergeRanges = (ranges, newRange) => {
|
|
1826
|
+
const all = [...ranges, newRange].sort((a, b) => a.start - b.start);
|
|
1827
|
+
const merged = [];
|
|
1828
|
+
for (const r of all) {
|
|
1829
|
+
if (merged.length === 0 || r.start > merged[merged.length - 1].end) {
|
|
1830
|
+
merged.push({ start: r.start, end: r.end });
|
|
1831
|
+
}
|
|
1832
|
+
else {
|
|
1833
|
+
merged[merged.length - 1].end = Math.max(merged[merged.length - 1].end, r.end);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return merged;
|
|
1837
|
+
};
|
|
1822
1838
|
const useHistoricalPriceDataStore = create((set, get) => ({
|
|
1823
1839
|
historicalPriceData: {},
|
|
1824
1840
|
loadingTokens: new Set(),
|
|
@@ -1829,6 +1845,8 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
1829
1845
|
if (!existing) {
|
|
1830
1846
|
// Create new entry
|
|
1831
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;
|
|
1832
1850
|
return {
|
|
1833
1851
|
historicalPriceData: {
|
|
1834
1852
|
...state.historicalPriceData,
|
|
@@ -1837,7 +1855,9 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
1837
1855
|
interval,
|
|
1838
1856
|
candles: sortedCandles,
|
|
1839
1857
|
oldestTime: sortedCandles.length > 0 ? sortedCandles[0].t : null,
|
|
1840
|
-
latestTime: sortedCandles.length > 0 ? sortedCandles[sortedCandles.length - 1].t : null
|
|
1858
|
+
latestTime: sortedCandles.length > 0 ? sortedCandles[sortedCandles.length - 1].t : null,
|
|
1859
|
+
requestedRanges: [range],
|
|
1860
|
+
noDataBefore
|
|
1841
1861
|
}
|
|
1842
1862
|
}
|
|
1843
1863
|
};
|
|
@@ -1849,6 +1869,16 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
1849
1869
|
// Update time pointers
|
|
1850
1870
|
const oldestTime = mergedCandles.length > 0 ? mergedCandles[0].t : null;
|
|
1851
1871
|
const latestTime = mergedCandles.length > 0 ? mergedCandles[mergedCandles.length - 1].t : null;
|
|
1872
|
+
// Merge requested ranges
|
|
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
|
+
}
|
|
1852
1882
|
return {
|
|
1853
1883
|
historicalPriceData: {
|
|
1854
1884
|
...state.historicalPriceData,
|
|
@@ -1856,7 +1886,9 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
1856
1886
|
...existing,
|
|
1857
1887
|
candles: mergedCandles,
|
|
1858
1888
|
oldestTime,
|
|
1859
|
-
latestTime
|
|
1889
|
+
latestTime,
|
|
1890
|
+
requestedRanges: mergedRanges,
|
|
1891
|
+
noDataBefore
|
|
1860
1892
|
}
|
|
1861
1893
|
}
|
|
1862
1894
|
};
|
|
@@ -1866,8 +1898,24 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
1866
1898
|
const { historicalPriceData } = get();
|
|
1867
1899
|
const key = createKey(symbol, interval);
|
|
1868
1900
|
const tokenData = historicalPriceData[key];
|
|
1869
|
-
if (!tokenData
|
|
1901
|
+
if (!tokenData)
|
|
1902
|
+
return false;
|
|
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
|
|
1909
|
+
const requestedRanges = tokenData.requestedRanges || [];
|
|
1910
|
+
for (const range of requestedRanges) {
|
|
1911
|
+
if (range.start <= startTime && range.end >= endTime) {
|
|
1912
|
+
return true; // Already attempted this fetch
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
// Check actual data coverage
|
|
1916
|
+
if (tokenData.oldestTime === null || tokenData.latestTime === null) {
|
|
1870
1917
|
return false;
|
|
1918
|
+
}
|
|
1871
1919
|
const intervalMilisecond = getIntervalSeconds(interval) * 1000;
|
|
1872
1920
|
const hasStartCoverage = tokenData.oldestTime <= startTime;
|
|
1873
1921
|
const hasEndCoverage = tokenData.latestTime >= endTime ||
|
|
@@ -1882,6 +1930,27 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
1882
1930
|
return [];
|
|
1883
1931
|
return tokenData.candles.filter(candle => candle.t >= startTime && candle.t < endTime);
|
|
1884
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
|
+
},
|
|
1885
1954
|
setTokenLoading: (symbol, loading) => {
|
|
1886
1955
|
set(state => {
|
|
1887
1956
|
const newLoadingTokens = new Set(state.loadingTokens);
|
|
@@ -6012,7 +6081,7 @@ const useHistoricalPriceData = () => {
|
|
|
6012
6081
|
const shortTokens = useUserSelection$1((state) => state.shortTokens);
|
|
6013
6082
|
const candleInterval = useUserSelection$1((state) => state.candleInterval);
|
|
6014
6083
|
// Historical price data store
|
|
6015
|
-
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();
|
|
6016
6085
|
// Track previous tokens and interval to detect changes
|
|
6017
6086
|
const prevTokensRef = useRef(new Set());
|
|
6018
6087
|
const prevIntervalRef = useRef(null);
|
|
@@ -6065,6 +6134,11 @@ const useHistoricalPriceData = () => {
|
|
|
6065
6134
|
const getAllHistoricalPriceData = useCallback(async () => {
|
|
6066
6135
|
return useHistoricalPriceDataStore.getState().historicalPriceData;
|
|
6067
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]);
|
|
6068
6142
|
const fetchHistoricalPriceData = useCallback(async (startTime, endTime, interval, callback) => {
|
|
6069
6143
|
const allTokens = getAllTokens();
|
|
6070
6144
|
if (allTokens.length === 0) {
|
|
@@ -6122,6 +6196,7 @@ const useHistoricalPriceData = () => {
|
|
|
6122
6196
|
hasHistoricalPriceData,
|
|
6123
6197
|
getAllHistoricalPriceData,
|
|
6124
6198
|
getHistoricalPriceData,
|
|
6199
|
+
getEffectiveDataBoundary,
|
|
6125
6200
|
isLoading,
|
|
6126
6201
|
clearCache,
|
|
6127
6202
|
};
|
|
@@ -6318,7 +6393,7 @@ const useBasketCandles = () => {
|
|
|
6318
6393
|
const longTokens = useUserSelection$1((state) => state.longTokens);
|
|
6319
6394
|
const shortTokens = useUserSelection$1((state) => state.shortTokens);
|
|
6320
6395
|
const candleData = useHyperliquidData((s) => s.candleData);
|
|
6321
|
-
const { fetchHistoricalPriceData, isLoading: tokenLoading, getAllHistoricalPriceData } = useHistoricalPriceData();
|
|
6396
|
+
const { fetchHistoricalPriceData, isLoading: tokenLoading, getAllHistoricalPriceData, getEffectiveDataBoundary } = useHistoricalPriceData();
|
|
6322
6397
|
const fetchBasketCandles = useCallback(async (startTime, endTime, interval) => {
|
|
6323
6398
|
const tokenCandles = await fetchHistoricalPriceData(startTime, endTime, interval);
|
|
6324
6399
|
const basket = computeBasketCandles(longTokens, shortTokens, tokenCandles);
|
|
@@ -6518,6 +6593,7 @@ const useBasketCandles = () => {
|
|
|
6518
6593
|
fetchBasketCandles,
|
|
6519
6594
|
fetchPerformanceCandles,
|
|
6520
6595
|
fetchOverallPerformanceCandles,
|
|
6596
|
+
getEffectiveDataBoundary,
|
|
6521
6597
|
isLoading,
|
|
6522
6598
|
addRealtimeListener,
|
|
6523
6599
|
removeRealtimeListener,
|
|
@@ -9,6 +9,8 @@ interface TokenHistoricalPriceData {
|
|
|
9
9
|
candles: CandleData[];
|
|
10
10
|
oldestTime: number | null;
|
|
11
11
|
latestTime: number | null;
|
|
12
|
+
requestedRanges: HistoricalRange[];
|
|
13
|
+
noDataBefore: number | null;
|
|
12
14
|
}
|
|
13
15
|
interface HistoricalPriceDataState {
|
|
14
16
|
historicalPriceData: Record<string, TokenHistoricalPriceData>;
|
|
@@ -16,6 +18,7 @@ interface HistoricalPriceDataState {
|
|
|
16
18
|
addHistoricalPriceData: (symbol: string, interval: CandleInterval, candles: CandleData[], range: HistoricalRange) => void;
|
|
17
19
|
hasHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => boolean;
|
|
18
20
|
getHistoricalPriceData: (symbol: string, interval: CandleInterval, startTime: number, endTime: number) => CandleData[];
|
|
21
|
+
getEffectiveDataBoundary: (symbols: string[], interval: CandleInterval) => number | null;
|
|
19
22
|
setTokenLoading: (symbol: string, loading: boolean) => void;
|
|
20
23
|
isTokenLoading: (symbol: string) => boolean;
|
|
21
24
|
removeTokenPriceData: (symbol: string, interval: CandleInterval) => void;
|