@pear-protocol/core-sdk 1.20.1 → 2.1.0

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.
@@ -47,7 +47,7 @@ declare class Auth {
47
47
  refreshToken: string;
48
48
  user: {
49
49
  id: string;
50
- role: "basic" | "pro";
50
+ role: "basic" | "pro" | "vault";
51
51
  providerId: string | null;
52
52
  loginMethod: "email" | "evm_wallet" | "oauth" | "x";
53
53
  };
@@ -77,7 +77,7 @@ declare class Auth {
77
77
  refreshToken: string;
78
78
  user: {
79
79
  id: string;
80
- role: "basic" | "pro";
80
+ role: "basic" | "pro" | "vault";
81
81
  providerId: string | null;
82
82
  loginMethod: "email" | "evm_wallet" | "oauth" | "x";
83
83
  };
@@ -91,7 +91,7 @@ declare class Auth {
91
91
  logout(headers?: ClientHeaders): Promise<void>;
92
92
  me(headers?: ClientHeaders): Promise<{
93
93
  id: string;
94
- role: "basic" | "pro";
94
+ role: "basic" | "pro" | "vault";
95
95
  providerId: string | null;
96
96
  loginMethod: "email" | "evm_wallet" | "oauth" | "x";
97
97
  identities: {
@@ -102,7 +102,7 @@ declare class Auth {
102
102
  }>;
103
103
  apiKeyMe(headers?: ClientHeaders): Promise<{
104
104
  id: string;
105
- role: "basic" | "pro";
105
+ role: "basic" | "pro" | "vault";
106
106
  scope: "read" | "read_write";
107
107
  authMethod: "api_key";
108
108
  }>;
@@ -14,6 +14,7 @@ declare class Core {
14
14
  id: string;
15
15
  alias: string;
16
16
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
17
+ kind: "vault" | "eoa";
17
18
  exchangeIdentifier: string;
18
19
  createdAt: string;
19
20
  updatedAt: string;
@@ -32,6 +33,7 @@ declare class Core {
32
33
  id: string;
33
34
  alias: string;
34
35
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
36
+ kind: "vault" | "eoa";
35
37
  exchangeIdentifier: string;
36
38
  createdAt: string;
37
39
  updatedAt: string;
@@ -50,6 +52,7 @@ declare class Core {
50
52
  id: string;
51
53
  alias: string;
52
54
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
55
+ kind: "vault" | "eoa";
53
56
  exchangeIdentifier: string;
54
57
  createdAt: string;
55
58
  updatedAt: string;
@@ -70,6 +73,7 @@ declare class Core {
70
73
  id: string;
71
74
  alias: string;
72
75
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
76
+ kind: "vault" | "eoa";
73
77
  exchangeIdentifier: string;
74
78
  createdAt: string;
75
79
  updatedAt: string;
@@ -91,6 +95,7 @@ declare class Core {
91
95
  id: string;
92
96
  alias: string;
93
97
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
98
+ kind: "vault" | "eoa";
94
99
  exchangeIdentifier: string;
95
100
  createdAt: string;
96
101
  updatedAt: string;
@@ -119,6 +124,7 @@ declare class Core {
119
124
  id: string;
120
125
  alias: string;
121
126
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
127
+ kind: "vault" | "eoa";
122
128
  exchangeIdentifier: string;
123
129
  createdAt: string;
124
130
  updatedAt: string;
@@ -141,6 +147,7 @@ declare class Core {
141
147
  id: string;
142
148
  alias: string;
143
149
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
150
+ kind: "vault" | "eoa";
144
151
  exchangeIdentifier: string;
145
152
  createdAt: string;
146
153
  updatedAt: string;
@@ -164,6 +171,7 @@ declare class Core {
164
171
  id: string;
165
172
  alias: string;
166
173
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
174
+ kind: "vault" | "eoa";
167
175
  exchangeIdentifier: string;
168
176
  createdAt: string;
169
177
  updatedAt: string;
@@ -182,6 +190,69 @@ declare class Core {
182
190
  };
183
191
  }>;
184
192
  restore: (id: string, headers?: ClientHeaders) => Promise<void>;
193
+ createVault: (body: HttpTypes.CreateVaultTradeAccountInput, headers?: ClientHeaders) => Promise<{
194
+ account: {
195
+ id: string;
196
+ alias: string;
197
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
198
+ kind: "vault" | "eoa";
199
+ exchangeIdentifier: string;
200
+ createdAt: string;
201
+ updatedAt: string;
202
+ metadata?: {
203
+ agentWalletAddress: string;
204
+ isSubaccount: boolean;
205
+ mainAccountAddress: string;
206
+ } | {
207
+ l1_address: string;
208
+ } | undefined;
209
+ deletedAt?: string | undefined;
210
+ };
211
+ }>;
212
+ getVaultStatus: (vaultAddress: string, headers?: ClientHeaders) => Promise<{
213
+ status: {
214
+ exists: false;
215
+ } | {
216
+ exists: true;
217
+ tradeAccountId: string;
218
+ account: {
219
+ id: string;
220
+ alias: string;
221
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
222
+ kind: "vault" | "eoa";
223
+ exchangeIdentifier: string;
224
+ createdAt: string;
225
+ updatedAt: string;
226
+ metadata?: {
227
+ agentWalletAddress: string;
228
+ isSubaccount: boolean;
229
+ mainAccountAddress: string;
230
+ } | {
231
+ l1_address: string;
232
+ } | undefined;
233
+ deletedAt?: string | undefined;
234
+ };
235
+ };
236
+ }>;
237
+ refreshVault: (vaultAddress: string, headers?: ClientHeaders) => Promise<{
238
+ account: {
239
+ id: string;
240
+ alias: string;
241
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
242
+ kind: "vault" | "eoa";
243
+ exchangeIdentifier: string;
244
+ createdAt: string;
245
+ updatedAt: string;
246
+ metadata?: {
247
+ agentWalletAddress: string;
248
+ isSubaccount: boolean;
249
+ mainAccountAddress: string;
250
+ } | {
251
+ l1_address: string;
252
+ } | undefined;
253
+ deletedAt?: string | undefined;
254
+ };
255
+ }>;
185
256
  };
186
257
  fee: {
187
258
  get: (query?: HttpTypes.QuoteFeeParamsInput, headers?: ClientHeaders) => Promise<{
@@ -3471,16 +3542,19 @@ declare class Core {
3471
3542
  }[];
3472
3543
  }>;
3473
3544
  /**
3474
- * Closed-trade history, newest close first, composed server-side.
3545
+ * Closed-position history, newest close first, composed server-side.
3475
3546
  *
3476
- * A page may hold fewer than `limit` trades and still return a `nextCursor` —
3547
+ * A page may hold fewer than `limit` positions and still return a `nextCursor` —
3477
3548
  * page until `nextCursor` is absent, never until a page comes back short.
3549
+ * `includeSteps` is accepted only together with `positionId`: the timeline is
3550
+ * unbounded per row, so it is served one position at a time.
3478
3551
  */
3479
3552
  closed: (query?: HttpTypes.ClosedPositionListParamsInput, headers?: ClientHeaders) => Promise<{
3480
3553
  limit: number;
3481
- trades: {
3554
+ positions: {
3482
3555
  positionId: string;
3483
3556
  connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
3557
+ status: "CLOSED";
3484
3558
  openedAt: string;
3485
3559
  closedAt: string;
3486
3560
  origin: "PARTIAL" | "PEAR" | "EXTERNAL";
@@ -3547,180 +3621,369 @@ declare class Core {
3547
3621
  }[];
3548
3622
  nextCursor?: string | undefined;
3549
3623
  }>;
3624
+ /**
3625
+ * Open-position history: the realized part of every open position, newest
3626
+ * opened first, composed server-side. Every open position yields exactly
3627
+ * one row — one whose fills are not visible yet comes back as an explicit
3628
+ * zero-state row.
3629
+ *
3630
+ * Page until `nextCursor` is absent, never until a page comes back short.
3631
+ */
3632
+ open: (query?: HttpTypes.OpenPositionListParamsInput, headers?: ClientHeaders) => Promise<{
3633
+ limit: number;
3634
+ positions: {
3635
+ positionId: string;
3636
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
3637
+ status: "OPEN";
3638
+ openedAt: string;
3639
+ updatedAt: string;
3640
+ origin: "PARTIAL" | "PEAR" | "EXTERNAL";
3641
+ realizedGrossPnl: `-${string}` | `+${string}`;
3642
+ netCashflow: `-${string}` | `+${string}`;
3643
+ totalFees: `-${string}` | `+${string}`;
3644
+ tradeFees: `-${string}` | `+${string}`;
3645
+ pearFees: `-${string}` | `+${string}`;
3646
+ totalFunding: `-${string}` | `+${string}`;
3647
+ initialExposureUSD: Record<string, `-${string}` | `+${string}`>;
3648
+ hasSyntheticFills: boolean;
3649
+ hasProvisionalFills: boolean;
3650
+ unstableHistoricalData: boolean;
3651
+ legs: {
3652
+ asset: string;
3653
+ side: "LONG" | "SHORT";
3654
+ realized: {
3655
+ quantity: string;
3656
+ unpricedQuantity: string;
3657
+ grossPnl: `-${string}` | `+${string}`;
3658
+ netPnl: `-${string}` | `+${string}`;
3659
+ exitVwap?: string | undefined;
3660
+ };
3661
+ remaining: {
3662
+ quantity: `-${string}` | `+${string}`;
3663
+ entryVwap?: string | undefined;
3664
+ };
3665
+ totalFees: `-${string}` | `+${string}`;
3666
+ tradeFees: `-${string}` | `+${string}`;
3667
+ pearFees: `-${string}` | `+${string}`;
3668
+ funding: `-${string}` | `+${string}`;
3669
+ }[];
3670
+ steps?: {
3671
+ at: string;
3672
+ grossPnl: `-${string}` | `+${string}`;
3673
+ legs: ({
3674
+ kind: "INCREASE";
3675
+ asset: string;
3676
+ side: "BUY" | "SELL";
3677
+ quantity: string;
3678
+ price: string;
3679
+ tradeFee: `-${string}` | `+${string}`;
3680
+ pearFee: `-${string}` | `+${string}`;
3681
+ } | {
3682
+ kind: "REDUCE";
3683
+ asset: string;
3684
+ side: "BUY" | "SELL";
3685
+ quantity: string;
3686
+ price: string;
3687
+ entryBasis: string;
3688
+ grossPnl: `-${string}` | `+${string}`;
3689
+ tradeFee: `-${string}` | `+${string}`;
3690
+ pearFee: `-${string}` | `+${string}`;
3691
+ } | {
3692
+ kind: "REDUCE_UNPRICED";
3693
+ asset: string;
3694
+ side: "BUY" | "SELL";
3695
+ quantity: string;
3696
+ tradeFee: `-${string}` | `+${string}`;
3697
+ pearFee: `-${string}` | `+${string}`;
3698
+ })[];
3699
+ executionId?: string | undefined;
3700
+ }[] | undefined;
3701
+ }[];
3702
+ nextCursor?: string | undefined;
3703
+ }>;
3704
+ };
3705
+ /** Fill-level history; basket commands live under the singular `trade` namespace. */
3706
+ trades: {
3707
+ /** List fill-level trades grouped by execution with compound cursor pagination. */
3708
+ list: (query?: HttpTypes.TradeListParamsInput, headers?: ClientHeaders) => Promise<{
3709
+ limit: number;
3710
+ groups: {
3711
+ id: string;
3712
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
3713
+ at: string;
3714
+ netCashflow: `-${string}` | `+${string}`;
3715
+ trades: {
3716
+ id: string;
3717
+ positionId: string;
3718
+ symbol: string;
3719
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
3720
+ side: "BUY" | "SELL";
3721
+ quantity: string;
3722
+ price: string;
3723
+ timestamp: string;
3724
+ settlement: "PROVISIONAL" | "CONFIRMED";
3725
+ positionEffect: {
3726
+ kind: "OPEN";
3727
+ openedQuantity: string;
3728
+ } | {
3729
+ kind: "INCREASE";
3730
+ increasedQuantity: string;
3731
+ } | {
3732
+ kind: "REDUCE";
3733
+ reducedQuantity: string;
3734
+ realization: {
3735
+ kind: "PRICED";
3736
+ quantity: string;
3737
+ entryPrice: string;
3738
+ exitPrice: string;
3739
+ grossPnl: `-${string}` | `+${string}`;
3740
+ } | {
3741
+ kind: "UNPRICED";
3742
+ quantity: string;
3743
+ };
3744
+ } | {
3745
+ kind: "CLOSE";
3746
+ reducedQuantity: string;
3747
+ realization: {
3748
+ kind: "PRICED";
3749
+ quantity: string;
3750
+ entryPrice: string;
3751
+ exitPrice: string;
3752
+ grossPnl: `-${string}` | `+${string}`;
3753
+ } | {
3754
+ kind: "UNPRICED";
3755
+ quantity: string;
3756
+ };
3757
+ } | {
3758
+ kind: "FLIP";
3759
+ reducedQuantity: string;
3760
+ openedQuantity: string;
3761
+ realization: {
3762
+ kind: "PRICED";
3763
+ quantity: string;
3764
+ entryPrice: string;
3765
+ exitPrice: string;
3766
+ grossPnl: `-${string}` | `+${string}`;
3767
+ } | {
3768
+ kind: "UNPRICED";
3769
+ quantity: string;
3770
+ };
3771
+ };
3772
+ basisBefore: {
3773
+ signedQuantity: `-${string}` | `+${string}`;
3774
+ basis: {
3775
+ kind: "FLAT";
3776
+ } | {
3777
+ kind: "PRICED";
3778
+ entryPrice: string;
3779
+ } | {
3780
+ kind: "UNPRICED";
3781
+ };
3782
+ };
3783
+ basisAfter: {
3784
+ signedQuantity: `-${string}` | `+${string}`;
3785
+ basis: {
3786
+ kind: "FLAT";
3787
+ } | {
3788
+ kind: "PRICED";
3789
+ entryPrice: string;
3790
+ } | {
3791
+ kind: "UNPRICED";
3792
+ };
3793
+ };
3794
+ tradeFee?: `-${string}` | `+${string}` | undefined;
3795
+ pearFee?: `-${string}` | `+${string}` | undefined;
3796
+ executionId?: string | undefined;
3797
+ }[];
3798
+ executionId?: string | undefined;
3799
+ scheduleId?: string | undefined;
3800
+ triggerId?: string | undefined;
3801
+ }[];
3802
+ nextCursor?: string | undefined;
3803
+ }>;
3550
3804
  };
3551
3805
  portfolio: {
3552
3806
  overview: (query?: HttpTypes.PortfolioQueryInput, headers?: ClientHeaders) => Promise<{
3553
- intervals: {
3554
- oneDay: {
3555
- periodStart: string;
3556
- periodEnd: string;
3557
- volume: number;
3558
- openInterest: number;
3559
- winningTradesCount: number;
3560
- winningTradesUsd: number;
3561
- losingTradesCount: number;
3562
- losingTradesUsd: number;
3563
- }[];
3564
- oneWeek: {
3565
- periodStart: string;
3566
- periodEnd: string;
3567
- volume: number;
3568
- openInterest: number;
3569
- winningTradesCount: number;
3570
- winningTradesUsd: number;
3571
- losingTradesCount: number;
3572
- losingTradesUsd: number;
3573
- }[];
3574
- oneMonth: {
3575
- periodStart: string;
3576
- periodEnd: string;
3577
- volume: number;
3578
- openInterest: number;
3579
- winningTradesCount: number;
3580
- winningTradesUsd: number;
3581
- losingTradesCount: number;
3582
- losingTradesUsd: number;
3583
- }[];
3584
- oneYear: {
3585
- periodStart: string;
3586
- periodEnd: string;
3587
- volume: number;
3588
- openInterest: number;
3589
- winningTradesCount: number;
3590
- winningTradesUsd: number;
3591
- losingTradesCount: number;
3592
- losingTradesUsd: number;
3593
- }[];
3594
- all: {
3595
- periodStart: string;
3596
- periodEnd: string;
3597
- volume: number;
3598
- openInterest: number;
3599
- winningTradesCount: number;
3600
- winningTradesUsd: number;
3601
- losingTradesCount: number;
3602
- losingTradesUsd: number;
3603
- }[];
3604
- } | null;
3605
- overall: {
3606
- totalWinningTradesCount: number;
3607
- totalLosingTradesCount: number;
3608
- totalWinningUsd: number;
3609
- totalLosingUsd: number;
3610
- currentOpenInterest: number;
3611
- currentTotalVolume: number;
3807
+ realizedCashflow: {
3808
+ grossPnl: number;
3809
+ tradeFees: number;
3810
+ pearFees: number;
3811
+ netCashflow: number;
3812
+ funding: number;
3813
+ netCashflowWithFunding: number;
3814
+ undeterminedQuantityByAsset: Record<string, number>;
3815
+ fundingSynced: boolean;
3816
+ intervals?: {
3817
+ oneDay: {
3818
+ grossPnl: number;
3819
+ tradeFees: number;
3820
+ pearFees: number;
3821
+ netCashflow: number;
3822
+ funding: number;
3823
+ netCashflowWithFunding: number;
3824
+ undeterminedQuantityByAsset: Record<string, number>;
3825
+ periodStart: string;
3826
+ periodEnd: string;
3827
+ }[];
3828
+ oneWeek: {
3829
+ grossPnl: number;
3830
+ tradeFees: number;
3831
+ pearFees: number;
3832
+ netCashflow: number;
3833
+ funding: number;
3834
+ netCashflowWithFunding: number;
3835
+ undeterminedQuantityByAsset: Record<string, number>;
3836
+ periodStart: string;
3837
+ periodEnd: string;
3838
+ }[];
3839
+ oneMonth: {
3840
+ grossPnl: number;
3841
+ tradeFees: number;
3842
+ pearFees: number;
3843
+ netCashflow: number;
3844
+ funding: number;
3845
+ netCashflowWithFunding: number;
3846
+ undeterminedQuantityByAsset: Record<string, number>;
3847
+ periodStart: string;
3848
+ periodEnd: string;
3849
+ }[];
3850
+ oneYear: {
3851
+ grossPnl: number;
3852
+ tradeFees: number;
3853
+ pearFees: number;
3854
+ netCashflow: number;
3855
+ funding: number;
3856
+ netCashflowWithFunding: number;
3857
+ undeterminedQuantityByAsset: Record<string, number>;
3858
+ periodStart: string;
3859
+ periodEnd: string;
3860
+ }[];
3861
+ all: {
3862
+ grossPnl: number;
3863
+ tradeFees: number;
3864
+ pearFees: number;
3865
+ netCashflow: number;
3866
+ funding: number;
3867
+ netCashflowWithFunding: number;
3868
+ undeterminedQuantityByAsset: Record<string, number>;
3869
+ periodStart: string;
3870
+ periodEnd: string;
3871
+ }[];
3872
+ } | undefined;
3873
+ };
3874
+ closedPositionStats: {
3875
+ totalPositions: number;
3876
+ wins: number;
3877
+ losses: number;
3878
+ hitRate: number | null;
3879
+ profitFactor: number | null;
3880
+ avgWinSize: number | null;
3881
+ avgLossSize: number | null;
3882
+ netPnl: number;
3883
+ positionPnls: number[];
3884
+ positionReturns: number[];
3885
+ };
3886
+ openSnapshot: {
3887
+ openInterest: number;
3612
3888
  unrealizedPnl: number;
3613
- realizedPnl: number;
3614
- totalFees: number;
3615
- totalTrades: number;
3889
+ };
3890
+ volume: {
3891
+ total: number;
3892
+ intervals?: {
3893
+ oneDay: {
3894
+ periodStart: string;
3895
+ periodEnd: string;
3896
+ volume: number;
3897
+ }[];
3898
+ oneWeek: {
3899
+ periodStart: string;
3900
+ periodEnd: string;
3901
+ volume: number;
3902
+ }[];
3903
+ oneMonth: {
3904
+ periodStart: string;
3905
+ periodEnd: string;
3906
+ volume: number;
3907
+ }[];
3908
+ oneYear: {
3909
+ periodStart: string;
3910
+ periodEnd: string;
3911
+ volume: number;
3912
+ }[];
3913
+ all: {
3914
+ periodStart: string;
3915
+ periodEnd: string;
3916
+ volume: number;
3917
+ }[];
3918
+ } | undefined;
3616
3919
  };
3617
3920
  }>;
3618
3921
  analytics: (query?: HttpTypes.PortfolioAnalyticsQueryInput, headers?: ClientHeaders) => Promise<{
3619
3922
  config: {
3620
- rollingWindowDays: number;
3621
3923
  startDate: string;
3622
3924
  endDate: string;
3925
+ };
3926
+ realizedCashflow: {
3927
+ grossPnl: number;
3928
+ tradeFees: number;
3929
+ pearFees: number;
3930
+ netCashflow: number;
3931
+ funding: number;
3932
+ netCashflowWithFunding: number;
3933
+ undeterminedQuantityByAsset: Record<string, number>;
3623
3934
  fundingSynced: boolean;
3935
+ series?: {
3936
+ grossPnl: number;
3937
+ tradeFees: number;
3938
+ pearFees: number;
3939
+ netCashflow: number;
3940
+ funding: number;
3941
+ netCashflowWithFunding: number;
3942
+ undeterminedQuantityByAsset: Record<string, number>;
3943
+ periodStart: string;
3944
+ periodEnd: string;
3945
+ }[] | undefined;
3624
3946
  };
3625
- portfolio: {
3626
- realizedOnly: {
3627
- pnlAbsolute: number;
3628
- pnlPercent: number | null;
3629
- hitRate: number | null;
3630
- profitFactor: number | null;
3631
- avgWinSize: number | null;
3632
- avgLossSize: number | null;
3633
- avgReturnPerWin: number | null;
3634
- avgReturnPerLoss: number | null;
3635
- maxDrawdown: number | null;
3636
- sharpeRatio: number | null;
3637
- sortinoRatio: number | null;
3638
- };
3639
- realizedPlusUnrealized: {
3640
- pnlAbsolute: number;
3641
- pnlPercent: number | null;
3642
- hitRate: number | null;
3643
- profitFactor: number | null;
3644
- avgWinSize: number | null;
3645
- avgLossSize: number | null;
3646
- avgReturnPerWin: number | null;
3647
- avgReturnPerLoss: number | null;
3648
- maxDrawdown: number | null;
3649
- sharpeRatio: number | null;
3650
- sortinoRatio: number | null;
3651
- };
3652
- realizedHitRate: number | null;
3947
+ closedPositionStats: {
3948
+ totalPositions: number;
3949
+ wins: number;
3950
+ losses: number;
3951
+ hitRate: number | null;
3653
3952
  profitFactor: number | null;
3654
3953
  avgWinSize: number | null;
3655
3954
  avgLossSize: number | null;
3656
- breakevenHitRate: number | null;
3657
- cushion: number | null;
3955
+ netPnl: number;
3956
+ positionPnls: number[];
3957
+ positionReturns: number[];
3658
3958
  };
3659
- assets: {
3660
- asset: string;
3661
- realizedOnly: {
3662
- pnlAbsolute: number;
3663
- pnlPercent: number | null;
3664
- hitRate: number | null;
3665
- profitFactor: number | null;
3666
- avgWinSize: number | null;
3667
- avgLossSize: number | null;
3668
- avgReturnPerWin: number | null;
3669
- avgReturnPerLoss: number | null;
3670
- maxDrawdown: number | null;
3671
- sharpeRatio: number | null;
3672
- sortinoRatio: number | null;
3673
- };
3674
- realizedPlusUnrealized: {
3675
- pnlAbsolute: number;
3676
- pnlPercent: number | null;
3677
- hitRate: number | null;
3678
- profitFactor: number | null;
3679
- avgWinSize: number | null;
3680
- avgLossSize: number | null;
3681
- avgReturnPerWin: number | null;
3682
- avgReturnPerLoss: number | null;
3683
- maxDrawdown: number | null;
3684
- sharpeRatio: number | null;
3685
- sortinoRatio: number | null;
3686
- };
3687
- unrealizedReturnPerDay: number | null;
3688
- }[];
3689
- pairs: {
3959
+ pairBreakdown: {
3690
3960
  key: string;
3691
3961
  longAssets: string[];
3692
3962
  shortAssets: string[];
3693
- trades: number;
3963
+ positions: number;
3694
3964
  wins: number;
3695
3965
  losses: number;
3696
3966
  hitRate: number | null;
3697
- avgWinSize: number | null;
3698
- avgLossSize: number | null;
3699
- expectancy: number | null;
3700
- totalPnl: number;
3967
+ profitFactor: number | null;
3968
+ expectancy: number;
3969
+ grossPnl: number;
3970
+ tradeFees: number;
3971
+ pearFees: number;
3972
+ netPnl: number;
3701
3973
  bookPercent: number | null;
3702
3974
  }[];
3703
- series?: {
3704
- date: string;
3705
- trades: number;
3706
- wins: number;
3707
- losses: number;
3708
- dayPnl: number;
3709
- dayVolume: number;
3710
- dayFunding: number;
3711
- dayNetPnl: number;
3712
- hitRate: number | null;
3713
- winLossRatio: number | null;
3714
- rollingHitRate: number | null;
3715
- rollingWinLossRatio: number | null;
3716
- dailyReturn: number | null;
3717
- cumulativeReturn: number;
3718
- equity: number;
3719
- drawdown: number;
3720
- rollingSharpe: number | null;
3721
- rollingSortino: number | null;
3722
- rollingVolatility: number | null;
3723
- }[] | undefined;
3975
+ openSnapshot: {
3976
+ openInterest: number;
3977
+ unrealizedPnl: number;
3978
+ };
3979
+ volume: {
3980
+ total: number;
3981
+ series?: {
3982
+ periodStart: string;
3983
+ periodEnd: string;
3984
+ volume: number;
3985
+ }[] | undefined;
3986
+ };
3724
3987
  }>;
3725
3988
  };
3726
3989
  prices: {
@@ -4170,6 +4433,7 @@ declare class Core {
4170
4433
  createBulk: (body: HttpTypes.CreateFundingPaymentsRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
4171
4434
  };
4172
4435
  };
4436
+ /** Basket commands; executed-fill history lives under the plural `trades` namespace. */
4173
4437
  trade: {
4174
4438
  open: (body: HttpTypes.CreateTradeOpen, headers?: ClientHeaders) => Promise<{
4175
4439
  execution: {
@@ -4917,6 +5181,10 @@ declare class Core {
4917
5181
  })[];
4918
5182
  }>;
4919
5183
  setLeverage: (body: HttpTypes.SetLeverage, headers?: ClientHeaders) => Promise<Record<string, never>>;
5184
+ /** Add or remove margin from an isolated position without changing its size. */
5185
+ adjustIsolatedMargin: (body: HttpTypes.AdjustIsolatedMargin, headers?: ClientHeaders) => Promise<{
5186
+ adjustmentId: string;
5187
+ }>;
4920
5188
  };
4921
5189
  triggers: {
4922
5190
  list: (query: HttpTypes.TriggerListParamsInput, headers?: ClientHeaders) => Promise<{
@@ -7195,7 +7463,7 @@ declare class Core {
7195
7463
  profile: {
7196
7464
  id: string;
7197
7465
  displayName: string;
7198
- role: "basic" | "pro";
7466
+ role: "basic" | "pro" | "vault";
7199
7467
  address: string | null;
7200
7468
  email: string | null;
7201
7469
  emailVerified: boolean;
@@ -61,7 +61,26 @@ class Core {
61
61
  method: "POST",
62
62
  headers
63
63
  });
64
- }, "restore")
64
+ }, "restore"),
65
+ createVault: /* @__PURE__ */ __name(async (body, headers) => {
66
+ return await this.client.fetch(`/trade-accounts/vault`, {
67
+ method: "POST",
68
+ headers,
69
+ body
70
+ });
71
+ }, "createVault"),
72
+ getVaultStatus: /* @__PURE__ */ __name(async (vaultAddress, headers) => {
73
+ return await this.client.fetch(`/trade-accounts/vault/${vaultAddress}`, {
74
+ method: "GET",
75
+ headers
76
+ });
77
+ }, "getVaultStatus"),
78
+ refreshVault: /* @__PURE__ */ __name(async (vaultAddress, headers) => {
79
+ return await this.client.fetch(`/trade-accounts/vault/${vaultAddress}/refresh`, {
80
+ method: "POST",
81
+ headers
82
+ });
83
+ }, "refreshVault")
65
84
  };
66
85
  fee = {
67
86
  // Resolves the trading fee and connector fee recipient for the caller's selected trade account.
@@ -309,10 +328,12 @@ class Core {
309
328
  });
310
329
  }, "openLite"),
311
330
  /**
312
- * Closed-trade history, newest close first, composed server-side.
331
+ * Closed-position history, newest close first, composed server-side.
313
332
  *
314
- * A page may hold fewer than `limit` trades and still return a `nextCursor` —
333
+ * A page may hold fewer than `limit` positions and still return a `nextCursor` —
315
334
  * page until `nextCursor` is absent, never until a page comes back short.
335
+ * `includeSteps` is accepted only together with `positionId`: the timeline is
336
+ * unbounded per row, so it is served one position at a time.
316
337
  */
317
338
  closed: /* @__PURE__ */ __name(async (query, headers) => {
318
339
  return await this.client.fetch(`/positions/closed`, {
@@ -320,7 +341,33 @@ class Core {
320
341
  headers,
321
342
  query
322
343
  });
323
- }, "closed")
344
+ }, "closed"),
345
+ /**
346
+ * Open-position history: the realized part of every open position, newest
347
+ * opened first, composed server-side. Every open position yields exactly
348
+ * one row — one whose fills are not visible yet comes back as an explicit
349
+ * zero-state row.
350
+ *
351
+ * Page until `nextCursor` is absent, never until a page comes back short.
352
+ */
353
+ open: /* @__PURE__ */ __name(async (query, headers) => {
354
+ return await this.client.fetch(`/positions/open`, {
355
+ method: "GET",
356
+ headers,
357
+ query
358
+ });
359
+ }, "open")
360
+ };
361
+ /** Fill-level history; basket commands live under the singular `trade` namespace. */
362
+ trades = {
363
+ /** List fill-level trades grouped by execution with compound cursor pagination. */
364
+ list: /* @__PURE__ */ __name(async (query, headers) => {
365
+ return await this.client.fetch(`/trades`, {
366
+ method: "GET",
367
+ headers,
368
+ query
369
+ });
370
+ }, "list")
324
371
  };
325
372
  portfolio = {
326
373
  overview: /* @__PURE__ */ __name(async (query, headers) => {
@@ -560,6 +607,7 @@ class Core {
560
607
  }, "createBulk")
561
608
  }
562
609
  };
610
+ /** Basket commands; executed-fill history lives under the plural `trades` namespace. */
563
611
  trade = {
564
612
  open: /* @__PURE__ */ __name(async (body, headers) => {
565
613
  return await this.client.fetch(`/trade/open`, {
@@ -602,7 +650,15 @@ class Core {
602
650
  headers,
603
651
  body
604
652
  });
605
- }, "setLeverage")
653
+ }, "setLeverage"),
654
+ /** Add or remove margin from an isolated position without changing its size. */
655
+ adjustIsolatedMargin: /* @__PURE__ */ __name(async (body, headers) => {
656
+ return await this.client.fetch(`/margin`, {
657
+ method: "POST",
658
+ headers,
659
+ body
660
+ });
661
+ }, "adjustIsolatedMargin")
606
662
  };
607
663
  triggers = {
608
664
  list: /* @__PURE__ */ __name(async (query, headers) => {
package/dist/index.d.ts CHANGED
@@ -2,11 +2,14 @@ import { Auth } from './auth/index.js';
2
2
  import { Core } from './core/index.js';
3
3
  import { External } from './external/index.js';
4
4
  import { SDKConfig } from './types.js';
5
+ export { AuthErrorContext } from './types.js';
5
6
  export { ExternalTrigger, ExternalTriggerSource, HttpTypes, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
6
7
  export * from '@pear-protocol/utils';
7
8
  export { FetchError } from './utils.js';
8
9
  import './http.js';
9
10
 
11
+ /** Header that makes a request act as a Pear vault (see `SDKConfig.getVaultAddress`). */
12
+ declare const VAULT_ADDRESS_HEADER = "pear-vault-address";
10
13
  declare class PearSDK {
11
14
  auth: Auth;
12
15
  core: Core;
@@ -14,4 +17,4 @@ declare class PearSDK {
14
17
  constructor(config: SDKConfig);
15
18
  }
16
19
 
17
- export { External, PearSDK as default };
20
+ export { External, VAULT_ADDRESS_HEADER, PearSDK as default };
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ export { FetchError } from './utils';
10
10
 
11
11
  var __defProp = Object.defineProperty;
12
12
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
13
+ const VAULT_ADDRESS_HEADER = "pear-vault-address";
13
14
  class PearSDK {
14
15
  static {
15
16
  __name(this, "PearSDK");
@@ -91,13 +92,47 @@ class PearSDK {
91
92
  });
92
93
  if (config.onAuthError) {
93
94
  const onAuthError = config.onAuthError;
94
- client.useResponse(async (response) => {
95
- if (response.status === 401) {
96
- onAuthError();
95
+ const replayed = /* @__PURE__ */ new WeakSet();
96
+ const recoveries = /* @__PURE__ */ new Map();
97
+ const recover = /* @__PURE__ */ __name((request, failedCredential) => {
98
+ const inFlight = recoveries.get(failedCredential);
99
+ if (inFlight) {
100
+ logger.debug("[bearer-auth] Recovery already in flight for this credential, waiting...");
101
+ return inFlight;
102
+ }
103
+ const context = {
104
+ request: request.clone(),
105
+ failedCredential
106
+ };
107
+ const recovery = (async () => onAuthError(context))().finally(() => {
108
+ if (recoveries.get(failedCredential) === recovery) {
109
+ recoveries.delete(failedCredential);
110
+ }
111
+ });
112
+ recoveries.set(failedCredential, recovery);
113
+ return recovery;
114
+ }, "recover");
115
+ const bearerAuthMiddleware = /* @__PURE__ */ __name(async (response, retry, request) => {
116
+ if (response.status !== 401) {
117
+ return response;
118
+ }
119
+ if (replayed.has(request)) {
120
+ logger.error("[bearer-auth] Replay after recovery returned 401 again, giving up");
97
121
  throw new FetchError("Unauthorized. Token may be expired or revoked.", "Unauthorized", 401);
98
122
  }
99
- return response;
100
- });
123
+ const failedCredential = readBearerCredential(request);
124
+ logger.warn(`[bearer-auth] 401 received for ${request.method} ${request.url}`);
125
+ replayed.add(request);
126
+ try {
127
+ await recover(request, failedCredential);
128
+ } catch (err) {
129
+ logger.error("[bearer-auth] Recovery rejected, not replaying:", String(err));
130
+ throw new FetchError("Unauthorized. Token may be expired or revoked.", "Unauthorized", 401);
131
+ }
132
+ logger.info(`[bearer-auth] Replaying ${request.method} ${request.url}`);
133
+ return retry();
134
+ }, "bearerAuthMiddleware");
135
+ client.useResponse(bearerAuthMiddleware);
101
136
  }
102
137
  }
103
138
  if (authMode === "apikey" && config.auth?.key) {
@@ -111,19 +146,32 @@ class PearSDK {
111
146
  });
112
147
  if (config.onAuthError) {
113
148
  const onAuthError = config.onAuthError;
114
- client.useResponse(async (response) => {
115
- if (response.status === 401) {
116
- onAuthError();
117
- throw new FetchError("Unauthorized. API key may be expired or revoked.", "Unauthorized", 401);
149
+ const apiKeyAuthMiddleware = /* @__PURE__ */ __name(async (response, _retry, request) => {
150
+ if (response.status !== 401) {
151
+ return response;
118
152
  }
119
- return response;
120
- });
153
+ const notified = onAuthError({
154
+ request: request.clone(),
155
+ failedCredential: request.headers.get("x-api-key")
156
+ });
157
+ void Promise.resolve(notified).catch((err) => {
158
+ logger.error("[apikey-auth] onAuthError callback rejected:", String(err));
159
+ });
160
+ throw new FetchError("Unauthorized. API key may be expired or revoked.", "Unauthorized", 401);
161
+ }, "apiKeyAuthMiddleware");
162
+ client.useResponse(apiKeyAuthMiddleware);
121
163
  }
122
164
  }
123
- if (config.getTradeAccountId) {
165
+ if (config.getTradeAccountId || config.getVaultAddress) {
124
166
  const getTradeAccountId = config.getTradeAccountId;
167
+ const getVaultAddress = config.getVaultAddress;
125
168
  client.useRequest(async (request, next) => {
126
- const tradeAccountId = getTradeAccountId();
169
+ const vaultAddress = getVaultAddress?.();
170
+ if (vaultAddress) {
171
+ request.headers.set(VAULT_ADDRESS_HEADER, vaultAddress);
172
+ return next();
173
+ }
174
+ const tradeAccountId = getTradeAccountId?.();
127
175
  if (tradeAccountId) {
128
176
  request.headers.set("x-trade-account-id", tradeAccountId);
129
177
  }
@@ -142,5 +190,13 @@ function isSessionRefreshRequest(url) {
142
190
  return pathname.endsWith("/auth/session/refresh") || pathname.endsWith("/auth/session/refresh/token");
143
191
  }
144
192
  __name(isSessionRefreshRequest, "isSessionRefreshRequest");
193
+ function readBearerCredential(request) {
194
+ const header = request.headers.get("authorization");
195
+ if (!header) {
196
+ return null;
197
+ }
198
+ return header.replace(/^Bearer\s+/i, "");
199
+ }
200
+ __name(readBearerCredential, "readBearerCredential");
145
201
 
146
- export { PearSDK as default };
202
+ export { VAULT_ADDRESS_HEADER, PearSDK as default };
package/dist/types.d.ts CHANGED
@@ -2,6 +2,20 @@ import { HttpTypes } from '@pear-protocol/types';
2
2
  import { ProxyConfig } from '@pear-protocol/utils';
3
3
 
4
4
  type AuthMode = 'session' | 'bearer' | 'apikey';
5
+ /** What received a 401, so `onAuthError` can tell whose request it was. */
6
+ type AuthErrorContext = {
7
+ /**
8
+ * A snapshot clone of the request that received the 401 — same method, URL, headers and
9
+ * body, but safe to consume: reading it never disturbs the underlying request, in
10
+ * bearer mode the very request the SDK is about to replay.
11
+ */
12
+ request: Request;
13
+ /**
14
+ * The credential that request carried: the bearer token without its `Bearer ` prefix, or
15
+ * the `x-api-key` value. `null` when the getter supplied none.
16
+ */
17
+ failedCredential: string | null;
18
+ };
5
19
  type SDKConfig = {
6
20
  /**
7
21
  * API endpoint.
@@ -48,6 +62,17 @@ type SDKConfig = {
48
62
  * Example: () => localStorage.getState().activeTradeAccountId
49
63
  */
50
64
  getTradeAccountId?: () => string | null;
65
+ /**
66
+ * Pear vault address getter (used in both modes). When it returns an address the
67
+ * request carries the `pear-vault-address` header and acts as that vault: the
68
+ * backend authorizes the caller as the vault's owner/trader and resolves the
69
+ * vault's own trade account, so the trade-account header is not sent. For a
70
+ * one-off call without this hook, pass `{ [VAULT_ADDRESS_HEADER]: address }` as
71
+ * the call's headers.
72
+ *
73
+ * Example: () => useSessionStore.getState().activeVault?.address ?? null
74
+ */
75
+ getVaultAddress?: () => string | null;
51
76
  /**
52
77
  * Default attribution client code (client_ids.code). When set, it is
53
78
  * auto-added to the body of trade / trigger / schedule / rebalance requests
@@ -58,14 +83,21 @@ type SDKConfig = {
58
83
  */
59
84
  clientId?: string | null;
60
85
  /**
61
- * Called when server returns 401 (bearer / apikey mode).
86
+ * Called when the server returns 401 (bearer / apikey mode). The context carries the
87
+ * request and credential that actually received the 401, not the getter's current value.
88
+ *
89
+ * Bearer mode awaits the callback, then replays the original request exactly once with
90
+ * the token the getter returns afterward; reject to refuse the replay (e.g. after an
91
+ * identity switch). A second 401 ends the request without calling back. Refresh through
92
+ * a separate transport — calling this SDK instance from the callback deadlocks. Apikey
93
+ * mode stays notify-only: no await, no replay.
62
94
  *
63
- * Example: () => {
64
- * console.error('Unauthorized. Token may be expired or revoked.');
65
- * localStorage.removeItem('apiKey');
95
+ * Example: async ({ failedCredential }) => {
96
+ * if (failedCredential !== activeToken()) throw new Error('identity changed');
97
+ * await refreshTokenViaSeparateTransport();
66
98
  * }
67
99
  */
68
- onAuthError?: () => void;
100
+ onAuthError?: (context: AuthErrorContext) => void | Promise<void>;
69
101
  /**
70
102
  * Called when the session cannot be recovered (session mode only).
71
103
  * Fires after a 401 when the subsequent `POST /auth/refresh` also fails.
@@ -132,4 +164,4 @@ type RequestMiddleware = (request: Request, next: () => Promise<Response>) => Pr
132
164
  type ResponseMiddleware = (response: Response, retry: () => Promise<Response>, request: Request) => Promise<Response>;
133
165
  type ClientIdBody = HttpTypes.RebalanceManual | HttpTypes.CreateSchedule | HttpTypes.CreateTradeOpen | HttpTypes.CreateTradeAdjust | HttpTypes.CreateTradeClose | HttpTypes.CreateTradeCloseAll | HttpTypes.CreateTriggerOpen | HttpTypes.CreateTriggerClose;
134
166
 
135
- export type { AuthMode, ClientHeaders, ClientIdBody, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
167
+ export type { AuthErrorContext, AuthMode, ClientHeaders, ClientIdBody, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/core-sdk",
3
- "version": "1.20.1",
3
+ "version": "2.1.0",
4
4
  "description": "Pear Protocol Core SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -26,8 +26,8 @@
26
26
  "typecheck": "tsc --noEmit"
27
27
  },
28
28
  "dependencies": {
29
- "@pear-protocol/types": "^1.33.0",
30
- "@pear-protocol/utils": "^0.8.1",
29
+ "@pear-protocol/types": "^2.1.0",
30
+ "@pear-protocol/utils": "^1.0.0",
31
31
  "qs": "^6.14.0"
32
32
  },
33
33
  "devDependencies": {