@pear-protocol/hyperliquid-sdk 0.1.22-beta → 0.1.22-pnl

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.
@@ -0,0 +1,7 @@
1
+ import type { ApiResponse, TradeHistoryDataDto } from '../types';
2
+ export interface GetTradeHistoryParams {
3
+ startDate?: string;
4
+ endDate?: string;
5
+ limit?: number;
6
+ }
7
+ export declare function getTradeHistory(baseUrl: string, params?: GetTradeHistoryParams): Promise<ApiResponse<TradeHistoryDataDto[]>>;
@@ -18,3 +18,5 @@ export * from './usePortfolio';
18
18
  export * from './useAuth';
19
19
  export * from './useAllUserBalances';
20
20
  export * from './useHyperliquidUserFills';
21
+ export * from './usePnlCalendar';
22
+ export * from './usePnlHeatmap';
@@ -0,0 +1,61 @@
1
+ export type PnlCalendarTimeframe = '2W' | '3W' | '2M' | '3M';
2
+ export interface PnlCalendarOptions {
3
+ timeframe?: PnlCalendarTimeframe;
4
+ startDate?: Date | string;
5
+ endDate?: Date | string;
6
+ }
7
+ export interface PnlCalendarAsset {
8
+ coin: string;
9
+ symbol: string;
10
+ assetName: string;
11
+ marketPrefix: string;
12
+ percentage: number;
13
+ collateralToken: string;
14
+ }
15
+ export interface PnlCalendarTrade {
16
+ tradeHistoryId: string;
17
+ realizedPnl: number;
18
+ result: 'profit' | 'loss' | 'breakeven';
19
+ collateralTypes: string[];
20
+ closedLongAssets: PnlCalendarAsset[];
21
+ closedShortAssets: PnlCalendarAsset[];
22
+ }
23
+ export interface PnlCalendarDay {
24
+ date: string;
25
+ totalPnl: number;
26
+ volume: number;
27
+ positionsClosed: number;
28
+ result: 'profit' | 'loss' | 'breakeven';
29
+ trades: PnlCalendarTrade[];
30
+ }
31
+ export interface PeriodSummary {
32
+ pnl: number;
33
+ volume: number;
34
+ winRate: number;
35
+ wins: number;
36
+ losses: number;
37
+ totalProfit: number;
38
+ totalLoss: number;
39
+ }
40
+ export interface PnlCalendarWeek {
41
+ weekStart: string;
42
+ weekEnd: string;
43
+ days: PnlCalendarDay[];
44
+ summary: PeriodSummary;
45
+ }
46
+ export interface PnlCalendarMonth {
47
+ month: string;
48
+ label: string;
49
+ days: PnlCalendarDay[];
50
+ summary: PeriodSummary;
51
+ }
52
+ export interface UsePnlCalendarResult {
53
+ timeframe: PnlCalendarTimeframe;
54
+ weeks: PnlCalendarWeek[];
55
+ months: PnlCalendarMonth[];
56
+ overall: PeriodSummary;
57
+ isLoading: boolean;
58
+ error: string | null;
59
+ refetch: () => void;
60
+ }
61
+ export declare function usePnlCalendar(options?: PnlCalendarTimeframe | PnlCalendarOptions): UsePnlCalendarResult;
@@ -0,0 +1,13 @@
1
+ import type { PnlCalendarTrade } from './usePnlCalendar';
2
+ export type PnlHeatmapTimeframe = 'allTime' | '100D' | '30D' | '7D';
3
+ export interface PnlHeatmapTrade extends PnlCalendarTrade {
4
+ percentage: number;
5
+ }
6
+ export interface UsePnlHeatmapResult {
7
+ timeframe: PnlHeatmapTimeframe;
8
+ trades: PnlHeatmapTrade[];
9
+ isLoading: boolean;
10
+ error: string | null;
11
+ refetch: () => void;
12
+ }
13
+ export declare function usePnlHeatmap(timeframe?: PnlHeatmapTimeframe): UsePnlHeatmapResult;
package/dist/index.d.ts CHANGED
@@ -1512,6 +1512,81 @@ interface UseHyperliquidUserFillsState {
1512
1512
  */
1513
1513
  declare function useHyperliquidUserFills(options: UseHyperliquidUserFillsOptions): UseHyperliquidUserFillsState;
1514
1514
 
1515
+ type PnlCalendarTimeframe = '2W' | '3W' | '2M' | '3M';
1516
+ interface PnlCalendarOptions {
1517
+ timeframe?: PnlCalendarTimeframe;
1518
+ startDate?: Date | string;
1519
+ endDate?: Date | string;
1520
+ }
1521
+ interface PnlCalendarAsset {
1522
+ coin: string;
1523
+ symbol: string;
1524
+ assetName: string;
1525
+ marketPrefix: string;
1526
+ percentage: number;
1527
+ collateralToken: string;
1528
+ }
1529
+ interface PnlCalendarTrade {
1530
+ tradeHistoryId: string;
1531
+ realizedPnl: number;
1532
+ result: 'profit' | 'loss' | 'breakeven';
1533
+ collateralTypes: string[];
1534
+ closedLongAssets: PnlCalendarAsset[];
1535
+ closedShortAssets: PnlCalendarAsset[];
1536
+ }
1537
+ interface PnlCalendarDay {
1538
+ date: string;
1539
+ totalPnl: number;
1540
+ volume: number;
1541
+ positionsClosed: number;
1542
+ result: 'profit' | 'loss' | 'breakeven';
1543
+ trades: PnlCalendarTrade[];
1544
+ }
1545
+ interface PeriodSummary {
1546
+ pnl: number;
1547
+ volume: number;
1548
+ winRate: number;
1549
+ wins: number;
1550
+ losses: number;
1551
+ totalProfit: number;
1552
+ totalLoss: number;
1553
+ }
1554
+ interface PnlCalendarWeek {
1555
+ weekStart: string;
1556
+ weekEnd: string;
1557
+ days: PnlCalendarDay[];
1558
+ summary: PeriodSummary;
1559
+ }
1560
+ interface PnlCalendarMonth {
1561
+ month: string;
1562
+ label: string;
1563
+ days: PnlCalendarDay[];
1564
+ summary: PeriodSummary;
1565
+ }
1566
+ interface UsePnlCalendarResult {
1567
+ timeframe: PnlCalendarTimeframe;
1568
+ weeks: PnlCalendarWeek[];
1569
+ months: PnlCalendarMonth[];
1570
+ overall: PeriodSummary;
1571
+ isLoading: boolean;
1572
+ error: string | null;
1573
+ refetch: () => void;
1574
+ }
1575
+ declare function usePnlCalendar(options?: PnlCalendarTimeframe | PnlCalendarOptions): UsePnlCalendarResult;
1576
+
1577
+ type PnlHeatmapTimeframe = 'allTime' | '100D' | '30D' | '7D';
1578
+ interface PnlHeatmapTrade extends PnlCalendarTrade {
1579
+ percentage: number;
1580
+ }
1581
+ interface UsePnlHeatmapResult {
1582
+ timeframe: PnlHeatmapTimeframe;
1583
+ trades: PnlHeatmapTrade[];
1584
+ isLoading: boolean;
1585
+ error: string | null;
1586
+ refetch: () => void;
1587
+ }
1588
+ declare function usePnlHeatmap(timeframe?: PnlHeatmapTimeframe): UsePnlHeatmapResult;
1589
+
1515
1590
  /**
1516
1591
  * Mark notifications as read up to a given timestamp (ms)
1517
1592
  */
@@ -1799,5 +1874,5 @@ interface MarketDataState {
1799
1874
  }
1800
1875
  declare const useMarketData: zustand.UseBoundStore<zustand.StoreApi<MarketDataState>>;
1801
1876
 
1802
- export { ClosePositionValidationError, ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, ReadyState, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, executeSpotOrder, getCompleteTimestamps, getKalshiMarkets, getOrderDirection, getOrderLadderConfig, getOrderLeverage, getOrderReduceOnly, getOrderTpSlTriggerType, getOrderTrailingInfo, getOrderTriggerType, getOrderTriggerValue, getOrderTwapDuration, getOrderUsdValue, getPortfolio, isBtcDomOrder, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useAgentWallet, useAllUserBalances, useAuth, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidUserFills, useMarket, useMarketData, useMarketDataHook, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTradeHistories, useTwap, useUserSelection, useWatchlist, validateClosePositionRequest, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
1803
- export type { AccountSummaryResponseDto, ActiveAssetData, ActiveAssetGroupItem, ActiveAssetsAllResponse, ActiveAssetsResponse, AddressState, AdjustAdvanceAssetInput, AdjustAdvanceItemInput, AdjustAdvanceResponseDto, AdjustExecutionType, AdjustOrderRequestInput, AdjustOrderResponseDto, AdjustPositionRequestInput, AdjustPositionResponseDto, AgentWalletDto, AgentWalletState, AgentWalletStatus, AllDexsAssetCtxsData, AllDexsClearinghouseStateData, AllPerpMetasItem, AllPerpMetasResponse, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetMarketData, AssetPosition, AuthenticateRequest, AuthenticateResponse, AvailableToTrades, BalanceSummaryDto, BaseTriggerOrderNotificationParams, BtcDomTriggerParams, CancelOrderResponseDto, CancelTwapResponseDto, CandleChartData, CandleData, CandleInterval, CandleSnapshotRequest, ChunkFillDto, ClearinghouseState, CloseAllExecutionType, CloseAllPositionsRequestInput, CloseAllPositionsResponseDto, CloseAllPositionsResultDto, CloseExecutionType, ClosePositionExecutionType, ClosePositionRequestInput, ClosePositionResponseDto, CloseTriggerType, CollateralToken, CreateAgentWalletResponseDto, CreatePositionRequestInput, CreatePositionResponseDto, CrossAssetPriceTriggerParams, CrossMarginSummaryDto, CumFundingDto, EIP712AuthDetails, ExecutionType, ExternalFillDto, ExternalLiquidationDto, ExtraAgent, GetAgentWalletResponseDto, GetEIP712MessageResponse, GetKalshiMarketsParams, HLChannel, HLChannelDataMap, HLWebSocketResponse, HistoricalRange, KalshiMarket, KalshiMarketsResponse, KalshiMveLeg, KalshiPriceRange, LadderConfigInput, LadderOrderParameters, LeverageInfo, LogoutRequest, LogoutResponse, MarginRequiredPerCollateral, MarginRequiredResult, MarginSummaryDto, MarginTableDef, MarginTablesEntry, MarginTier, MarketOrderParameters, NotificationCategory, NotificationDto, OpenLimitOrderDto, OpenPositionDto, OrderAssetDto, OrderDirection, OrderParameters, OrderStatus, OrderType, PairAssetDto, PairAssetInput, PerformanceOverlay, PerpDex, PerpDexsResponse, PerpMetaAsset, PlatformAccountSummaryResponseDto, PortfolioBucketDto, PortfolioInterval, PortfolioIntervalsDto, PortfolioOverallDto, PortfolioResponseDto, PositionAdjustmentType, PositionAssetDetailDto, PredictionMarketOutcomeTriggerParams, PriceRatioTriggerParams, PriceTriggerParams, PrivyAuthDetails, RawAssetDto, RawPositionDto, RealtimeBar, RealtimeBarsCallback, RebalanceAssetPlan, RebalancePlan, RefreshTokenRequest, RefreshTokenResponse, SpotBalance, SpotBalances, SpotOrderFilledStatus, SpotOrderHyperliquidData, SpotOrderHyperliquidResult, SpotOrderRequestInput, SpotOrderResponseDto, SpotState, SyncFillsRequestDto, SyncFillsResponseDto, ToggleWatchlistResponseDto, TokenConflict, TokenEntry, TokenHistoricalPriceData, TokenMetadata, TokenSelection, TokenSelectorConfig, TpSlOrderParameters, TpSlThreshold, TpSlThresholdInput, TpSlThresholdType, TpSlTriggerType, TradeHistoryAssetDataDto, TradeHistoryDataDto, TriggerOrderNotificationAsset, TriggerOrderNotificationParams, TriggerOrderNotificationType, TriggerOrderParameters, TriggerType, TwapChunkStatus, TwapChunkStatusDto, TwapMonitoringDto, TwapOrderOverallStatus, TwapOrderParameters, TwapSliceFillResponseItem, UniverseAsset, UpdateLeverageRequestInput, UpdateLeverageResponseDto, UpdateRiskParametersRequestInput, UpdateRiskParametersResponseDto, UseAuthOptions, UseBasketCandlesReturn, UseHistoricalPriceDataReturn, UseHyperliquidUserFillsOptions, UseHyperliquidUserFillsState, UseNotificationsResult, UsePerformanceOverlaysReturn, UsePortfolioResult, UseSpotOrderResult, UseTokenSelectionMetadataReturn, UserAbstraction, UserProfile, UserSelectionState, WatchlistAssetDto, WatchlistItemDto, WebData3AssetCtx, WebData3PerpDexState, WebData3Response, WebData3UserState, WebSocketAckResponse, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketSubscribeMessage, WsAllMidsData };
1877
+ export { ClosePositionValidationError, ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, ReadyState, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, executeSpotOrder, getCompleteTimestamps, getKalshiMarkets, getOrderDirection, getOrderLadderConfig, getOrderLeverage, getOrderReduceOnly, getOrderTpSlTriggerType, getOrderTrailingInfo, getOrderTriggerType, getOrderTriggerValue, getOrderTwapDuration, getOrderUsdValue, getPortfolio, isBtcDomOrder, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useAgentWallet, useAllUserBalances, useAuth, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidUserFills, useMarket, useMarketData, useMarketDataHook, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePnlCalendar, usePnlHeatmap, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTradeHistories, useTwap, useUserSelection, useWatchlist, validateClosePositionRequest, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
1878
+ export type { AccountSummaryResponseDto, ActiveAssetData, ActiveAssetGroupItem, ActiveAssetsAllResponse, ActiveAssetsResponse, AddressState, AdjustAdvanceAssetInput, AdjustAdvanceItemInput, AdjustAdvanceResponseDto, AdjustExecutionType, AdjustOrderRequestInput, AdjustOrderResponseDto, AdjustPositionRequestInput, AdjustPositionResponseDto, AgentWalletDto, AgentWalletState, AgentWalletStatus, AllDexsAssetCtxsData, AllDexsClearinghouseStateData, AllPerpMetasItem, AllPerpMetasResponse, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetMarketData, AssetPosition, AuthenticateRequest, AuthenticateResponse, AvailableToTrades, BalanceSummaryDto, BaseTriggerOrderNotificationParams, BtcDomTriggerParams, CancelOrderResponseDto, CancelTwapResponseDto, CandleChartData, CandleData, CandleInterval, CandleSnapshotRequest, ChunkFillDto, ClearinghouseState, CloseAllExecutionType, CloseAllPositionsRequestInput, CloseAllPositionsResponseDto, CloseAllPositionsResultDto, CloseExecutionType, ClosePositionExecutionType, ClosePositionRequestInput, ClosePositionResponseDto, CloseTriggerType, CollateralToken, CreateAgentWalletResponseDto, CreatePositionRequestInput, CreatePositionResponseDto, CrossAssetPriceTriggerParams, CrossMarginSummaryDto, CumFundingDto, EIP712AuthDetails, ExecutionType, ExternalFillDto, ExternalLiquidationDto, ExtraAgent, GetAgentWalletResponseDto, GetEIP712MessageResponse, GetKalshiMarketsParams, HLChannel, HLChannelDataMap, HLWebSocketResponse, HistoricalRange, KalshiMarket, KalshiMarketsResponse, KalshiMveLeg, KalshiPriceRange, LadderConfigInput, LadderOrderParameters, LeverageInfo, LogoutRequest, LogoutResponse, MarginRequiredPerCollateral, MarginRequiredResult, MarginSummaryDto, MarginTableDef, MarginTablesEntry, MarginTier, MarketOrderParameters, NotificationCategory, NotificationDto, OpenLimitOrderDto, OpenPositionDto, OrderAssetDto, OrderDirection, OrderParameters, OrderStatus, OrderType, PairAssetDto, PairAssetInput, PerformanceOverlay, PeriodSummary, PerpDex, PerpDexsResponse, PerpMetaAsset, PlatformAccountSummaryResponseDto, PnlCalendarAsset, PnlCalendarDay, PnlCalendarMonth, PnlCalendarOptions, PnlCalendarTimeframe, PnlCalendarTrade, PnlCalendarWeek, PnlHeatmapTimeframe, PnlHeatmapTrade, PortfolioBucketDto, PortfolioInterval, PortfolioIntervalsDto, PortfolioOverallDto, PortfolioResponseDto, PositionAdjustmentType, PositionAssetDetailDto, PredictionMarketOutcomeTriggerParams, PriceRatioTriggerParams, PriceTriggerParams, PrivyAuthDetails, RawAssetDto, RawPositionDto, RealtimeBar, RealtimeBarsCallback, RebalanceAssetPlan, RebalancePlan, RefreshTokenRequest, RefreshTokenResponse, SpotBalance, SpotBalances, SpotOrderFilledStatus, SpotOrderHyperliquidData, SpotOrderHyperliquidResult, SpotOrderRequestInput, SpotOrderResponseDto, SpotState, SyncFillsRequestDto, SyncFillsResponseDto, ToggleWatchlistResponseDto, TokenConflict, TokenEntry, TokenHistoricalPriceData, TokenMetadata, TokenSelection, TokenSelectorConfig, TpSlOrderParameters, TpSlThreshold, TpSlThresholdInput, TpSlThresholdType, TpSlTriggerType, TradeHistoryAssetDataDto, TradeHistoryDataDto, TriggerOrderNotificationAsset, TriggerOrderNotificationParams, TriggerOrderNotificationType, TriggerOrderParameters, TriggerType, TwapChunkStatus, TwapChunkStatusDto, TwapMonitoringDto, TwapOrderOverallStatus, TwapOrderParameters, TwapSliceFillResponseItem, UniverseAsset, UpdateLeverageRequestInput, UpdateLeverageResponseDto, UpdateRiskParametersRequestInput, UpdateRiskParametersResponseDto, UseAuthOptions, UseBasketCandlesReturn, UseHistoricalPriceDataReturn, UseHyperliquidUserFillsOptions, UseHyperliquidUserFillsState, UseNotificationsResult, UsePerformanceOverlaysReturn, UsePnlCalendarResult, UsePnlHeatmapResult, UsePortfolioResult, UseSpotOrderResult, UseTokenSelectionMetadataReturn, UserAbstraction, UserProfile, UserSelectionState, WatchlistAssetDto, WatchlistItemDto, WebData3AssetCtx, WebData3PerpDexState, WebData3Response, WebData3UserState, WebSocketAckResponse, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketSubscribeMessage, WsAllMidsData };
package/dist/index.js CHANGED
@@ -471,11 +471,9 @@ const applyOiCapsToMetadataMap = (tokenMetadata, finalAtOICaps) => {
471
471
  });
472
472
  return next;
473
473
  };
474
- const shouldSkipToken = (asset, oiCapSet) => {
474
+ const shouldSkipToken = (asset) => {
475
475
  if (asset.isDelisted)
476
476
  return true;
477
- if (isAtOiCaps(asset.name, oiCapSet))
478
- return true;
479
477
  return false;
480
478
  };
481
479
  const buildTokenMetadataMap = ({ perpMetasByDex, assetContextsByDex, allMids, activeAssetData, finalAtOICaps, }) => {
@@ -487,7 +485,7 @@ const buildTokenMetadataMap = ({ perpMetasByDex, assetContextsByDex, allMids, ac
487
485
  // Iterate through all DEXes and their assets
488
486
  for (const [, assets] of perpMetasByDex) {
489
487
  for (const asset of assets) {
490
- if (shouldSkipToken(asset, oiCapSet)) {
488
+ if (shouldSkipToken(asset)) {
491
489
  continue;
492
490
  }
493
491
  const symbol = asset.name;
@@ -511,7 +509,7 @@ const updateTokenMetadataForSymbols = (prev, symbols, { perpMetasByDex, assetCon
511
509
  if (foundAsset)
512
510
  break;
513
511
  }
514
- if (foundAsset && shouldSkipToken(foundAsset, oiCapSet)) {
512
+ if (foundAsset && shouldSkipToken(foundAsset)) {
515
513
  delete next[symbol];
516
514
  return;
517
515
  }
@@ -8476,6 +8474,456 @@ function useHyperliquidUserFills(options) {
8476
8474
  };
8477
8475
  }
8478
8476
 
8477
+ async function getTradeHistory(baseUrl, params) {
8478
+ const url = joinUrl(baseUrl, '/trade-history');
8479
+ try {
8480
+ const resp = await apiClient.get(url, {
8481
+ params,
8482
+ timeout: 60000,
8483
+ });
8484
+ return { data: resp.data, status: resp.status, headers: resp.headers };
8485
+ }
8486
+ catch (error) {
8487
+ throw toApiError(error);
8488
+ }
8489
+ }
8490
+
8491
+ // ─── helpers ────────────────────────────────────────────────────
8492
+ const EMPTY_SUMMARY = {
8493
+ pnl: 0,
8494
+ volume: 0,
8495
+ winRate: 0,
8496
+ wins: 0,
8497
+ losses: 0,
8498
+ totalProfit: 0,
8499
+ totalLoss: 0,
8500
+ };
8501
+ const getTimeframeDays$1 = (tf) => {
8502
+ switch (tf) {
8503
+ case '2W':
8504
+ return 14;
8505
+ case '3W':
8506
+ return 21;
8507
+ case '2M':
8508
+ return 60;
8509
+ case '3M':
8510
+ return 90;
8511
+ }
8512
+ };
8513
+ const isWeekTimeframe = (tf) => tf === '2W' || tf === '3W';
8514
+ const toDateKey = (date) => {
8515
+ const y = date.getFullYear();
8516
+ const m = String(date.getMonth() + 1).padStart(2, '0');
8517
+ const d = String(date.getDate()).padStart(2, '0');
8518
+ return `${y}-${m}-${d}`;
8519
+ };
8520
+ const toMonthKey = (date) => {
8521
+ const y = date.getFullYear();
8522
+ const m = String(date.getMonth() + 1).padStart(2, '0');
8523
+ return `${y}-${m}`;
8524
+ };
8525
+ const formatMonthLabel = (date) => date.toLocaleDateString('en-US', { month: 'short', year: 'numeric' });
8526
+ const getMonday = (date) => {
8527
+ const d = new Date(date);
8528
+ const day = d.getDay(); // 0=Sun … 6=Sat
8529
+ const diff = day === 0 ? -6 : 1 - day;
8530
+ d.setDate(d.getDate() + diff);
8531
+ d.setHours(0, 0, 0, 0);
8532
+ return d;
8533
+ };
8534
+ const toLocalMidnight = (input) => {
8535
+ const d = typeof input === 'string' ? new Date(input + 'T00:00:00') : new Date(input);
8536
+ d.setHours(0, 0, 0, 0);
8537
+ return d;
8538
+ };
8539
+ const diffDays = (start, end) => {
8540
+ return Math.round((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1;
8541
+ };
8542
+ const toISODateString$1 = (input) => {
8543
+ const d = typeof input === 'string' ? new Date(input + 'T00:00:00') : new Date(input);
8544
+ return d.toISOString();
8545
+ };
8546
+ const round2 = (n) => Math.round(n * 100) / 100;
8547
+ const mapAsset$1 = (asset, getAssetByName) => {
8548
+ var _a, _b, _c, _d;
8549
+ const metadata = getAssetByName(asset.coin);
8550
+ const marketInfo = getMarketInfoFromSymbol(asset.coin);
8551
+ return {
8552
+ coin: asset.coin,
8553
+ symbol: (_a = metadata === null || metadata === void 0 ? void 0 : metadata.symbolName) !== null && _a !== void 0 ? _a : marketInfo.symbolName,
8554
+ assetName: (_b = metadata === null || metadata === void 0 ? void 0 : metadata.assetName) !== null && _b !== void 0 ? _b : asset.coin,
8555
+ marketPrefix: (_c = metadata === null || metadata === void 0 ? void 0 : metadata.marketName) !== null && _c !== void 0 ? _c : marketInfo.marketName,
8556
+ percentage: asset.closeWeight * 100,
8557
+ collateralToken: (_d = metadata === null || metadata === void 0 ? void 0 : metadata.collateralToken) !== null && _d !== void 0 ? _d : 'USDC',
8558
+ };
8559
+ };
8560
+ const getCollateralTypes$1 = (assets) => {
8561
+ const set = new Set();
8562
+ for (const a of assets)
8563
+ set.add(a.collateralToken);
8564
+ return set.size > 0 ? Array.from(set) : ['USDC'];
8565
+ };
8566
+ const buildSummary = (days) => {
8567
+ let pnl = 0;
8568
+ let volume = 0;
8569
+ let wins = 0;
8570
+ let losses = 0;
8571
+ let totalProfit = 0;
8572
+ let totalLoss = 0;
8573
+ for (const day of days) {
8574
+ pnl += day.totalPnl;
8575
+ volume += day.volume;
8576
+ if (day.positionsClosed === 0)
8577
+ continue;
8578
+ if (day.totalPnl > 0) {
8579
+ wins++;
8580
+ totalProfit += day.totalPnl;
8581
+ }
8582
+ else if (day.totalPnl < 0) {
8583
+ losses++;
8584
+ totalLoss += Math.abs(day.totalPnl);
8585
+ }
8586
+ }
8587
+ const total = wins + losses;
8588
+ const winRate = total > 0 ? Math.round((wins / total) * 100) : 0;
8589
+ return {
8590
+ pnl: round2(pnl),
8591
+ volume: round2(volume),
8592
+ winRate,
8593
+ wins,
8594
+ losses,
8595
+ totalProfit: round2(totalProfit),
8596
+ totalLoss: round2(totalLoss),
8597
+ };
8598
+ };
8599
+ const buildCalendarData = (tradeHistories, timeframe, rangeStart, rangeEnd, totalDays, useCustomDates, getAssetByName) => {
8600
+ const startKey = toDateKey(rangeStart);
8601
+ const endKey = toDateKey(rangeEnd);
8602
+ // Build day buckets for the full range
8603
+ const buckets = new Map();
8604
+ for (let i = 0; i < totalDays; i++) {
8605
+ const d = new Date(rangeStart);
8606
+ d.setDate(rangeStart.getDate() + i);
8607
+ buckets.set(toDateKey(d), {
8608
+ pnl: 0,
8609
+ volume: 0,
8610
+ positionsClosed: 0,
8611
+ trades: [],
8612
+ });
8613
+ }
8614
+ // Populate buckets from trade histories
8615
+ for (const trade of tradeHistories) {
8616
+ if (!trade.createdAt)
8617
+ continue;
8618
+ const date = new Date(trade.createdAt);
8619
+ if (isNaN(date.getTime()))
8620
+ continue;
8621
+ const dateKey = toDateKey(date);
8622
+ if (dateKey < startKey || dateKey > endKey)
8623
+ continue;
8624
+ const bucket = buckets.get(dateKey);
8625
+ if (!bucket)
8626
+ continue;
8627
+ const pnl = trade.realizedPnl;
8628
+ bucket.pnl += isFinite(pnl) ? pnl : 0;
8629
+ const vol = trade.totalValue;
8630
+ bucket.volume += isFinite(vol) ? vol : 0;
8631
+ bucket.positionsClosed += 1;
8632
+ const tradePnl = trade.realizedPnl;
8633
+ const longAssets = trade.closedLongAssets.map((a) => mapAsset$1(a, getAssetByName));
8634
+ const shortAssets = trade.closedShortAssets.map((a) => mapAsset$1(a, getAssetByName));
8635
+ bucket.trades.push({
8636
+ tradeHistoryId: trade.tradeHistoryId,
8637
+ realizedPnl: tradePnl,
8638
+ result: tradePnl > 0 ? 'profit' : tradePnl < 0 ? 'loss' : 'breakeven',
8639
+ collateralTypes: getCollateralTypes$1([...longAssets, ...shortAssets]),
8640
+ closedLongAssets: longAssets,
8641
+ closedShortAssets: shortAssets,
8642
+ });
8643
+ }
8644
+ // Build day objects
8645
+ const allDays = [];
8646
+ const sortedKeys = Array.from(buckets.keys()).sort();
8647
+ for (const key of sortedKeys) {
8648
+ const bucket = buckets.get(key);
8649
+ const roundedPnl = round2(bucket.pnl);
8650
+ const result = roundedPnl > 0 ? 'profit' : roundedPnl < 0 ? 'loss' : 'breakeven';
8651
+ allDays.push({
8652
+ date: key,
8653
+ totalPnl: roundedPnl,
8654
+ volume: round2(bucket.volume),
8655
+ positionsClosed: bucket.positionsClosed,
8656
+ result,
8657
+ trades: bucket.trades,
8658
+ });
8659
+ }
8660
+ // Group into periods
8661
+ let weeks = [];
8662
+ let months = [];
8663
+ const useWeekGrouping = useCustomDates
8664
+ ? totalDays <= 28
8665
+ : isWeekTimeframe(timeframe);
8666
+ if (useWeekGrouping) {
8667
+ const weekMap = new Map();
8668
+ for (const day of allDays) {
8669
+ const date = new Date(day.date + 'T00:00:00');
8670
+ const monday = getMonday(date);
8671
+ const mondayKey = toDateKey(monday);
8672
+ if (!weekMap.has(mondayKey)) {
8673
+ weekMap.set(mondayKey, []);
8674
+ }
8675
+ weekMap.get(mondayKey).push(day);
8676
+ }
8677
+ const sortedWeekKeys = Array.from(weekMap.keys()).sort();
8678
+ weeks = sortedWeekKeys.map((mondayKey) => {
8679
+ const days = weekMap.get(mondayKey);
8680
+ const monday = new Date(mondayKey + 'T00:00:00');
8681
+ const sunday = new Date(monday);
8682
+ sunday.setDate(monday.getDate() + 6);
8683
+ return {
8684
+ weekStart: mondayKey,
8685
+ weekEnd: toDateKey(sunday),
8686
+ days,
8687
+ summary: buildSummary(days),
8688
+ };
8689
+ });
8690
+ }
8691
+ else {
8692
+ const monthMap = new Map();
8693
+ for (const day of allDays) {
8694
+ const date = new Date(day.date + 'T00:00:00');
8695
+ const mk = toMonthKey(date);
8696
+ if (!monthMap.has(mk)) {
8697
+ monthMap.set(mk, { days: [], label: formatMonthLabel(date) });
8698
+ }
8699
+ monthMap.get(mk).days.push(day);
8700
+ }
8701
+ const sortedMonthKeys = Array.from(monthMap.keys()).sort();
8702
+ months = sortedMonthKeys.map((mk) => {
8703
+ const { days, label } = monthMap.get(mk);
8704
+ return {
8705
+ month: mk,
8706
+ label,
8707
+ days,
8708
+ summary: buildSummary(days),
8709
+ };
8710
+ });
8711
+ }
8712
+ return {
8713
+ timeframe,
8714
+ weeks,
8715
+ months,
8716
+ overall: buildSummary(allDays),
8717
+ isLoading: false,
8718
+ };
8719
+ };
8720
+ // ─── hook ───────────────────────────────────────────────────────
8721
+ function usePnlCalendar(options) {
8722
+ var _a;
8723
+ const opts = typeof options === 'string'
8724
+ ? { timeframe: options }
8725
+ : options !== null && options !== void 0 ? options : {};
8726
+ const timeframe = (_a = opts.timeframe) !== null && _a !== void 0 ? _a : '2W';
8727
+ const customStart = opts.startDate;
8728
+ const customEnd = opts.endDate;
8729
+ const context = useContext(PearHyperliquidContext);
8730
+ if (!context) {
8731
+ throw new Error('usePnlCalendar must be used within a PearHyperliquidProvider');
8732
+ }
8733
+ const { apiBaseUrl } = context;
8734
+ const isAuthenticated = useUserData((state) => state.isAuthenticated);
8735
+ const { getAssetByName } = useMarket();
8736
+ const [trades, setTrades] = useState(null);
8737
+ const [isLoading, setIsLoading] = useState(false);
8738
+ const [error, setError] = useState(null);
8739
+ const mountedRef = useRef(true);
8740
+ useEffect(() => {
8741
+ mountedRef.current = true;
8742
+ return () => { mountedRef.current = false; };
8743
+ }, []);
8744
+ // Compute the date range
8745
+ const useCustomDates = !!(customStart && customEnd);
8746
+ let rangeStart;
8747
+ let rangeEnd;
8748
+ let totalDays;
8749
+ if (useCustomDates) {
8750
+ rangeStart = toLocalMidnight(customStart);
8751
+ rangeEnd = toLocalMidnight(customEnd);
8752
+ totalDays = diffDays(rangeStart, rangeEnd);
8753
+ }
8754
+ else {
8755
+ totalDays = getTimeframeDays$1(timeframe);
8756
+ rangeEnd = new Date();
8757
+ rangeEnd.setHours(0, 0, 0, 0);
8758
+ rangeStart = new Date(rangeEnd);
8759
+ rangeStart.setDate(rangeEnd.getDate() - totalDays + 1);
8760
+ }
8761
+ const startIso = toISODateString$1(rangeStart);
8762
+ const endIso = toISODateString$1(rangeEnd);
8763
+ const fetchData = useCallback(async () => {
8764
+ if (!isAuthenticated)
8765
+ return;
8766
+ setIsLoading(true);
8767
+ setError(null);
8768
+ try {
8769
+ const response = await getTradeHistory(apiBaseUrl, {
8770
+ startDate: startIso,
8771
+ endDate: endIso,
8772
+ limit: totalDays * 50,
8773
+ });
8774
+ if (!mountedRef.current)
8775
+ return;
8776
+ setTrades(response.data);
8777
+ }
8778
+ catch (err) {
8779
+ if (!mountedRef.current)
8780
+ return;
8781
+ setError(err instanceof Error ? err.message : 'Failed to fetch trade history');
8782
+ setTrades(null);
8783
+ }
8784
+ finally {
8785
+ if (mountedRef.current)
8786
+ setIsLoading(false);
8787
+ }
8788
+ }, [apiBaseUrl, isAuthenticated, startIso, endIso, totalDays]);
8789
+ useEffect(() => {
8790
+ fetchData();
8791
+ }, [fetchData]);
8792
+ const result = useMemo(() => {
8793
+ const empty = {
8794
+ timeframe,
8795
+ weeks: [],
8796
+ months: [],
8797
+ overall: EMPTY_SUMMARY,
8798
+ isLoading: true,
8799
+ };
8800
+ if (!trades)
8801
+ return empty;
8802
+ if (totalDays <= 0)
8803
+ return empty;
8804
+ return buildCalendarData(trades, timeframe, rangeStart, rangeEnd, totalDays, useCustomDates, getAssetByName);
8805
+ }, [trades, timeframe, startIso, endIso, getAssetByName]);
8806
+ return { ...result, isLoading, error, refetch: fetchData };
8807
+ }
8808
+
8809
+ const HEATMAP_LIMIT = 50;
8810
+ // ─── helpers ────────────────────────────────────────────────────
8811
+ const getTimeframeDays = (tf) => {
8812
+ switch (tf) {
8813
+ case '7D':
8814
+ return 7;
8815
+ case '30D':
8816
+ return 30;
8817
+ case '100D':
8818
+ return 100;
8819
+ case 'allTime':
8820
+ return null;
8821
+ }
8822
+ };
8823
+ const toISODateString = (date) => date.toISOString();
8824
+ const mapAsset = (asset, getAssetByName) => {
8825
+ var _a, _b, _c, _d;
8826
+ const metadata = getAssetByName(asset.coin);
8827
+ const marketInfo = getMarketInfoFromSymbol(asset.coin);
8828
+ return {
8829
+ coin: asset.coin,
8830
+ symbol: (_a = metadata === null || metadata === void 0 ? void 0 : metadata.symbolName) !== null && _a !== void 0 ? _a : marketInfo.symbolName,
8831
+ assetName: (_b = metadata === null || metadata === void 0 ? void 0 : metadata.assetName) !== null && _b !== void 0 ? _b : asset.coin,
8832
+ marketPrefix: (_c = metadata === null || metadata === void 0 ? void 0 : metadata.marketName) !== null && _c !== void 0 ? _c : marketInfo.marketName,
8833
+ percentage: asset.closeWeight * 100,
8834
+ collateralToken: (_d = metadata === null || metadata === void 0 ? void 0 : metadata.collateralToken) !== null && _d !== void 0 ? _d : 'USDC',
8835
+ };
8836
+ };
8837
+ const getCollateralTypes = (assets) => {
8838
+ const set = new Set();
8839
+ for (const a of assets)
8840
+ set.add(a.collateralToken);
8841
+ return set.size > 0 ? Array.from(set) : ['USDC'];
8842
+ };
8843
+ const toCalendarTrade = (trade, getAssetByName) => {
8844
+ const pnl = trade.realizedPnl;
8845
+ const longAssets = trade.closedLongAssets.map((a) => mapAsset(a, getAssetByName));
8846
+ const shortAssets = trade.closedShortAssets.map((a) => mapAsset(a, getAssetByName));
8847
+ return {
8848
+ tradeHistoryId: trade.tradeHistoryId,
8849
+ realizedPnl: pnl,
8850
+ result: pnl > 0 ? 'profit' : pnl < 0 ? 'loss' : 'breakeven',
8851
+ collateralTypes: getCollateralTypes([...longAssets, ...shortAssets]),
8852
+ closedLongAssets: longAssets,
8853
+ closedShortAssets: shortAssets,
8854
+ };
8855
+ };
8856
+ // ─── hook ───────────────────────────────────────────────────────
8857
+ function usePnlHeatmap(timeframe = 'allTime') {
8858
+ const context = useContext(PearHyperliquidContext);
8859
+ if (!context) {
8860
+ throw new Error('usePnlHeatmap must be used within a PearHyperliquidProvider');
8861
+ }
8862
+ const { apiBaseUrl } = context;
8863
+ const isAuthenticated = useUserData((state) => state.isAuthenticated);
8864
+ const { getAssetByName } = useMarket();
8865
+ const [trades, setTrades] = useState(null);
8866
+ const [isLoading, setIsLoading] = useState(false);
8867
+ const [error, setError] = useState(null);
8868
+ const mountedRef = useRef(true);
8869
+ useEffect(() => {
8870
+ mountedRef.current = true;
8871
+ return () => { mountedRef.current = false; };
8872
+ }, []);
8873
+ const days = getTimeframeDays(timeframe);
8874
+ let startIso;
8875
+ if (days !== null) {
8876
+ const start = new Date();
8877
+ start.setHours(0, 0, 0, 0);
8878
+ start.setDate(start.getDate() - days);
8879
+ startIso = toISODateString(start);
8880
+ }
8881
+ const fetchData = useCallback(async () => {
8882
+ if (!isAuthenticated)
8883
+ return;
8884
+ setIsLoading(true);
8885
+ setError(null);
8886
+ try {
8887
+ const response = await getTradeHistory(apiBaseUrl, {
8888
+ ...(startIso ? { startDate: startIso } : {}),
8889
+ limit: 5000,
8890
+ });
8891
+ if (!mountedRef.current)
8892
+ return;
8893
+ setTrades(response.data);
8894
+ }
8895
+ catch (err) {
8896
+ if (!mountedRef.current)
8897
+ return;
8898
+ setError(err instanceof Error ? err.message : 'Failed to fetch trade history');
8899
+ setTrades(null);
8900
+ }
8901
+ finally {
8902
+ if (mountedRef.current)
8903
+ setIsLoading(false);
8904
+ }
8905
+ }, [apiBaseUrl, isAuthenticated, startIso]);
8906
+ useEffect(() => {
8907
+ fetchData();
8908
+ }, [fetchData]);
8909
+ const result = useMemo(() => {
8910
+ if (!trades)
8911
+ return [];
8912
+ const top = trades
8913
+ .slice()
8914
+ .sort((a, b) => Math.abs(b.realizedPnl) - Math.abs(a.realizedPnl))
8915
+ .slice(0, HEATMAP_LIMIT);
8916
+ const totalAbsPnl = top.reduce((sum, t) => sum + Math.abs(t.realizedPnl), 0);
8917
+ return top.map((t) => ({
8918
+ ...toCalendarTrade(t, getAssetByName),
8919
+ percentage: totalAbsPnl > 0
8920
+ ? Math.round((Math.abs(t.realizedPnl) / totalAbsPnl) * 10000) / 100
8921
+ : 0,
8922
+ }));
8923
+ }, [trades, getAssetByName]);
8924
+ return { timeframe, trades: result, isLoading, error, refetch: fetchData };
8925
+ }
8926
+
8479
8927
  const PearHyperliquidContext = createContext(undefined);
8480
8928
  /**
8481
8929
  * React Provider for PearHyperliquidClient
@@ -8827,4 +9275,4 @@ function getOrderTrailingInfo(order) {
8827
9275
  return undefined;
8828
9276
  }
8829
9277
 
8830
- export { ClosePositionValidationError, ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, executeSpotOrder, getCompleteTimestamps, getKalshiMarkets, getOrderDirection, getOrderLadderConfig, getOrderLeverage, getOrderReduceOnly, getOrderTpSlTriggerType, getOrderTrailingInfo, getOrderTriggerType, getOrderTriggerValue, getOrderTwapDuration, getOrderUsdValue, getPortfolio, isBtcDomOrder, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useAgentWallet, useAllUserBalances, useAuth, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidUserFills, useMarket, useMarketData, useMarketDataHook, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTradeHistories, useTwap, useUserSelection, useWatchlist, validateClosePositionRequest, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
9278
+ export { ClosePositionValidationError, ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, executeSpotOrder, getCompleteTimestamps, getKalshiMarkets, getOrderDirection, getOrderLadderConfig, getOrderLeverage, getOrderReduceOnly, getOrderTpSlTriggerType, getOrderTrailingInfo, getOrderTriggerType, getOrderTriggerValue, getOrderTwapDuration, getOrderUsdValue, getPortfolio, isBtcDomOrder, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useAgentWallet, useAllUserBalances, useAuth, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidUserFills, useMarket, useMarketData, useMarketDataHook, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePnlCalendar, usePnlHeatmap, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTradeHistories, useTwap, useUserSelection, useWatchlist, validateClosePositionRequest, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/hyperliquid-sdk",
3
- "version": "0.1.22-beta",
3
+ "version": "0.1.22-pnl",
4
4
  "description": "React SDK for Pear Protocol Hyperliquid API integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",