@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.
@@ -5,3 +5,4 @@ export * from './useWebData';
5
5
  export * from './useTokenSelectionMetadata';
6
6
  export * from './useHistoricalPriceData';
7
7
  export * from './useBasketCandles';
8
+ export * from './usePerformanceOverlays';
@@ -1,6 +1,8 @@
1
- import type { CandleInterval, WeightedCandleData } from '../types';
1
+ import type { CandleData, CandleInterval } from '../types';
2
2
  export interface UseBasketCandlesReturn {
3
- fetchBasketCandles: (startTime: number, endTime: number, interval: CandleInterval) => Promise<WeightedCandleData[]>;
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
- s: string;
621
- i: string;
622
- o: string;
623
- c: string;
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<WeightedCandleData[]>;
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[]>) => WeightedCandleData[];
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
- interface HistoricalRange {
1042
- start: number;
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
- var PositionSide;
7180
- (function (PositionSide) {
7181
- PositionSide["LONG"] = "LONG";
7182
- PositionSide["SHORT"] = "SHORT";
7183
- })(PositionSide || (PositionSide = {}));
7184
- class PositionProcessor {
7185
- constructor(webData2, allMids) {
7186
- this.webData2 = webData2;
7187
- this.allMids = allMids;
7188
- }
7189
- execute(rawPositions) {
7190
- if (!rawPositions || rawPositions.length === 0) {
7191
- return [];
7192
- }
7193
- const userHyperliquidPositions = this.getUserPositions();
7194
- const platformTotalsByAsset = this.calculatePlatformTotalsByAsset(rawPositions);
7195
- const hlPositionsMap = new Map();
7196
- (userHyperliquidPositions || []).forEach(assetPos => {
7197
- var _a;
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
- const hlTotalSize = Math.abs(Number(hlPosition.position.szi || 0));
7345
- const totalDifference = Math.abs(hlTotalSize - platformTotal);
7346
- const tolerance = platformTotal * 0.001;
7347
- const isExternallyModified = totalDifference > tolerance;
7348
- const proportion = platformTotal > 0 ? platformSize / platformTotal : 0;
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
- stopLoss: position.stopLoss,
7385
- takeProfit: position.takeProfit,
7386
- entryRatio: this.calculateEntryRatio(syncResults),
7387
- markRatio: this.calculateMarkRatio(syncResults),
7388
- netFunding: this.calculateNetFundingFromSyncResults(syncResults),
7389
- positionValue: currentTotalPositionValue,
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
- calculateEntryRatio(syncResults) {
7422
- var _a, _b;
7423
- const longResults = syncResults.filter(result => result.asset.side === PositionSide.LONG);
7424
- const shortResults = syncResults.filter(result => result.asset.side === PositionSide.SHORT);
7425
- if (longResults.length === 0 || shortResults.length === 0)
7426
- return 0;
7427
- const longEntryPrice = ((_a = longResults[0]) === null || _a === void 0 ? void 0 : _a.asset.entryPrice) ? Number(longResults[0].asset.entryPrice) : 0;
7428
- const shortEntryPrice = ((_b = shortResults[0]) === null || _b === void 0 ? void 0 : _b.asset.entryPrice) ? Number(shortResults[0].asset.entryPrice) : 0;
7429
- return shortEntryPrice > 0 ? longEntryPrice / shortEntryPrice : 0;
7430
- }
7431
- calculateMarkRatio(syncResults) {
7432
- var _a, _b;
7433
- const longResults = syncResults.filter(result => result.asset.side === PositionSide.LONG);
7434
- const shortResults = syncResults.filter(result => result.asset.side === PositionSide.SHORT);
7435
- if (longResults.length === 0 || shortResults.length === 0)
7436
- return 0;
7437
- const longMarkPrice = ((_a = longResults[0]) === null || _a === void 0 ? void 0 : _a.asset.coin) ? this.getMarketPrice(longResults[0].asset.coin) : 0;
7438
- const shortMarkPrice = ((_b = shortResults[0]) === null || _b === void 0 ? void 0 : _b.asset.coin) ? this.getMarketPrice(shortResults[0].asset.coin) : 0;
7439
- return shortMarkPrice > 0 ? longMarkPrice / shortMarkPrice : 0;
7440
- }
7441
- calculateNetFundingFromSyncResults(syncResults) {
7442
- const netFunding = syncResults.reduce((sum, result) => {
7443
- const funding = result.cumFunding.sinceOpen;
7444
- return sum + funding;
7445
- }, 0);
7446
- return netFunding;
7447
- }
7448
- calculateTotalUnrealizedPnlFromSyncResults(syncResults) {
7449
- return syncResults.reduce((sum, result) => sum + result.unrealizedPnl, 0);
7450
- }
7451
- calculateCurrentTotalPositionValue(syncResults) {
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 processor = new PositionProcessor(webData2, allMids);
7493
- const processed = processor.execute(userOpenPositions);
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 = parseFloat(candle[priceType]);
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 = parseFloat(candle[priceType]);
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 = parseFloat(candle.o);
8213
- const h = parseFloat(candle.h);
8214
- const l = parseFloat(candle.l);
8215
- const c = parseFloat(candle.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 = parseFloat(candle.o);
8240
- const h = parseFloat(candle.h);
8241
- const l = parseFloat(candle.l);
8242
- const c = parseFloat(candle.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 = parseFloat(c.o), h = parseFloat(c.h), l = parseFloat(c.l), cl = parseFloat(c.c);
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 = parseFloat(c.o), h = parseFloat(c.h), l = parseFloat(c.l), cl = parseFloat(c.c);
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
- s: string;
626
- i: string;
627
- o: string;
628
- c: string;
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, WeightedCandleData } from '../types';
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[]>) => WeightedCandleData[];
24
+ export declare const computeBasketCandles: (longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>) => CandleData[];
@@ -1,22 +1,2 @@
1
- import type { OpenPositionDto, WebData2Response, WsAllMidsData, RawPositionDto } from '../types';
2
- export declare class PositionProcessor {
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[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/hyperliquid-sdk",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "description": "React SDK for Pear Protocol Hyperliquid API integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",