@pear-protocol/hyperliquid-sdk 0.0.22 → 0.0.24
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.
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useBasketCandles.d.ts +4 -2
- package/dist/hooks/useHistoricalPriceData.d.ts +3 -0
- package/dist/hooks/usePerformanceOverlays.d.ts +14 -0
- package/dist/index.d.ts +42 -38
- package/dist/index.js +226 -313
- package/dist/types.d.ts +6 -21
- package/dist/utils/basket-calculator.d.ts +2 -2
- package/dist/utils/position-processor.d.ts +2 -22
- package/package.json +1 -1
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CandleData, CandleInterval } from '../types';
|
|
2
2
|
export interface UseBasketCandlesReturn {
|
|
3
|
-
fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<
|
|
3
|
+
fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
|
|
4
|
+
fetchPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval, symbol: string) => Promise<CandleData[]>;
|
|
5
|
+
fetchOverallPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
|
|
4
6
|
isLoading: boolean;
|
|
5
7
|
addRealtimeListener: (cb: RealtimeBarsCallback) => string;
|
|
6
8
|
removeRealtimeListener: (id: string) => void;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { TokenHistoricalPriceData } from '../store/historicalPriceDataStore';
|
|
1
2
|
import type { CandleData, CandleInterval } from '../types';
|
|
2
3
|
export interface UseHistoricalPriceDataReturn {
|
|
3
4
|
fetchHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval, callback?: (data: Record<string, CandleData[]>) => void) => Promise<Record<string, CandleData[]>>;
|
|
4
5
|
hasHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => boolean;
|
|
5
6
|
getHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => Record<string, CandleData[]>;
|
|
7
|
+
getAllHistoricalPriceData(): Promise<Record<string, TokenHistoricalPriceData>>;
|
|
8
|
+
fetchFirstCandle: (symbol: string, interval: CandleInterval) => Promise<CandleData | null>;
|
|
6
9
|
isLoading: (symbol?: string) => boolean;
|
|
7
10
|
clearCache: () => void;
|
|
8
11
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PerformanceOverlay {
|
|
2
|
+
id: string;
|
|
3
|
+
symbol: string;
|
|
4
|
+
label: string;
|
|
5
|
+
color: string;
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
type: 'asset' | 'portfolio';
|
|
8
|
+
weight?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface UsePerformanceOverlaysReturn {
|
|
11
|
+
overlays: PerformanceOverlay[];
|
|
12
|
+
generateOverlaySymbols: () => string[];
|
|
13
|
+
}
|
|
14
|
+
export declare const usePerformanceOverlays: () => UsePerformanceOverlaysReturn;
|
package/dist/index.d.ts
CHANGED
|
@@ -291,6 +291,7 @@ interface PositionAssetDetailDto {
|
|
|
291
291
|
unrealizedPnl: number;
|
|
292
292
|
liquidationPrice: number;
|
|
293
293
|
isExternallyModified: boolean;
|
|
294
|
+
initialWeight: number;
|
|
294
295
|
}
|
|
295
296
|
/**
|
|
296
297
|
* Position sync status
|
|
@@ -615,16 +616,13 @@ type CandleInterval = "1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" | "4h" |
|
|
|
615
616
|
* Candle data structure from WebSocket
|
|
616
617
|
*/
|
|
617
618
|
interface CandleData {
|
|
619
|
+
s?: string;
|
|
618
620
|
t: number;
|
|
619
621
|
T: number;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
h: string;
|
|
625
|
-
l: string;
|
|
626
|
-
v: string;
|
|
627
|
-
n: number;
|
|
622
|
+
o: number;
|
|
623
|
+
c: number;
|
|
624
|
+
h: number;
|
|
625
|
+
l: number;
|
|
628
626
|
}
|
|
629
627
|
/**
|
|
630
628
|
* Candle chart data organized by symbol only
|
|
@@ -643,19 +641,6 @@ interface CandleSnapshotRequest {
|
|
|
643
641
|
};
|
|
644
642
|
type: "candleSnapshot";
|
|
645
643
|
}
|
|
646
|
-
/**
|
|
647
|
-
* Weighted candle data for chart visualization
|
|
648
|
-
*/
|
|
649
|
-
interface WeightedCandleData {
|
|
650
|
-
t: number;
|
|
651
|
-
T: number;
|
|
652
|
-
o: number;
|
|
653
|
-
c: number;
|
|
654
|
-
h: number;
|
|
655
|
-
l: number;
|
|
656
|
-
v: number;
|
|
657
|
-
n: number;
|
|
658
|
-
}
|
|
659
644
|
|
|
660
645
|
/**
|
|
661
646
|
* Main SDK client for Pear Protocol Hyperliquid API integration
|
|
@@ -883,17 +868,34 @@ interface UseTokenSelectionMetadataReturn {
|
|
|
883
868
|
}
|
|
884
869
|
declare const useTokenSelectionMetadata: () => UseTokenSelectionMetadataReturn;
|
|
885
870
|
|
|
871
|
+
interface HistoricalRange {
|
|
872
|
+
start: number;
|
|
873
|
+
end: number;
|
|
874
|
+
}
|
|
875
|
+
interface TokenHistoricalPriceData {
|
|
876
|
+
symbol: string;
|
|
877
|
+
interval: CandleInterval;
|
|
878
|
+
candles: CandleData[];
|
|
879
|
+
oldestTime: number | null;
|
|
880
|
+
latestTime: number | null;
|
|
881
|
+
}
|
|
882
|
+
declare const useHistoricalPriceDataStore: any;
|
|
883
|
+
|
|
886
884
|
interface UseHistoricalPriceDataReturn {
|
|
887
885
|
fetchHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval, callback?: (data: Record<string, CandleData[]>) => void) => Promise<Record<string, CandleData[]>>;
|
|
888
886
|
hasHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => boolean;
|
|
889
887
|
getHistoricalPriceData: (startTime: number, endTime: number, interval: CandleInterval) => Record<string, CandleData[]>;
|
|
888
|
+
getAllHistoricalPriceData(): Promise<Record<string, TokenHistoricalPriceData>>;
|
|
889
|
+
fetchFirstCandle: (symbol: string, interval: CandleInterval) => Promise<CandleData | null>;
|
|
890
890
|
isLoading: (symbol?: string) => boolean;
|
|
891
891
|
clearCache: () => void;
|
|
892
892
|
}
|
|
893
893
|
declare const useHistoricalPriceData: () => UseHistoricalPriceDataReturn;
|
|
894
894
|
|
|
895
895
|
interface UseBasketCandlesReturn {
|
|
896
|
-
fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<
|
|
896
|
+
fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
|
|
897
|
+
fetchPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval, symbol: string) => Promise<CandleData[]>;
|
|
898
|
+
fetchOverallPerformanceCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<CandleData[]>;
|
|
897
899
|
isLoading: boolean;
|
|
898
900
|
addRealtimeListener: (cb: RealtimeBarsCallback) => string;
|
|
899
901
|
removeRealtimeListener: (id: string) => void;
|
|
@@ -915,6 +917,21 @@ type RealtimeBarsCallback = (bar: RealtimeBar) => void;
|
|
|
915
917
|
*/
|
|
916
918
|
declare const useBasketCandles: () => UseBasketCandlesReturn;
|
|
917
919
|
|
|
920
|
+
interface PerformanceOverlay {
|
|
921
|
+
id: string;
|
|
922
|
+
symbol: string;
|
|
923
|
+
label: string;
|
|
924
|
+
color: string;
|
|
925
|
+
enabled: boolean;
|
|
926
|
+
type: 'asset' | 'portfolio';
|
|
927
|
+
weight?: number;
|
|
928
|
+
}
|
|
929
|
+
interface UsePerformanceOverlaysReturn {
|
|
930
|
+
overlays: PerformanceOverlay[];
|
|
931
|
+
generateOverlaySymbols: () => string[];
|
|
932
|
+
}
|
|
933
|
+
declare const usePerformanceOverlays: () => UsePerformanceOverlaysReturn;
|
|
934
|
+
|
|
918
935
|
interface UseHyperliquidWebSocketProps {
|
|
919
936
|
wsUrl: string;
|
|
920
937
|
address: string | null;
|
|
@@ -1027,7 +1044,7 @@ declare const getCompleteTimestamps: (candleLookups: Record<string, Map<number,
|
|
|
1027
1044
|
* Compute basket candles from individual token candles using weighted ratios
|
|
1028
1045
|
* Optimized version that creates lookup maps once and reuses them
|
|
1029
1046
|
*/
|
|
1030
|
-
declare const computeBasketCandles: (longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>) =>
|
|
1047
|
+
declare const computeBasketCandles: (longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>) => CandleData[];
|
|
1031
1048
|
|
|
1032
1049
|
/**
|
|
1033
1050
|
* Maps TradingView ResolutionString to CandleInterval
|
|
@@ -1038,18 +1055,5 @@ declare function mapTradingViewIntervalToCandleInterval(interval: string): Candl
|
|
|
1038
1055
|
*/
|
|
1039
1056
|
declare function mapCandleIntervalToTradingViewInterval(interval: CandleInterval): string;
|
|
1040
1057
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
end: number;
|
|
1044
|
-
}
|
|
1045
|
-
interface TokenHistoricalPriceData {
|
|
1046
|
-
symbol: string;
|
|
1047
|
-
interval: CandleInterval;
|
|
1048
|
-
candles: CandleData[];
|
|
1049
|
-
oldestTime: number | null;
|
|
1050
|
-
latestTime: number | null;
|
|
1051
|
-
}
|
|
1052
|
-
declare const useHistoricalPriceDataStore: any;
|
|
1053
|
-
|
|
1054
|
-
export { AccountSummaryCalculator, ConflictDetector, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, TokenMetadataExtractor, calculateWeightedRatio, computeBasketCandles, createCandleLookups, PearHyperliquidClient as default, getCompleteTimestamps, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, useAccountSummary, useAddress, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, useTokenSelectionMetadata, useTradeHistories, useUserSelection, useWebData };
|
|
1055
|
-
export type { AccountSummaryResponseDto, AgentWalletDto, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetMarketData, AssetPosition, BalanceSummaryDto, CandleChartData, CandleData, CandleInterval, CandleSnapshotRequest, ClearinghouseState, CrossMarginSummaryDto, CumFundingDto, HLWebSocketResponse, HistoricalRange, MarginSummaryDto, MigrationHookState, MigrationHooks, OpenLimitOrderDto, OpenOrderV1Dto, OpenPositionDto, OpenPositionV1Dto, OrderAssetDto, OrderStatus, PearHyperliquidConfig, PnlDto, PositionAssetDetailDto, PositionSideDto, PositionSyncStatus, RawValueDto, RealtimeBar, RealtimeBarsCallback, SyncOpenOrderDto, SyncOpenOrderResponseDto, SyncOpenPositionDto, SyncOpenPositionResponseDto, SyncTradeHistoryDto, SyncTradeHistoryResponseDto, TokenConflict, TokenHistoricalPriceData, TokenMetadata, TokenSelection, TpSlDto, TradeHistoryAssetDataDto, TradeHistoryDataDto, TradeHistoryV1Dto, UniverseAsset, UseBasketCandlesReturn, UseHistoricalPriceDataReturn, UseTokenSelectionMetadataReturn, UserSelectionState, WebData2Response, WebSocketAckResponse, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketSubscribeMessage, WeightedCandleData, WsAllMidsData };
|
|
1058
|
+
export { AccountSummaryCalculator, ConflictDetector, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, TokenMetadataExtractor, calculateWeightedRatio, computeBasketCandles, createCandleLookups, PearHyperliquidClient as default, getCompleteTimestamps, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, useAccountSummary, useAddress, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, usePerformanceOverlays, useTokenSelectionMetadata, useTradeHistories, useUserSelection, useWebData };
|
|
1059
|
+
export type { AccountSummaryResponseDto, AgentWalletDto, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetMarketData, AssetPosition, BalanceSummaryDto, CandleChartData, CandleData, CandleInterval, CandleSnapshotRequest, ClearinghouseState, CrossMarginSummaryDto, CumFundingDto, HLWebSocketResponse, HistoricalRange, MarginSummaryDto, MigrationHookState, MigrationHooks, OpenLimitOrderDto, OpenOrderV1Dto, OpenPositionDto, OpenPositionV1Dto, OrderAssetDto, OrderStatus, PearHyperliquidConfig, PerformanceOverlay, PnlDto, PositionAssetDetailDto, PositionSideDto, PositionSyncStatus, RawValueDto, RealtimeBar, RealtimeBarsCallback, SyncOpenOrderDto, SyncOpenOrderResponseDto, SyncOpenPositionDto, SyncOpenPositionResponseDto, SyncTradeHistoryDto, SyncTradeHistoryResponseDto, TokenConflict, TokenHistoricalPriceData, TokenMetadata, TokenSelection, TpSlDto, TradeHistoryAssetDataDto, TradeHistoryDataDto, TradeHistoryV1Dto, UniverseAsset, UseBasketCandlesReturn, UseHistoricalPriceDataReturn, UsePerformanceOverlaysReturn, UseTokenSelectionMetadataReturn, UserSelectionState, WebData2Response, WebSocketAckResponse, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketSubscribeMessage, WsAllMidsData };
|
package/dist/index.js
CHANGED
|
@@ -7176,290 +7176,73 @@ class AccountSummaryCalculator {
|
|
|
7176
7176
|
}
|
|
7177
7177
|
}
|
|
7178
7178
|
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
if ((_a = assetPos.position) === null || _a === void 0 ? void 0 : _a.coin) {
|
|
7199
|
-
hlPositionsMap.set(assetPos.position.coin, assetPos);
|
|
7200
|
-
}
|
|
7201
|
-
});
|
|
7202
|
-
const openPositionDtos = [];
|
|
7203
|
-
for (const position of rawPositions) {
|
|
7204
|
-
const syncedPositionDto = this.syncPositionWithAggregateData(position, hlPositionsMap, platformTotalsByAsset);
|
|
7205
|
-
openPositionDtos.push(syncedPositionDto);
|
|
7206
|
-
}
|
|
7207
|
-
return openPositionDtos;
|
|
7208
|
-
}
|
|
7209
|
-
getUserPositions() {
|
|
7210
|
-
var _a, _b;
|
|
7211
|
-
return ((_b = (_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState) === null || _b === void 0 ? void 0 : _b.assetPositions) || [];
|
|
7212
|
-
}
|
|
7213
|
-
getMarketPrice(coin) {
|
|
7214
|
-
var _a;
|
|
7215
|
-
if (!((_a = this.allMids) === null || _a === void 0 ? void 0 : _a.mids))
|
|
7216
|
-
return 0;
|
|
7217
|
-
const exactPrice = this.allMids.mids[coin];
|
|
7218
|
-
if (exactPrice) {
|
|
7219
|
-
return Number(exactPrice);
|
|
7220
|
-
}
|
|
7221
|
-
const baseCurrency = this.extractBaseCurrency(coin);
|
|
7222
|
-
const basePrice = this.allMids.mids[baseCurrency];
|
|
7223
|
-
if (basePrice) {
|
|
7224
|
-
return Number(basePrice);
|
|
7225
|
-
}
|
|
7226
|
-
return 0;
|
|
7227
|
-
}
|
|
7228
|
-
calculatePlatformTotalsByAsset(positions) {
|
|
7229
|
-
const totalsMap = new Map();
|
|
7230
|
-
for (const position of positions) {
|
|
7231
|
-
for (const asset of position.longAssets || []) {
|
|
7232
|
-
const baseCurrency = this.extractBaseCurrency(asset.coin);
|
|
7233
|
-
if (!totalsMap.has(baseCurrency)) {
|
|
7234
|
-
totalsMap.set(baseCurrency, {
|
|
7235
|
-
totalSize: 0,
|
|
7236
|
-
positions: []
|
|
7237
|
-
});
|
|
7238
|
-
}
|
|
7239
|
-
const totals = totalsMap.get(baseCurrency);
|
|
7240
|
-
const assetSize = Number(asset.size || 0);
|
|
7241
|
-
totals.totalSize += assetSize;
|
|
7242
|
-
totals.positions.push({
|
|
7243
|
-
positionId: position.positionId,
|
|
7244
|
-
asset: asset,
|
|
7245
|
-
size: assetSize
|
|
7246
|
-
});
|
|
7247
|
-
}
|
|
7248
|
-
for (const asset of position.shortAssets || []) {
|
|
7249
|
-
const baseCurrency = this.extractBaseCurrency(asset.coin);
|
|
7250
|
-
if (!totalsMap.has(baseCurrency)) {
|
|
7251
|
-
totalsMap.set(baseCurrency, {
|
|
7252
|
-
totalSize: 0,
|
|
7253
|
-
positions: []
|
|
7254
|
-
});
|
|
7255
|
-
}
|
|
7256
|
-
const totals = totalsMap.get(baseCurrency);
|
|
7257
|
-
const assetSize = Number(asset.size || 0);
|
|
7258
|
-
totals.totalSize += assetSize;
|
|
7259
|
-
totals.positions.push({
|
|
7260
|
-
positionId: position.positionId,
|
|
7261
|
-
asset: asset,
|
|
7262
|
-
size: assetSize
|
|
7263
|
-
});
|
|
7264
|
-
}
|
|
7265
|
-
}
|
|
7266
|
-
return totalsMap;
|
|
7267
|
-
}
|
|
7268
|
-
extractBaseCurrency(assetName) {
|
|
7269
|
-
return assetName.split('/')[0] || assetName;
|
|
7270
|
-
}
|
|
7271
|
-
syncPositionWithAggregateData(position, hlPositionsMap, platformTotalsByAsset) {
|
|
7272
|
-
const syncResults = [];
|
|
7273
|
-
let hasExternalModification = false;
|
|
7274
|
-
let allAssetsClosed = true;
|
|
7275
|
-
let longAssetStatuses = { total: 0, closed: 0 };
|
|
7276
|
-
let shortAssetStatuses = { total: 0, closed: 0 };
|
|
7277
|
-
// Process long assets
|
|
7278
|
-
for (const asset of position.longAssets || []) {
|
|
7279
|
-
const baseCurrency = this.extractBaseCurrency(asset.coin);
|
|
7280
|
-
const hlPosition = hlPositionsMap.get(baseCurrency);
|
|
7281
|
-
const platformTotals = platformTotalsByAsset.get(baseCurrency);
|
|
7282
|
-
const syncResult = this.syncAssetWithAggregateData({ ...asset, side: PositionSide.LONG }, hlPosition, (platformTotals === null || platformTotals === void 0 ? void 0 : platformTotals.totalSize) || 0);
|
|
7283
|
-
syncResults.push(syncResult);
|
|
7284
|
-
longAssetStatuses.total++;
|
|
7285
|
-
if (syncResult.actualSize === 0) {
|
|
7286
|
-
longAssetStatuses.closed++;
|
|
7287
|
-
}
|
|
7288
|
-
if (syncResult.isExternallyModified) {
|
|
7289
|
-
hasExternalModification = true;
|
|
7290
|
-
}
|
|
7291
|
-
if (syncResult.actualSize !== 0) {
|
|
7292
|
-
allAssetsClosed = false;
|
|
7293
|
-
}
|
|
7294
|
-
}
|
|
7295
|
-
// Process short assets
|
|
7296
|
-
for (const asset of position.shortAssets || []) {
|
|
7297
|
-
const baseCurrency = this.extractBaseCurrency(asset.coin);
|
|
7298
|
-
const hlPosition = hlPositionsMap.get(baseCurrency);
|
|
7299
|
-
const platformTotals = platformTotalsByAsset.get(baseCurrency);
|
|
7300
|
-
const syncResult = this.syncAssetWithAggregateData({ ...asset, side: PositionSide.SHORT }, hlPosition, (platformTotals === null || platformTotals === void 0 ? void 0 : platformTotals.totalSize) || 0);
|
|
7301
|
-
syncResults.push(syncResult);
|
|
7302
|
-
shortAssetStatuses.total++;
|
|
7303
|
-
if (syncResult.actualSize === 0) {
|
|
7304
|
-
shortAssetStatuses.closed++;
|
|
7305
|
-
}
|
|
7306
|
-
if (syncResult.isExternallyModified) {
|
|
7307
|
-
hasExternalModification = true;
|
|
7308
|
-
}
|
|
7309
|
-
if (syncResult.actualSize !== 0) {
|
|
7310
|
-
allAssetsClosed = false;
|
|
7311
|
-
}
|
|
7312
|
-
}
|
|
7313
|
-
const syncStatus = this.determineSyncStatus(hasExternalModification, allAssetsClosed, longAssetStatuses, shortAssetStatuses);
|
|
7314
|
-
return this.mapPositionToDtoWithSyncData(position, syncResults, syncStatus);
|
|
7315
|
-
}
|
|
7316
|
-
determineSyncStatus(hasExternalModification, allAssetsClosed, longAssetStatuses, shortAssetStatuses) {
|
|
7317
|
-
if (allAssetsClosed) {
|
|
7318
|
-
return 'EXTERNALLY_CLOSED';
|
|
7319
|
-
}
|
|
7320
|
-
const allLongsClosed = longAssetStatuses.total > 0 &&
|
|
7321
|
-
longAssetStatuses.closed === longAssetStatuses.total;
|
|
7322
|
-
const allShortsClosed = shortAssetStatuses.total > 0 &&
|
|
7323
|
-
shortAssetStatuses.closed === shortAssetStatuses.total;
|
|
7324
|
-
if ((allLongsClosed && !allShortsClosed) || (!allLongsClosed && allShortsClosed)) {
|
|
7325
|
-
return 'PAIR_BROKEN';
|
|
7326
|
-
}
|
|
7327
|
-
if (hasExternalModification) {
|
|
7328
|
-
return 'EXTERNALLY_MODIFIED';
|
|
7329
|
-
}
|
|
7330
|
-
return 'SYNCED';
|
|
7331
|
-
}
|
|
7332
|
-
syncAssetWithAggregateData(asset, hlPosition, platformTotal) {
|
|
7333
|
-
const platformSize = Number(asset.size || 0);
|
|
7334
|
-
if (!hlPosition || !hlPosition.position || !hlPosition.position.szi) {
|
|
7335
|
-
return {
|
|
7336
|
-
asset,
|
|
7337
|
-
actualSize: 0,
|
|
7338
|
-
isExternallyModified: true,
|
|
7339
|
-
cumFunding: { allTime: 0, sinceChange: 0, sinceOpen: 0 },
|
|
7340
|
-
unrealizedPnl: 0,
|
|
7341
|
-
liquidationPrice: 0
|
|
7342
|
-
};
|
|
7179
|
+
const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, leverage, cumFunding, isLong = true) => {
|
|
7180
|
+
const initialPositionValue = asset.entryPrice * asset.size;
|
|
7181
|
+
const positionValue = currentPrice * asset.size;
|
|
7182
|
+
const marginUsed = positionValue / leverage;
|
|
7183
|
+
const unrealizedPnl = isLong
|
|
7184
|
+
? positionValue - initialPositionValue
|
|
7185
|
+
: initialPositionValue - positionValue;
|
|
7186
|
+
return {
|
|
7187
|
+
coin: asset.coin,
|
|
7188
|
+
entryPrice: asset.entryPrice,
|
|
7189
|
+
actualSize: asset.size,
|
|
7190
|
+
marginUsed: marginUsed,
|
|
7191
|
+
positionValue: positionValue,
|
|
7192
|
+
unrealizedPnl: unrealizedPnl,
|
|
7193
|
+
initialWeight: initialPositionValue / totalInitialPositionSize,
|
|
7194
|
+
cumFunding: {
|
|
7195
|
+
allTime: parseFloat((cumFunding === null || cumFunding === void 0 ? void 0 : cumFunding.allTime) || "0"),
|
|
7196
|
+
sinceChange: parseFloat((cumFunding === null || cumFunding === void 0 ? void 0 : cumFunding.sinceChange) || "0"),
|
|
7197
|
+
sinceOpen: parseFloat((cumFunding === null || cumFunding === void 0 ? void 0 : cumFunding.sinceOpen) || "0"),
|
|
7343
7198
|
}
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
const actualSize = hlTotalSize * proportion;
|
|
7350
|
-
// Get cumFunding from hlPosition.position.cumFunding
|
|
7351
|
-
const rawCumFunding = hlPosition.position.cumFunding;
|
|
7352
|
-
const cumFunding = {
|
|
7353
|
-
allTime: Number((rawCumFunding === null || rawCumFunding === void 0 ? void 0 : rawCumFunding.allTime) || 0),
|
|
7354
|
-
sinceChange: Number((rawCumFunding === null || rawCumFunding === void 0 ? void 0 : rawCumFunding.sinceChange) || 0) * proportion,
|
|
7355
|
-
sinceOpen: Number((rawCumFunding === null || rawCumFunding === void 0 ? void 0 : rawCumFunding.sinceOpen) || 0) * proportion
|
|
7356
|
-
};
|
|
7357
|
-
const unrealizedPnl = Number(hlPosition.position.unrealizedPnl || 0) * proportion;
|
|
7358
|
-
const liquidationPrice = Number(hlPosition.position.liquidationPx || 0);
|
|
7359
|
-
return {
|
|
7360
|
-
asset,
|
|
7361
|
-
actualSize,
|
|
7362
|
-
isExternallyModified,
|
|
7363
|
-
cumFunding,
|
|
7364
|
-
unrealizedPnl,
|
|
7365
|
-
liquidationPrice
|
|
7366
|
-
};
|
|
7367
|
-
}
|
|
7368
|
-
mapPositionToDtoWithSyncData(position, syncResults, syncStatus) {
|
|
7369
|
-
var _a, _b;
|
|
7370
|
-
const longAssets = ((_a = position.longAssets) === null || _a === void 0 ? void 0 : _a.filter(asset => asset)) || [];
|
|
7371
|
-
const shortAssets = ((_b = position.shortAssets) === null || _b === void 0 ? void 0 : _b.filter(asset => asset)) || [];
|
|
7372
|
-
const syncResultsMap = new Map();
|
|
7373
|
-
syncResults.forEach(result => {
|
|
7374
|
-
syncResultsMap.set(`${result.asset.coin}-${result.asset.side}`, result);
|
|
7375
|
-
});
|
|
7376
|
-
const currentTotalPositionValue = this.calculateCurrentTotalPositionValue(syncResults);
|
|
7377
|
-
const entryTotalPositionValue = this.calculateEntryTotalPositionValue(syncResults);
|
|
7378
|
-
const totalMarginUsed = entryTotalPositionValue / position.leverage;
|
|
7379
|
-
return {
|
|
7380
|
-
syncStatus: syncStatus,
|
|
7199
|
+
};
|
|
7200
|
+
};
|
|
7201
|
+
const buildPositionValue = (rawPositions, webData2, allMids) => {
|
|
7202
|
+
return rawPositions.map((position) => {
|
|
7203
|
+
let mappedPosition = {
|
|
7381
7204
|
positionId: position.positionId,
|
|
7382
7205
|
address: position.address,
|
|
7383
7206
|
leverage: position.leverage,
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
netFunding:
|
|
7389
|
-
positionValue:
|
|
7390
|
-
marginUsed: totalMarginUsed,
|
|
7391
|
-
unrealizedPnl: this.calculateTotalUnrealizedPnlFromSyncResults(syncResults),
|
|
7392
|
-
lastSyncAt: new Date().toISOString(),
|
|
7393
|
-
longAssets: longAssets.map(asset => this.mapAssetToDetailDto(asset, syncResultsMap.get(`${asset.coin}-LONG`))),
|
|
7394
|
-
shortAssets: shortAssets.map(asset => this.mapAssetToDetailDto(asset, syncResultsMap.get(`${asset.coin}-SHORT`))),
|
|
7395
|
-
createdAt: position.createdAt,
|
|
7396
|
-
updatedAt: position.updatedAt
|
|
7397
|
-
};
|
|
7398
|
-
}
|
|
7399
|
-
mapAssetToDetailDto(asset, syncData) {
|
|
7400
|
-
const currentPrice = this.getMarketPrice(asset.coin);
|
|
7401
|
-
const actualSize = (syncData === null || syncData === void 0 ? void 0 : syncData.actualSize) || Number(asset.size || 0);
|
|
7402
|
-
const positionValue = actualSize * currentPrice;
|
|
7403
|
-
const entryValue = Number(asset.size || 0) * Number(asset.entryPrice || 0);
|
|
7404
|
-
return {
|
|
7405
|
-
coin: asset.coin,
|
|
7406
|
-
entryPrice: Number(asset.entryPrice || 0),
|
|
7407
|
-
platformSize: Number(asset.size || 0),
|
|
7408
|
-
actualSize: actualSize,
|
|
7409
|
-
isExternallyModified: (syncData === null || syncData === void 0 ? void 0 : syncData.isExternallyModified) || false,
|
|
7410
|
-
cumFunding: (syncData === null || syncData === void 0 ? void 0 : syncData.cumFunding) || {
|
|
7411
|
-
allTime: 0,
|
|
7412
|
-
sinceChange: 0,
|
|
7413
|
-
sinceOpen: 0
|
|
7414
|
-
},
|
|
7415
|
-
marginUsed: entryValue,
|
|
7416
|
-
positionValue: positionValue,
|
|
7417
|
-
unrealizedPnl: (syncData === null || syncData === void 0 ? void 0 : syncData.unrealizedPnl) || 0,
|
|
7418
|
-
liquidationPrice: (syncData === null || syncData === void 0 ? void 0 : syncData.liquidationPrice) || 0
|
|
7207
|
+
entryRatio: 1,
|
|
7208
|
+
marginUsed: 0,
|
|
7209
|
+
markRatio: 1,
|
|
7210
|
+
unrealizedPnl: 0,
|
|
7211
|
+
netFunding: 0,
|
|
7212
|
+
positionValue: 0,
|
|
7419
7213
|
};
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
return
|
|
7450
|
-
}
|
|
7451
|
-
|
|
7452
|
-
return syncResults.reduce((sum, result) => {
|
|
7453
|
-
const currentPrice = this.getMarketPrice(result.asset.coin);
|
|
7454
|
-
return sum + (result.actualSize * currentPrice);
|
|
7455
|
-
}, 0);
|
|
7456
|
-
}
|
|
7457
|
-
calculateEntryTotalPositionValue(syncResults) {
|
|
7458
|
-
return syncResults.reduce((sum, result) => {
|
|
7459
|
-
return sum + (Number(result.asset.size || 0) * Number(result.asset.entryPrice || 0));
|
|
7460
|
-
}, 0);
|
|
7461
|
-
}
|
|
7462
|
-
}
|
|
7214
|
+
const totalInitialPositionSize = position.longAssets.reduce((acc, asset) => acc + (asset.entryPrice * asset.size), 0) +
|
|
7215
|
+
position.shortAssets.reduce((acc, asset) => acc + (asset.entryPrice * asset.size), 0);
|
|
7216
|
+
mappedPosition.longAssets = position.longAssets.map(longAsset => {
|
|
7217
|
+
var _a;
|
|
7218
|
+
const currentPrice = parseFloat(allMids.mids[longAsset.coin]);
|
|
7219
|
+
const cumFunding = (_a = webData2.clearinghouseState.assetPositions.find(ap => ap.position.coin === longAsset.coin)) === null || _a === void 0 ? void 0 : _a.position.cumFunding;
|
|
7220
|
+
const mappedPositionAssets = calculatePositionAsset(longAsset, currentPrice, totalInitialPositionSize, mappedPosition.leverage, cumFunding, true);
|
|
7221
|
+
mappedPosition.unrealizedPnl += mappedPositionAssets.unrealizedPnl;
|
|
7222
|
+
mappedPosition.positionValue += mappedPositionAssets.positionValue;
|
|
7223
|
+
mappedPosition.marginUsed += mappedPositionAssets.marginUsed;
|
|
7224
|
+
mappedPosition.netFunding += mappedPositionAssets.cumFunding.sinceOpen;
|
|
7225
|
+
// Calculate weighted entry and mark ratios for long positions
|
|
7226
|
+
mappedPosition.entryRatio *= Math.pow(longAsset.entryPrice, mappedPositionAssets.initialWeight);
|
|
7227
|
+
mappedPosition.markRatio *= Math.pow(currentPrice, mappedPositionAssets.initialWeight);
|
|
7228
|
+
return mappedPositionAssets;
|
|
7229
|
+
});
|
|
7230
|
+
mappedPosition.shortAssets = position.shortAssets.map(shortAsset => {
|
|
7231
|
+
var _a;
|
|
7232
|
+
const currentPrice = parseFloat(allMids.mids[shortAsset.coin]);
|
|
7233
|
+
const cumFunding = (_a = webData2.clearinghouseState.assetPositions.find(ap => ap.position.coin === shortAsset.coin)) === null || _a === void 0 ? void 0 : _a.position.cumFunding;
|
|
7234
|
+
const mappedPositionAssets = calculatePositionAsset(shortAsset, currentPrice, totalInitialPositionSize, mappedPosition.leverage, cumFunding, false);
|
|
7235
|
+
mappedPosition.netFunding += mappedPositionAssets.cumFunding.sinceOpen;
|
|
7236
|
+
mappedPosition.unrealizedPnl += mappedPositionAssets.unrealizedPnl;
|
|
7237
|
+
mappedPosition.positionValue += mappedPositionAssets.positionValue;
|
|
7238
|
+
mappedPosition.marginUsed += mappedPositionAssets.marginUsed;
|
|
7239
|
+
mappedPosition.entryRatio *= Math.pow(shortAsset.entryPrice, -mappedPositionAssets.initialWeight);
|
|
7240
|
+
mappedPosition.markRatio *= Math.pow(currentPrice, -mappedPositionAssets.initialWeight);
|
|
7241
|
+
return mappedPositionAssets;
|
|
7242
|
+
});
|
|
7243
|
+
return mappedPosition;
|
|
7244
|
+
});
|
|
7245
|
+
};
|
|
7463
7246
|
|
|
7464
7247
|
const useTradeHistories = () => {
|
|
7465
7248
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -7489,9 +7272,8 @@ const useOpenPositions = () => {
|
|
|
7489
7272
|
if (!userOpenPositions || !webData2 || !allMids) {
|
|
7490
7273
|
return { data: null, isLoading };
|
|
7491
7274
|
}
|
|
7492
|
-
const
|
|
7493
|
-
|
|
7494
|
-
return { data: processed, isLoading };
|
|
7275
|
+
const positions = buildPositionValue(userOpenPositions, webData2, allMids);
|
|
7276
|
+
return { data: positions, isLoading };
|
|
7495
7277
|
};
|
|
7496
7278
|
/**
|
|
7497
7279
|
* Hook to access open orders with loading state
|
|
@@ -8017,6 +7799,9 @@ const useHistoricalPriceData = () => {
|
|
|
8017
7799
|
const allTokens = getAllTokens();
|
|
8018
7800
|
return allTokens.some(token => isTokenLoading(token.symbol));
|
|
8019
7801
|
}, [getAllTokens, isTokenLoading]);
|
|
7802
|
+
const getAllHistoricalPriceData = useCallback(async () => {
|
|
7803
|
+
return useHistoricalPriceDataStore.getState().historicalPriceData;
|
|
7804
|
+
}, []);
|
|
8020
7805
|
const fetchHistoricalPriceData = useCallback(async (startTime, endTime, interval, callback) => {
|
|
8021
7806
|
const allTokens = getAllTokens();
|
|
8022
7807
|
if (allTokens.length === 0) {
|
|
@@ -8068,13 +7853,23 @@ const useHistoricalPriceData = () => {
|
|
|
8068
7853
|
client,
|
|
8069
7854
|
addHistoricalPriceData,
|
|
8070
7855
|
]);
|
|
7856
|
+
const fetchFirstCandle = useCallback(async (symbol, interval) => {
|
|
7857
|
+
const key = `${symbol}-${interval}`;
|
|
7858
|
+
const storeData = useHistoricalPriceDataStore.getState().historicalPriceData[key];
|
|
7859
|
+
if (storeData && storeData.candles.length > 0) {
|
|
7860
|
+
return storeData.candles[0];
|
|
7861
|
+
}
|
|
7862
|
+
return null;
|
|
7863
|
+
}, [client, addHistoricalPriceData]);
|
|
8071
7864
|
const clearCache = useCallback(() => {
|
|
8072
7865
|
clearData();
|
|
8073
7866
|
}, [clearData]);
|
|
8074
7867
|
return {
|
|
8075
7868
|
fetchHistoricalPriceData,
|
|
8076
7869
|
hasHistoricalPriceData,
|
|
7870
|
+
getAllHistoricalPriceData,
|
|
8077
7871
|
getHistoricalPriceData,
|
|
7872
|
+
fetchFirstCandle,
|
|
8078
7873
|
isLoading,
|
|
8079
7874
|
clearCache,
|
|
8080
7875
|
};
|
|
@@ -8108,7 +7903,7 @@ const calculateWeightedRatio = (longTokens, shortTokens, candleLookups, timestam
|
|
|
8108
7903
|
const lookup = candleLookups[token.symbol];
|
|
8109
7904
|
const candle = lookup === null || lookup === void 0 ? void 0 : lookup.get(timestamp);
|
|
8110
7905
|
if (candle) {
|
|
8111
|
-
const price =
|
|
7906
|
+
const price = candle[priceType];
|
|
8112
7907
|
if (price > 0) {
|
|
8113
7908
|
const weightFactor = token.weight / 100;
|
|
8114
7909
|
longProduct *= Math.pow(price, weightFactor);
|
|
@@ -8123,7 +7918,7 @@ const calculateWeightedRatio = (longTokens, shortTokens, candleLookups, timestam
|
|
|
8123
7918
|
const lookup = candleLookups[token.symbol];
|
|
8124
7919
|
const candle = lookup === null || lookup === void 0 ? void 0 : lookup.get(timestamp);
|
|
8125
7920
|
if (candle) {
|
|
8126
|
-
const price =
|
|
7921
|
+
const price = candle[priceType];
|
|
8127
7922
|
if (price > 0) {
|
|
8128
7923
|
const weightFactor = token.weight / 100;
|
|
8129
7924
|
shortProduct *= Math.pow(price, -weightFactor);
|
|
@@ -8197,8 +7992,6 @@ const computeBasketCandles = (longTokens, shortTokens, tokenCandles) => {
|
|
|
8197
7992
|
// Compute all OHLC products in a single pass per side
|
|
8198
7993
|
let longOpen = 1, longHigh = 1, longLow = 1, longClose = 1;
|
|
8199
7994
|
let shortOpen = 1, shortHigh = 1, shortLow = 1, shortClose = 1;
|
|
8200
|
-
let totalVolume = 0;
|
|
8201
|
-
let totalTrades = 0;
|
|
8202
7995
|
let candleDuration = 0;
|
|
8203
7996
|
let missing = false;
|
|
8204
7997
|
// Accumulate volume/trades and compute long side contributions
|
|
@@ -8209,10 +8002,10 @@ const computeBasketCandles = (longTokens, shortTokens, tokenCandles) => {
|
|
|
8209
8002
|
break;
|
|
8210
8003
|
}
|
|
8211
8004
|
const weightFactor = token.weight / 100;
|
|
8212
|
-
const o =
|
|
8213
|
-
const h =
|
|
8214
|
-
const l =
|
|
8215
|
-
const c =
|
|
8005
|
+
const o = candle.o;
|
|
8006
|
+
const h = candle.h;
|
|
8007
|
+
const l = candle.l;
|
|
8008
|
+
const c = candle.c;
|
|
8216
8009
|
if (!(o > 0 && h > 0 && l > 0 && c > 0)) {
|
|
8217
8010
|
missing = true;
|
|
8218
8011
|
break;
|
|
@@ -8221,8 +8014,6 @@ const computeBasketCandles = (longTokens, shortTokens, tokenCandles) => {
|
|
|
8221
8014
|
longHigh *= Math.pow(h, weightFactor);
|
|
8222
8015
|
longLow *= Math.pow(l, weightFactor);
|
|
8223
8016
|
longClose *= Math.pow(c, weightFactor);
|
|
8224
|
-
totalVolume += parseFloat(candle.v);
|
|
8225
|
-
totalTrades += candle.n;
|
|
8226
8017
|
if (candleDuration === 0)
|
|
8227
8018
|
candleDuration = candle.T - candle.t;
|
|
8228
8019
|
}
|
|
@@ -8236,10 +8027,10 @@ const computeBasketCandles = (longTokens, shortTokens, tokenCandles) => {
|
|
|
8236
8027
|
break;
|
|
8237
8028
|
}
|
|
8238
8029
|
const weightFactor = -(token.weight / 100);
|
|
8239
|
-
const o =
|
|
8240
|
-
const h =
|
|
8241
|
-
const l =
|
|
8242
|
-
const c =
|
|
8030
|
+
const o = candle.o;
|
|
8031
|
+
const h = candle.h;
|
|
8032
|
+
const l = candle.l;
|
|
8033
|
+
const c = candle.c;
|
|
8243
8034
|
if (!(o > 0 && h > 0 && l > 0 && c > 0)) {
|
|
8244
8035
|
missing = true;
|
|
8245
8036
|
break;
|
|
@@ -8248,8 +8039,6 @@ const computeBasketCandles = (longTokens, shortTokens, tokenCandles) => {
|
|
|
8248
8039
|
shortHigh *= Math.pow(h, weightFactor);
|
|
8249
8040
|
shortLow *= Math.pow(l, weightFactor);
|
|
8250
8041
|
shortClose *= Math.pow(c, weightFactor);
|
|
8251
|
-
totalVolume += parseFloat(candle.v);
|
|
8252
|
-
totalTrades += candle.n;
|
|
8253
8042
|
if (candleDuration === 0)
|
|
8254
8043
|
candleDuration = candle.T - candle.t;
|
|
8255
8044
|
}
|
|
@@ -8262,8 +8051,6 @@ const computeBasketCandles = (longTokens, shortTokens, tokenCandles) => {
|
|
|
8262
8051
|
h: longHigh * shortHigh,
|
|
8263
8052
|
l: longLow * shortLow,
|
|
8264
8053
|
c: longClose * shortClose,
|
|
8265
|
-
v: totalVolume,
|
|
8266
|
-
n: totalTrades,
|
|
8267
8054
|
});
|
|
8268
8055
|
}
|
|
8269
8056
|
return basketCandles;
|
|
@@ -8279,12 +8066,97 @@ const useBasketCandles = () => {
|
|
|
8279
8066
|
const longTokens = useUserSelection$1((state) => state.longTokens);
|
|
8280
8067
|
const shortTokens = useUserSelection$1((state) => state.shortTokens);
|
|
8281
8068
|
const candleData = useHyperliquidData((s) => s.candleData);
|
|
8282
|
-
const { fetchHistoricalPriceData, isLoading: tokenLoading } = useHistoricalPriceData();
|
|
8069
|
+
const { fetchHistoricalPriceData, isLoading: tokenLoading, getAllHistoricalPriceData } = useHistoricalPriceData();
|
|
8283
8070
|
const fetchBasketCandles = useCallback(async (startTime, endTime, interval) => {
|
|
8284
8071
|
const tokenCandles = await fetchHistoricalPriceData(startTime, endTime, interval);
|
|
8285
8072
|
const basket = computeBasketCandles(longTokens, shortTokens, tokenCandles);
|
|
8286
8073
|
return basket;
|
|
8287
8074
|
}, [fetchHistoricalPriceData, longTokens, shortTokens]);
|
|
8075
|
+
const fetchPerformanceCandles = useCallback(async (startTime, endTime, interval, symbol) => {
|
|
8076
|
+
const assetSymbol = symbol.split(" ")[1];
|
|
8077
|
+
const tokenCandles = await fetchHistoricalPriceData(startTime, endTime, interval);
|
|
8078
|
+
const assetCandles = tokenCandles[assetSymbol];
|
|
8079
|
+
if (!assetCandles)
|
|
8080
|
+
return [];
|
|
8081
|
+
return assetCandles;
|
|
8082
|
+
}, [fetchHistoricalPriceData, longTokens, shortTokens]);
|
|
8083
|
+
const fetchOverallPerformanceCandles = useCallback(async (startTime, endTime, interval) => {
|
|
8084
|
+
await fetchHistoricalPriceData(startTime, endTime, interval);
|
|
8085
|
+
const allCandles = await getAllHistoricalPriceData();
|
|
8086
|
+
const allTokens = [...longTokens, ...shortTokens];
|
|
8087
|
+
if (allTokens.length === 0)
|
|
8088
|
+
return [];
|
|
8089
|
+
const symbolsData = {};
|
|
8090
|
+
const baselinePrices = {};
|
|
8091
|
+
for (const token of allTokens) {
|
|
8092
|
+
const candles = allCandles[`${token.symbol}-${interval}`].candles;
|
|
8093
|
+
if (!candles || candles.length === 0)
|
|
8094
|
+
continue;
|
|
8095
|
+
symbolsData[token.symbol] = candles;
|
|
8096
|
+
const firstCandle = symbolsData[token.symbol][0];
|
|
8097
|
+
baselinePrices[token.symbol] = firstCandle.o;
|
|
8098
|
+
}
|
|
8099
|
+
if (Object.keys(symbolsData).length === 0)
|
|
8100
|
+
return [];
|
|
8101
|
+
const allTimestamps = new Set();
|
|
8102
|
+
const symbolCandlesByTimestamp = {};
|
|
8103
|
+
Object.entries(symbolsData).forEach(([symbol, candles]) => {
|
|
8104
|
+
const candleMap = new Map();
|
|
8105
|
+
candles.forEach(candle => {
|
|
8106
|
+
allTimestamps.add(candle.t);
|
|
8107
|
+
candleMap.set(candle.t, candle);
|
|
8108
|
+
});
|
|
8109
|
+
symbolCandlesByTimestamp[symbol] = candleMap;
|
|
8110
|
+
});
|
|
8111
|
+
const sortedTimestamps = Array.from(allTimestamps).sort((a, b) => a - b);
|
|
8112
|
+
const performanceCandles = [];
|
|
8113
|
+
const initialPortfolioValue = 1000;
|
|
8114
|
+
const lastKnownPrices = {};
|
|
8115
|
+
for (const timestamp of sortedTimestamps) {
|
|
8116
|
+
let portfolioValue = 0;
|
|
8117
|
+
let hasAllData = true;
|
|
8118
|
+
for (const token of allTokens) {
|
|
8119
|
+
const candleMap = symbolCandlesByTimestamp[token.symbol];
|
|
8120
|
+
if (!candleMap) {
|
|
8121
|
+
hasAllData = false;
|
|
8122
|
+
break;
|
|
8123
|
+
}
|
|
8124
|
+
let candle = candleMap.get(timestamp);
|
|
8125
|
+
if (!candle) {
|
|
8126
|
+
candle = lastKnownPrices[token.symbol];
|
|
8127
|
+
if (!candle) {
|
|
8128
|
+
hasAllData = false;
|
|
8129
|
+
break;
|
|
8130
|
+
}
|
|
8131
|
+
}
|
|
8132
|
+
else {
|
|
8133
|
+
lastKnownPrices[token.symbol] = candle;
|
|
8134
|
+
}
|
|
8135
|
+
const currentPrice = candle.c;
|
|
8136
|
+
const baselinePrice = baselinePrices[token.symbol];
|
|
8137
|
+
const allocation = (token.weight / 100) * initialPortfolioValue;
|
|
8138
|
+
const priceRatio = currentPrice / baselinePrice;
|
|
8139
|
+
if (longTokens.includes(token)) {
|
|
8140
|
+
portfolioValue += allocation * priceRatio;
|
|
8141
|
+
}
|
|
8142
|
+
else {
|
|
8143
|
+
portfolioValue += allocation / priceRatio;
|
|
8144
|
+
}
|
|
8145
|
+
}
|
|
8146
|
+
if (!hasAllData)
|
|
8147
|
+
continue;
|
|
8148
|
+
const performanceCandle = {
|
|
8149
|
+
t: timestamp,
|
|
8150
|
+
T: timestamp,
|
|
8151
|
+
o: portfolioValue,
|
|
8152
|
+
h: portfolioValue,
|
|
8153
|
+
l: portfolioValue,
|
|
8154
|
+
c: portfolioValue,
|
|
8155
|
+
};
|
|
8156
|
+
performanceCandles.push(performanceCandle);
|
|
8157
|
+
}
|
|
8158
|
+
return performanceCandles;
|
|
8159
|
+
}, [fetchHistoricalPriceData, getAllHistoricalPriceData, longTokens, shortTokens]);
|
|
8288
8160
|
// Aggregate loading across selected tokens via underlying hook
|
|
8289
8161
|
const isLoading = tokenLoading();
|
|
8290
8162
|
// Realtime listeners management
|
|
@@ -8330,37 +8202,31 @@ const useBasketCandles = () => {
|
|
|
8330
8202
|
// Compute weighted OHLC similar to computeBasketCandles
|
|
8331
8203
|
let longOpen = 1, longHigh = 1, longLow = 1, longClose = 1;
|
|
8332
8204
|
let shortOpen = 1, shortHigh = 1, shortLow = 1, shortClose = 1;
|
|
8333
|
-
let totalVolume = 0;
|
|
8334
|
-
let totalTrades = 0;
|
|
8335
8205
|
for (const token of longTokens) {
|
|
8336
8206
|
const c = snapshot[token.symbol];
|
|
8337
8207
|
if (!c)
|
|
8338
8208
|
return null;
|
|
8339
8209
|
const w = token.weight / 100;
|
|
8340
|
-
const o =
|
|
8210
|
+
const o = c.o, h = c.h, l = c.l, cl = c.c;
|
|
8341
8211
|
if (!(o > 0 && h > 0 && l > 0 && cl > 0))
|
|
8342
8212
|
return null;
|
|
8343
8213
|
longOpen *= Math.pow(o, w);
|
|
8344
8214
|
longHigh *= Math.pow(h, w);
|
|
8345
8215
|
longLow *= Math.pow(l, w);
|
|
8346
8216
|
longClose *= Math.pow(cl, w);
|
|
8347
|
-
totalVolume += parseFloat(c.v);
|
|
8348
|
-
totalTrades += c.n;
|
|
8349
8217
|
}
|
|
8350
8218
|
for (const token of shortTokens) {
|
|
8351
8219
|
const c = snapshot[token.symbol];
|
|
8352
8220
|
if (!c)
|
|
8353
8221
|
return null;
|
|
8354
8222
|
const w = -(token.weight / 100);
|
|
8355
|
-
const o =
|
|
8223
|
+
const o = c.o, h = c.h, l = c.l, cl = c.c;
|
|
8356
8224
|
if (!(o > 0 && h > 0 && l > 0 && cl > 0))
|
|
8357
8225
|
return null;
|
|
8358
8226
|
shortOpen *= Math.pow(o, w);
|
|
8359
8227
|
shortHigh *= Math.pow(h, w);
|
|
8360
8228
|
shortLow *= Math.pow(l, w);
|
|
8361
8229
|
shortClose *= Math.pow(cl, w);
|
|
8362
|
-
totalVolume += parseFloat(c.v);
|
|
8363
|
-
totalTrades += c.n;
|
|
8364
8230
|
}
|
|
8365
8231
|
if (t === null || T === null)
|
|
8366
8232
|
return null;
|
|
@@ -8371,8 +8237,6 @@ const useBasketCandles = () => {
|
|
|
8371
8237
|
h: longHigh * shortHigh,
|
|
8372
8238
|
l: longLow * shortLow,
|
|
8373
8239
|
c: longClose * shortClose,
|
|
8374
|
-
v: totalVolume,
|
|
8375
|
-
n: totalTrades,
|
|
8376
8240
|
};
|
|
8377
8241
|
return weighted;
|
|
8378
8242
|
}, [candleData, longTokens, shortTokens]);
|
|
@@ -8390,7 +8254,6 @@ const useBasketCandles = () => {
|
|
|
8390
8254
|
high: bar.h,
|
|
8391
8255
|
low: bar.l,
|
|
8392
8256
|
close: bar.c,
|
|
8393
|
-
volume: bar.v,
|
|
8394
8257
|
};
|
|
8395
8258
|
listenersRef.current.forEach((cb) => {
|
|
8396
8259
|
try {
|
|
@@ -8401,12 +8264,62 @@ const useBasketCandles = () => {
|
|
|
8401
8264
|
}, [computeRealtimeBar]);
|
|
8402
8265
|
return {
|
|
8403
8266
|
fetchBasketCandles,
|
|
8267
|
+
fetchPerformanceCandles,
|
|
8268
|
+
fetchOverallPerformanceCandles,
|
|
8404
8269
|
isLoading,
|
|
8405
8270
|
addRealtimeListener,
|
|
8406
8271
|
removeRealtimeListener,
|
|
8407
8272
|
};
|
|
8408
8273
|
};
|
|
8409
8274
|
|
|
8275
|
+
// Color palette for overlays
|
|
8276
|
+
const LONG_COLORS = [
|
|
8277
|
+
'#22C55E', '#16A34A', '#15803D', '#166534', '#14532D', // Green shades
|
|
8278
|
+
'#84CC16', '#65A30D', '#4D7C0F', '#365314', '#1A2E05' // Lime shades
|
|
8279
|
+
];
|
|
8280
|
+
const SHORT_COLORS = [
|
|
8281
|
+
'#EF4444', '#DC2626', '#B91C1C', '#991B1B', '#7F1D1D', // Red shades
|
|
8282
|
+
'#F97316', '#EA580C', '#C2410C', '#9A3412', '#7C2D12' // Orange/red shades
|
|
8283
|
+
];
|
|
8284
|
+
const usePerformanceOverlays = () => {
|
|
8285
|
+
const longTokens = useUserSelection$1((state) => state.longTokens);
|
|
8286
|
+
const shortTokens = useUserSelection$1((state) => state.shortTokens);
|
|
8287
|
+
// Generate performance overlays from current portfolio - all enabled by default
|
|
8288
|
+
const overlays = [
|
|
8289
|
+
...longTokens.map((token, index) => ({
|
|
8290
|
+
id: `perf_long_${token.symbol}`,
|
|
8291
|
+
symbol: `LONG ${token.symbol}`,
|
|
8292
|
+
label: `${token.symbol} (${token.weight}%)`,
|
|
8293
|
+
color: LONG_COLORS[index % LONG_COLORS.length], // Green shades for long positions
|
|
8294
|
+
enabled: true, // Always enabled
|
|
8295
|
+
type: 'asset',
|
|
8296
|
+
weight: token.weight,
|
|
8297
|
+
})),
|
|
8298
|
+
...shortTokens.map((token, index) => ({
|
|
8299
|
+
id: `perf_short_${token.symbol}`,
|
|
8300
|
+
symbol: `SHORT ${token.symbol}`,
|
|
8301
|
+
label: `${token.symbol} (-${token.weight}%)`,
|
|
8302
|
+
color: SHORT_COLORS[index % SHORT_COLORS.length], // Red shades for short positions
|
|
8303
|
+
enabled: true, // Always enabled
|
|
8304
|
+
type: 'asset',
|
|
8305
|
+
weight: -token.weight,
|
|
8306
|
+
}))
|
|
8307
|
+
];
|
|
8308
|
+
const generateOverlaySymbols = useCallback(() => {
|
|
8309
|
+
const symbols = [];
|
|
8310
|
+
// Always include all asset overlays
|
|
8311
|
+
overlays.forEach(overlay => {
|
|
8312
|
+
symbols.push(overlay.symbol);
|
|
8313
|
+
});
|
|
8314
|
+
console.log("final symbols", symbols);
|
|
8315
|
+
return symbols;
|
|
8316
|
+
}, [overlays]);
|
|
8317
|
+
return {
|
|
8318
|
+
overlays,
|
|
8319
|
+
generateOverlaySymbols,
|
|
8320
|
+
};
|
|
8321
|
+
};
|
|
8322
|
+
|
|
8410
8323
|
/**
|
|
8411
8324
|
* Detects conflicts between selected tokens and existing positions
|
|
8412
8325
|
*/
|
|
@@ -8494,4 +8407,4 @@ function mapCandleIntervalToTradingViewInterval(interval) {
|
|
|
8494
8407
|
}
|
|
8495
8408
|
}
|
|
8496
8409
|
|
|
8497
|
-
export { AccountSummaryCalculator, ConflictDetector, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, TokenMetadataExtractor, calculateWeightedRatio, computeBasketCandles, createCandleLookups, PearHyperliquidClient as default, getCompleteTimestamps, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, useAccountSummary, useAddress, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, useTokenSelectionMetadata, useTradeHistories, useUserSelection, useWebData };
|
|
8410
|
+
export { AccountSummaryCalculator, ConflictDetector, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, TokenMetadataExtractor, calculateWeightedRatio, computeBasketCandles, createCandleLookups, PearHyperliquidClient as default, getCompleteTimestamps, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, useAccountSummary, useAddress, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, usePerformanceOverlays, useTokenSelectionMetadata, useTradeHistories, useUserSelection, useWebData };
|
package/dist/types.d.ts
CHANGED
|
@@ -287,6 +287,7 @@ export interface PositionAssetDetailDto {
|
|
|
287
287
|
unrealizedPnl: number;
|
|
288
288
|
liquidationPrice: number;
|
|
289
289
|
isExternallyModified: boolean;
|
|
290
|
+
initialWeight: number;
|
|
290
291
|
}
|
|
291
292
|
/**
|
|
292
293
|
* Position sync status
|
|
@@ -620,16 +621,13 @@ export type CandleInterval = "1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" |
|
|
|
620
621
|
* Candle data structure from WebSocket
|
|
621
622
|
*/
|
|
622
623
|
export interface CandleData {
|
|
624
|
+
s?: string;
|
|
623
625
|
t: number;
|
|
624
626
|
T: number;
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
h: string;
|
|
630
|
-
l: string;
|
|
631
|
-
v: string;
|
|
632
|
-
n: number;
|
|
627
|
+
o: number;
|
|
628
|
+
c: number;
|
|
629
|
+
h: number;
|
|
630
|
+
l: number;
|
|
633
631
|
}
|
|
634
632
|
/**
|
|
635
633
|
* Candle chart data organized by symbol only
|
|
@@ -648,16 +646,3 @@ export interface CandleSnapshotRequest {
|
|
|
648
646
|
};
|
|
649
647
|
type: "candleSnapshot";
|
|
650
648
|
}
|
|
651
|
-
/**
|
|
652
|
-
* Weighted candle data for chart visualization
|
|
653
|
-
*/
|
|
654
|
-
export interface WeightedCandleData {
|
|
655
|
-
t: number;
|
|
656
|
-
T: number;
|
|
657
|
-
o: number;
|
|
658
|
-
c: number;
|
|
659
|
-
h: number;
|
|
660
|
-
l: number;
|
|
661
|
-
v: number;
|
|
662
|
-
n: number;
|
|
663
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CandleData, TokenSelection
|
|
1
|
+
import type { CandleData, TokenSelection } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Create efficient timestamp-based lookup maps for candle data
|
|
4
4
|
*/
|
|
@@ -21,4 +21,4 @@ export declare const getCompleteTimestamps: (candleLookups: Record<string, Map<n
|
|
|
21
21
|
* Compute basket candles from individual token candles using weighted ratios
|
|
22
22
|
* Optimized version that creates lookup maps once and reuses them
|
|
23
23
|
*/
|
|
24
|
-
export declare const computeBasketCandles: (longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>) =>
|
|
24
|
+
export declare const computeBasketCandles: (longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>) => CandleData[];
|
|
@@ -1,22 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare
|
|
3
|
-
private webData2;
|
|
4
|
-
private allMids;
|
|
5
|
-
constructor(webData2: WebData2Response | null, allMids: WsAllMidsData | null);
|
|
6
|
-
execute(rawPositions: RawPositionDto[]): OpenPositionDto[];
|
|
7
|
-
private getUserPositions;
|
|
8
|
-
private getMarketPrice;
|
|
9
|
-
private calculatePlatformTotalsByAsset;
|
|
10
|
-
private extractBaseCurrency;
|
|
11
|
-
private syncPositionWithAggregateData;
|
|
12
|
-
private determineSyncStatus;
|
|
13
|
-
private syncAssetWithAggregateData;
|
|
14
|
-
private mapPositionToDtoWithSyncData;
|
|
15
|
-
private mapAssetToDetailDto;
|
|
16
|
-
private calculateEntryRatio;
|
|
17
|
-
private calculateMarkRatio;
|
|
18
|
-
private calculateNetFundingFromSyncResults;
|
|
19
|
-
private calculateTotalUnrealizedPnlFromSyncResults;
|
|
20
|
-
private calculateCurrentTotalPositionValue;
|
|
21
|
-
private calculateEntryTotalPositionValue;
|
|
22
|
-
}
|
|
1
|
+
import { OpenPositionDto, RawPositionDto, WebData2Response, WsAllMidsData } from "../types";
|
|
2
|
+
export declare const buildPositionValue: (rawPositions: RawPositionDto[], webData2: WebData2Response, allMids: WsAllMidsData) => OpenPositionDto[];
|