@pear-protocol/exchanges-sdk 0.0.18 → 0.1.3

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.
Files changed (190) hide show
  1. package/README.md +73 -137
  2. package/dist/client/base-ws.d.ts +30 -0
  3. package/dist/client/base-ws.js +113 -0
  4. package/dist/client/binance/exchange-ws.d.ts +19 -0
  5. package/dist/client/binance/exchange-ws.js +26 -0
  6. package/dist/{account/exchanges → client}/binance/rest.d.ts +2 -6
  7. package/dist/{account/exchanges → client}/binance/rest.js +4 -11
  8. package/dist/client/binance/types.d.ts +68 -0
  9. package/dist/client/binance/types.js +1 -0
  10. package/dist/client/binance/ws.d.ts +30 -0
  11. package/dist/client/binance/ws.js +54 -0
  12. package/dist/client/bybit/exchange-ws.d.ts +20 -0
  13. package/dist/client/bybit/exchange-ws.js +28 -0
  14. package/dist/{account/exchanges → client}/bybit/rest.js +3 -2
  15. package/dist/{account/exchanges → client}/bybit/types.d.ts +1 -9
  16. package/dist/client/bybit/types.js +1 -0
  17. package/dist/client/bybit/ws.d.ts +17 -0
  18. package/dist/client/bybit/ws.js +50 -0
  19. package/dist/client/exchange-ws.d.ts +12 -0
  20. package/dist/client/exchange-ws.js +10 -0
  21. package/dist/client/hyperliquid/exchange-ws.d.ts +15 -0
  22. package/dist/client/hyperliquid/exchange-ws.js +21 -0
  23. package/dist/client/hyperliquid/rest.d.ts +3 -0
  24. package/dist/client/hyperliquid/rest.js +12 -0
  25. package/dist/{account/exchanges → client}/hyperliquid/types.d.ts +93 -39
  26. package/dist/client/hyperliquid/types.js +1 -0
  27. package/dist/client/hyperliquid/ws.d.ts +10 -0
  28. package/dist/client/hyperliquid/ws.js +16 -0
  29. package/dist/client/index.d.ts +31 -0
  30. package/dist/client/index.js +47 -0
  31. package/dist/client/lighter/constants.d.ts +4 -0
  32. package/dist/client/lighter/constants.js +4 -0
  33. package/dist/client/lighter/exchange-ws.d.ts +15 -0
  34. package/dist/client/lighter/exchange-ws.js +21 -0
  35. package/dist/client/lighter/rest.d.ts +56 -0
  36. package/dist/client/lighter/rest.js +27 -0
  37. package/dist/client/lighter/types.d.ts +32 -0
  38. package/dist/client/lighter/types.js +1 -0
  39. package/dist/client/lighter/ws.d.ts +10 -0
  40. package/dist/client/lighter/ws.js +17 -0
  41. package/dist/client/okx/exchange-ws.d.ts +20 -0
  42. package/dist/client/okx/exchange-ws.js +28 -0
  43. package/dist/{account/exchanges → client}/okx/rest.js +2 -2
  44. package/dist/{account/exchanges → client}/okx/types.d.ts +1 -10
  45. package/dist/client/okx/types.js +1 -0
  46. package/dist/client/okx/ws.d.ts +17 -0
  47. package/dist/client/okx/ws.js +61 -0
  48. package/dist/helper/factory.d.ts +10 -0
  49. package/dist/helper/factory.js +12 -0
  50. package/dist/helper/index.d.ts +7 -0
  51. package/dist/helper/index.js +2 -0
  52. package/dist/helper/lighter/ethereum/abi.d.ts +66 -0
  53. package/dist/helper/lighter/ethereum/abi.js +40 -0
  54. package/dist/helper/lighter/ethereum/index.d.ts +8 -0
  55. package/dist/helper/lighter/ethereum/index.js +34 -0
  56. package/dist/helper/lighter/ethereum/types.d.ts +23 -0
  57. package/dist/helper/lighter/ethereum/types.js +1 -0
  58. package/dist/helper/lighter/helper.d.ts +9 -0
  59. package/dist/helper/lighter/helper.js +67 -0
  60. package/dist/helper/lighter/index.d.ts +6 -0
  61. package/dist/helper/lighter/index.js +2 -0
  62. package/dist/helper/lighter/types.d.ts +63 -0
  63. package/dist/helper/lighter/types.js +35 -0
  64. package/dist/helper/types.d.ts +11 -0
  65. package/dist/helper/types.js +1 -0
  66. package/dist/index.d.ts +43 -24
  67. package/dist/index.js +6 -21
  68. package/dist/sdk.d.ts +43 -0
  69. package/dist/sdk.js +53 -0
  70. package/dist/syncer/base.d.ts +40 -0
  71. package/dist/syncer/base.js +50 -0
  72. package/dist/syncer/binance/syncer.d.ts +24 -0
  73. package/dist/syncer/binance/syncer.js +9 -0
  74. package/dist/syncer/bybit/syncer.d.ts +24 -0
  75. package/dist/syncer/bybit/syncer.js +9 -0
  76. package/dist/syncer/factory.d.ts +22 -0
  77. package/dist/syncer/factory.js +26 -0
  78. package/dist/syncer/hyperliquid/syncer.d.ts +26 -0
  79. package/dist/syncer/hyperliquid/syncer.js +43 -0
  80. package/dist/syncer/index.d.ts +24 -0
  81. package/dist/syncer/index.js +7 -0
  82. package/dist/syncer/lighter/syncer.d.ts +24 -0
  83. package/dist/syncer/lighter/syncer.js +9 -0
  84. package/dist/syncer/okx/syncer.d.ts +24 -0
  85. package/dist/syncer/okx/syncer.js +9 -0
  86. package/dist/tracker/base.d.ts +79 -0
  87. package/dist/tracker/base.js +120 -0
  88. package/dist/tracker/binance/const.d.ts +4 -0
  89. package/dist/tracker/binance/const.js +4 -0
  90. package/dist/{account/exchanges → tracker}/binance/mapper.d.ts +4 -1
  91. package/dist/{account/exchanges → tracker}/binance/mapper.js +7 -6
  92. package/dist/tracker/binance/tracker.d.ts +60 -0
  93. package/dist/tracker/binance/tracker.js +181 -0
  94. package/dist/tracker/binance/types.d.ts +6 -0
  95. package/dist/{account/exchanges → tracker}/bybit/mapper.d.ts +5 -3
  96. package/dist/{account/exchanges → tracker}/bybit/mapper.js +11 -10
  97. package/dist/tracker/bybit/tracker.d.ts +51 -0
  98. package/dist/tracker/bybit/tracker.js +138 -0
  99. package/dist/tracker/bybit/types.d.ts +7 -0
  100. package/dist/{account/exchanges → tracker}/hyperliquid/mapper.d.ts +6 -4
  101. package/dist/{account/exchanges → tracker}/hyperliquid/mapper.js +18 -16
  102. package/dist/tracker/hyperliquid/tracker.d.ts +62 -0
  103. package/dist/tracker/hyperliquid/tracker.js +219 -0
  104. package/dist/tracker/hyperliquid/types.d.ts +23 -0
  105. package/dist/tracker/index.d.ts +38 -0
  106. package/dist/tracker/index.js +81 -0
  107. package/dist/tracker/lighter/const.d.ts +3 -0
  108. package/dist/tracker/lighter/const.js +3 -0
  109. package/dist/tracker/lighter/mapper.d.ts +16 -0
  110. package/dist/tracker/lighter/mapper.js +77 -0
  111. package/dist/tracker/lighter/tracker.d.ts +53 -0
  112. package/dist/tracker/lighter/tracker.js +150 -0
  113. package/dist/tracker/lighter/types.d.ts +16 -0
  114. package/dist/tracker/lighter/types.js +6 -0
  115. package/dist/{account/exchanges → tracker}/okx/mapper.d.ts +5 -3
  116. package/dist/{account/exchanges → tracker}/okx/mapper.js +11 -10
  117. package/dist/tracker/okx/tracker.d.ts +51 -0
  118. package/dist/tracker/okx/tracker.js +134 -0
  119. package/dist/tracker/okx/types.d.ts +8 -0
  120. package/dist/tracker/types.d.ts +63 -0
  121. package/dist/{account → tracker}/types.js +6 -4
  122. package/dist/tracker/utils.d.ts +11 -0
  123. package/dist/{account → tracker}/utils.js +0 -2
  124. package/dist/types.d.ts +50 -0
  125. package/dist/types.js +1 -0
  126. package/package.json +7 -5
  127. package/dist/account/account-manager.d.ts +0 -31
  128. package/dist/account/account-manager.js +0 -119
  129. package/dist/account/exchange-account.d.ts +0 -35
  130. package/dist/account/exchange-account.js +0 -158
  131. package/dist/account/exchanges/base.d.ts +0 -48
  132. package/dist/account/exchanges/base.js +0 -41
  133. package/dist/account/exchanges/binance/asset-tracker.d.ts +0 -26
  134. package/dist/account/exchanges/binance/asset-tracker.js +0 -38
  135. package/dist/account/exchanges/binance/const.d.ts +0 -10
  136. package/dist/account/exchanges/binance/const.js +0 -10
  137. package/dist/account/exchanges/binance/orchestrator.d.ts +0 -31
  138. package/dist/account/exchanges/binance/orchestrator.js +0 -91
  139. package/dist/account/exchanges/binance/state-handler.d.ts +0 -33
  140. package/dist/account/exchanges/binance/state-handler.js +0 -113
  141. package/dist/account/exchanges/binance/types.d.ts +0 -5
  142. package/dist/account/exchanges/binance/ws.d.ts +0 -23
  143. package/dist/account/exchanges/binance/ws.js +0 -69
  144. package/dist/account/exchanges/bybit/asset-tracker.d.ts +0 -26
  145. package/dist/account/exchanges/bybit/asset-tracker.js +0 -37
  146. package/dist/account/exchanges/bybit/const.d.ts +0 -7
  147. package/dist/account/exchanges/bybit/const.js +0 -7
  148. package/dist/account/exchanges/bybit/orchestrator.d.ts +0 -22
  149. package/dist/account/exchanges/bybit/orchestrator.js +0 -66
  150. package/dist/account/exchanges/bybit/state-handler.d.ts +0 -23
  151. package/dist/account/exchanges/bybit/state-handler.js +0 -70
  152. package/dist/account/exchanges/bybit/ws.d.ts +0 -19
  153. package/dist/account/exchanges/bybit/ws.js +0 -83
  154. package/dist/account/exchanges/hyperliquid/asset-tracker.d.ts +0 -35
  155. package/dist/account/exchanges/hyperliquid/asset-tracker.js +0 -83
  156. package/dist/account/exchanges/hyperliquid/orchestrator.d.ts +0 -26
  157. package/dist/account/exchanges/hyperliquid/orchestrator.js +0 -102
  158. package/dist/account/exchanges/hyperliquid/state-handler.d.ts +0 -25
  159. package/dist/account/exchanges/hyperliquid/state-handler.js +0 -104
  160. package/dist/account/exchanges/index.d.ts +0 -11
  161. package/dist/account/exchanges/index.js +0 -32
  162. package/dist/account/exchanges/okx/asset-tracker.d.ts +0 -26
  163. package/dist/account/exchanges/okx/asset-tracker.js +0 -34
  164. package/dist/account/exchanges/okx/const.d.ts +0 -7
  165. package/dist/account/exchanges/okx/const.js +0 -7
  166. package/dist/account/exchanges/okx/orchestrator.d.ts +0 -22
  167. package/dist/account/exchanges/okx/orchestrator.js +0 -57
  168. package/dist/account/exchanges/okx/state-handler.d.ts +0 -24
  169. package/dist/account/exchanges/okx/state-handler.js +0 -78
  170. package/dist/account/exchanges/okx/ws.d.ts +0 -20
  171. package/dist/account/exchanges/okx/ws.js +0 -103
  172. package/dist/account/index.d.ts +0 -11
  173. package/dist/account/index.js +0 -4
  174. package/dist/account/types.d.ts +0 -5
  175. package/dist/account/utils.d.ts +0 -10
  176. package/dist/credentials.d.ts +0 -28
  177. package/dist/credentials.js +0 -46
  178. package/dist/types-Caz2X4h0.d.ts +0 -151
  179. package/dist/utils/ws.d.ts +0 -10
  180. package/dist/utils/ws.js +0 -42
  181. /package/dist/{account/exchanges → client}/bybit/rest.d.ts +0 -0
  182. /package/dist/{utils → client}/hmac.d.ts +0 -0
  183. /package/dist/{utils → client}/hmac.js +0 -0
  184. /package/dist/{account/exchanges → client}/okx/rest.d.ts +0 -0
  185. /package/dist/{account/exchanges → tracker}/binance/types.js +0 -0
  186. /package/dist/{account/exchanges → tracker}/bybit/types.js +0 -0
  187. /package/dist/{account/exchanges → tracker}/hyperliquid/const.d.ts +0 -0
  188. /package/dist/{account/exchanges → tracker}/hyperliquid/const.js +0 -0
  189. /package/dist/{account/exchanges → tracker}/hyperliquid/types.js +0 -0
  190. /package/dist/{account/exchanges → tracker}/okx/types.js +0 -0
package/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # @pear-protocol/exchanges-sdk
2
2
 
3
- Unified SDK for connecting to cryptocurrency derivative exchanges. Provides real-time account state tracking including balances, positions, and leverage management through a single, exchange-agnostic interface with automatic WebSocket streaming and credential resolution.
3
+ Unified SDK for real-time account state (balance, positions, per-asset leverage) across supported derivative exchanges.
4
4
 
5
5
  ## Supported Exchanges
6
6
 
7
- | Exchange | Connector Name | Market Type |
8
- |----------|---------------|-------------|
7
+ | Exchange | Connector | Market |
8
+ |----------|-----------|--------|
9
9
  | Binance | `binance` | USDM Futures |
10
10
  | Bybit | `bybit` | Linear Perpetuals |
11
11
  | Hyperliquid | `hyperliquid` | Perpetuals |
12
- | OKX | `okx` | Linear SWAP Perpetuals |
12
+ | Lighter | `lighter` | Perpetuals |
13
+ | OKX | `okx` | Linear SWAP |
13
14
 
14
15
  ## Installation
15
16
 
@@ -26,187 +27,122 @@ import { ExchangesSDK } from '@pear-protocol/exchanges-sdk';
26
27
  const sdk = new PearSDK({ /* ... */ });
27
28
  const exchanges = new ExchangesSDK({ sdk });
28
29
 
29
- await exchanges.account.connect(tradeAccountId, 'binanceusdm');
30
+ const connection = await exchanges.connect(tradeAccountId, 'binance');
31
+ const tracker = exchanges.createTracker(connection);
32
+ await tracker.start();
30
33
 
31
- // Track balance and positions
32
- const balanceTracker = exchanges.account.trackBalance((balance) => {
34
+ const offBalance = tracker.trackBalance((balance) => {
33
35
  console.log(balance.totalEquity, balance.unrealizedPnl);
34
36
  });
35
37
 
36
- const positionsTracker = exchanges.account.trackPositions((positions) => {
37
- for (const pos of positions) {
38
- console.log(pos.symbol, pos.side, pos.size, pos.entryPrice);
39
- }
38
+ const offPositions = tracker.trackPosition((positions) => {
39
+ for (const p of positions) console.log(p.symbol, p.side, p.size);
40
40
  });
41
41
 
42
42
  // Cleanup
43
- balanceTracker.untrack();
44
- positionsTracker.untrack();
45
- exchanges.destroy();
43
+ offBalance();
44
+ offPositions();
45
+ await tracker.disconnect();
46
46
  ```
47
47
 
48
- ## Usage
49
-
50
- ### Initialization
48
+ Pass `demo: true` to target testnet:
51
49
 
52
50
  ```typescript
53
- // Production
54
- const exchanges = new ExchangesSDK({ sdk });
55
-
56
- // Testnet / demo
57
51
  const exchanges = new ExchangesSDK({ sdk, demo: true });
58
52
  ```
59
53
 
60
- The `ExchangesSDK` exposes three top-level modules:
61
-
62
- | Module | Description |
63
- |--------|-------------|
64
- | `exchanges.account` | Account connection, balance/position tracking, leverage management |
65
- | `exchanges.credentials` | Exchange API credential fetching and caching |
66
- | `exchanges.sdk` | Reference to the underlying `PearSDK` instance |
67
-
68
- ### Connecting to an Exchange
69
-
70
- Credentials are fetched automatically from the backend when you call `connect`. One exchange connection is active at a time.
71
-
72
- ```typescript
73
- await exchanges.account.connect(tradeAccountId, 'binance');
74
- await exchanges.account.connect(tradeAccountId, 'bybit');
75
- await exchanges.account.connect(tradeAccountId, 'hyperliquid');
76
- ```
77
-
78
- Check connection status:
79
-
80
- ```typescript
81
- exchanges.account.isConnected; // WebSocket is active
82
- exchanges.account.isInitialized; // first state snapshot received
83
- ```
54
+ ## Tracking
84
55
 
85
- ### Tracking Balance
56
+ Each `track*` method returns an unsubscribe function. Callbacks fire with the current snapshot on subscribe (if available) and on every update.
86
57
 
87
- Subscribe to real-time balance updates. The callback fires on every balance change from the exchange.
58
+ ### Balance
88
59
 
89
60
  ```typescript
90
- const tracker = exchanges.account.trackBalance((balance) => {
91
- balance.totalEquity; // total account equity
92
- balance.walletBalance; // wallet balance excluding unrealized PnL
93
- balance.unrealizedPnl; // total unrealized PnL
94
- balance.availableToTrade; // available margin for new trades
95
- balance.initialMarginUsed; // margin used by open positions
96
- balance.maintenanceMargin; // maintenance margin requirement
97
- balance.marginRatio; // current margin ratio
98
-
99
- // Per-asset breakdown
100
- for (const asset of balance.assets) {
101
- asset.asset; // "USDT", "BTC", etc.
102
- asset.free; // available amount
103
- asset.used; // amount in use
104
- asset.total; // total amount
105
- asset.walletBalance; // wallet balance
106
- asset.usdValue; // USD equivalent
61
+ tracker.trackBalance((balance) => {
62
+ balance.totalEquity;
63
+ balance.walletBalance;
64
+ balance.unrealizedPnl;
65
+ balance.availableToTrade;
66
+ balance.initialMarginUsed;
67
+ balance.maintenanceMargin;
68
+ balance.marginRatio;
69
+ balance.accountType;
70
+
71
+ for (const a of balance.assets) {
72
+ a.asset; // "USDT", "USDC", ...
73
+ a.free;
74
+ a.used;
75
+ a.total;
76
+ a.usdValue;
107
77
  }
108
78
  });
109
-
110
- // Read the latest value without waiting for a callback
111
- const current = tracker.get();
112
-
113
- // Stop receiving updates
114
- tracker.untrack();
115
79
  ```
116
80
 
117
- ### Tracking Positions
118
-
119
- Subscribe to real-time position updates. The callback fires with the full list of open positions on every change.
81
+ ### Positions
120
82
 
121
83
  ```typescript
122
- const tracker = exchanges.account.trackPositions((positions) => {
123
- for (const pos of positions) {
124
- pos.symbol; // "BTCUSDT"
125
- pos.side; // "long" | "short" | "both"
126
- pos.size; // "0.5"
127
- pos.entryPrice; // "65000.00"
128
- pos.unrealizedPnl; // "120.50"
129
- pos.leverage; // "10"
130
- pos.marginType; // "cross" | "isolated"
131
- pos.liquidationPrice; // "58000.00" or null
84
+ tracker.trackPosition((positions) => {
85
+ for (const p of positions) {
86
+ p.symbol;
87
+ p.side; // "long" | "short" | "both"
88
+ p.size;
89
+ p.entryPrice;
90
+ p.unrealizedPnl;
91
+ p.leverage;
92
+ p.marginType; // "cross" | "isolated"
93
+ p.liquidationPrice; // string | null
132
94
  }
133
95
  });
134
-
135
- const current = tracker.get();
136
- tracker.untrack();
137
96
  ```
138
97
 
139
- Positions with a size of `"0"` are automatically removed from the tracked state.
140
-
141
- ### Tracking a Specific Asset
98
+ Closed positions (`size === '0'`) are dropped automatically.
142
99
 
143
- Retrieve leverage, margin type, and trade size constraints for a specific coin. Useful when preparing to place a trade.
100
+ ### Per-Asset Leverage & Margin
144
101
 
145
102
  ```typescript
146
- const tracker = exchanges.account.trackAsset('ETH', (info) => {
147
- info.coin; // "ETH"
148
- info.leverage; // "20"
149
- info.marginType; // "cross" | "isolated"
103
+ tracker.trackAsset('ETH', (info) => {
104
+ info.coin;
105
+ info.leverage;
106
+ info.marginType;
150
107
  });
151
-
152
- const current = tracker.get();
153
- tracker.untrack();
154
108
  ```
155
109
 
156
- > **Symbol format per exchange:** `trackAsset` takes the exchange's native symbol:
157
- > - Binance / Bybit: `BTCUSDT`
158
- > - Hyperliquid: `BTC`
159
- > - OKX: `BTC-USDT-SWAP`
110
+ Asset symbol format per exchange:
160
111
 
161
- ### Managing Leverage
112
+ | Exchange | Format | Example |
113
+ |----------|--------|---------|
114
+ | Binance | `<BASE><QUOTE>` | `BTCUSDT` |
115
+ | Bybit | `<BASE><QUOTE>` | `BTCUSDT` |
116
+ | Hyperliquid | base coin | `BTC` |
117
+ | Lighter | base coin | `BTC` |
118
+ | OKX | `instId` | `BTC-USDT-SWAP` |
162
119
 
163
- ```typescript
164
- // Read cached leverage (returns null if not yet fetched)
165
- const leverage = exchanges.account.getLeverage('BTCUSDT');
166
- ```
167
-
168
- ### Reading Full State
120
+ ## Snapshot Reads
169
121
 
170
- Access a read-only snapshot of the complete account state at any time.
122
+ Synchronous getters for the latest cached state:
171
123
 
172
124
  ```typescript
173
- const state = exchanges.account.getState();
174
- if (state) {
175
- state.balance; // latest AccountBalance or null
176
- state.positions; // Map<"SYMBOL:side", AccountPosition>
177
- state.leverageSettings; // Map<symbol, leverage>
178
- state.trackedAssets; // Map<coin, TrackedAssetInfo>
179
- state.lastUpdated; // timestamp of last update
180
- state.initialized; // true after first snapshot
181
- }
125
+ tracker.getBalance(); // AccountBalance | null
126
+ tracker.getPositions(); // AccountPosition[]
127
+ tracker.getTrackedAsset('ETH'); // TrackedAssetInfo | null
128
+ tracker.isConnected;
129
+ tracker.isInitialized; // true after first snapshot
182
130
  ```
183
131
 
184
- ### Credential Management
132
+ ## Account Type Labels
185
133
 
186
- Credentials are resolved automatically on `connect`, but you can manage them directly:
134
+ `balance.accountType` is an exchange-specific enum. Render with:
187
135
 
188
136
  ```typescript
189
- // Fetch credentials from the backend
190
- const creds = await exchanges.credentials.fetch(tradeAccountId);
137
+ import { ACCOUNT_TYPE_LABELS } from '@pear-protocol/exchanges-sdk';
191
138
 
192
- // Get cached credentials (null if not fetched)
193
- const cached = exchanges.credentials.get(tradeAccountId);
194
-
195
- // Get from cache or fetch if missing
196
- const creds = await exchanges.credentials.getOrFetch(tradeAccountId);
197
-
198
- // Clear cached credentials
199
- exchanges.credentials.clear(tradeAccountId); // specific account
200
- exchanges.credentials.clear(); // all accounts
139
+ ACCOUNT_TYPE_LABELS[balance.accountType]; // "Cross Margin", "Portfolio Margin", ...
201
140
  ```
202
141
 
203
- ### Cleanup
142
+ ## Cleanup
204
143
 
205
144
  ```typescript
206
- // Disconnect but keep credentials cached for reconnection
207
- exchanges.account.disconnect();
208
-
209
- // Full teardown: disconnect and clear all credentials
210
- exchanges.destroy();
145
+ await tracker.disconnect();
211
146
  ```
212
147
 
148
+ Credentials are fetched automatically on `connect`; for Hyperliquid and Lighter the account index is resolved from the backend.
@@ -0,0 +1,30 @@
1
+ import { WebSocket } from 'partysocket';
2
+
3
+ interface WsMessage {
4
+ [key: string]: unknown;
5
+ }
6
+ type MessageListener = (data: string) => void;
7
+ type OpenListener = () => void;
8
+ declare abstract class BaseWs {
9
+ protected ws: WebSocket | null;
10
+ protected pingTimer: ReturnType<typeof setInterval> | null;
11
+ private messageListeners;
12
+ private openListeners;
13
+ private nextListenerId;
14
+ protected abstract getWsUrl(): string;
15
+ protected abstract getPingIntervalMs(): number;
16
+ protected abstract buildPingMessage(): WsMessage | string | null;
17
+ connect(): Promise<void>;
18
+ disconnect(): void;
19
+ get connected(): boolean;
20
+ send(msg: WsMessage | string): void;
21
+ addMessageListener(listener: MessageListener): string;
22
+ removeMessageListener(id: string): void;
23
+ addOpenListener(listener: OpenListener): string;
24
+ removeOpenListener(id: string): void;
25
+ destroy(): void;
26
+ private startPing;
27
+ private stopPing;
28
+ }
29
+
30
+ export { BaseWs, type MessageListener, type OpenListener, type WsMessage };
@@ -0,0 +1,113 @@
1
+ import { WebSocket } from 'partysocket';
2
+
3
+ class BaseWs {
4
+ ws = null;
5
+ pingTimer = null;
6
+ messageListeners = /* @__PURE__ */ new Map();
7
+ openListeners = /* @__PURE__ */ new Map();
8
+ nextListenerId = 0;
9
+ async connect() {
10
+ if (this.ws) return;
11
+ const ws = new WebSocket(this.getWsUrl(), [], {
12
+ maxReconnectionDelay: 3e4,
13
+ minReconnectionDelay: 1e3,
14
+ reconnectionDelayGrowFactor: 2,
15
+ connectionTimeout: 1e4
16
+ });
17
+ ws.addEventListener("open", () => {
18
+ this.startPing();
19
+ for (const listener of this.openListeners.values()) {
20
+ try {
21
+ listener();
22
+ } catch (error) {
23
+ console.warn("Error in ws open listener", error);
24
+ }
25
+ }
26
+ });
27
+ ws.addEventListener("message", (event) => {
28
+ const data = event.data;
29
+ if (typeof data !== "string") return;
30
+ for (const listener of this.messageListeners.values()) {
31
+ try {
32
+ listener(data);
33
+ } catch (error) {
34
+ console.warn("Error in ws message listener", error);
35
+ }
36
+ }
37
+ });
38
+ ws.addEventListener("close", () => {
39
+ this.stopPing();
40
+ });
41
+ ws.addEventListener("error", () => {
42
+ });
43
+ this.ws = ws;
44
+ await new Promise((resolve, reject) => {
45
+ if (ws.readyState === WebSocket.OPEN) {
46
+ resolve();
47
+ return;
48
+ }
49
+ const onOpen = () => {
50
+ ws.removeEventListener("error", onError);
51
+ resolve();
52
+ };
53
+ const onError = () => {
54
+ ws.removeEventListener("open", onOpen);
55
+ reject(new Error("WebSocket connection failed"));
56
+ };
57
+ ws.addEventListener("open", onOpen, { once: true });
58
+ ws.addEventListener("error", onError, { once: true });
59
+ });
60
+ }
61
+ disconnect() {
62
+ this.stopPing();
63
+ if (this.ws) {
64
+ this.ws.close();
65
+ this.ws = null;
66
+ }
67
+ }
68
+ get connected() {
69
+ return this.ws?.readyState === WebSocket.OPEN;
70
+ }
71
+ send(msg) {
72
+ if (this.ws?.readyState === WebSocket.OPEN) {
73
+ this.ws.send(typeof msg === "string" ? msg : JSON.stringify(msg));
74
+ }
75
+ }
76
+ addMessageListener(listener) {
77
+ const id = String(++this.nextListenerId);
78
+ this.messageListeners.set(id, listener);
79
+ return id;
80
+ }
81
+ removeMessageListener(id) {
82
+ this.messageListeners.delete(id);
83
+ }
84
+ addOpenListener(listener) {
85
+ const id = String(++this.nextListenerId);
86
+ this.openListeners.set(id, listener);
87
+ return id;
88
+ }
89
+ removeOpenListener(id) {
90
+ this.openListeners.delete(id);
91
+ }
92
+ destroy() {
93
+ this.disconnect();
94
+ this.messageListeners.clear();
95
+ this.openListeners.clear();
96
+ }
97
+ startPing() {
98
+ this.stopPing();
99
+ const intervalMs = this.getPingIntervalMs();
100
+ if (intervalMs <= 0) return;
101
+ const pingMsg = this.buildPingMessage();
102
+ if (pingMsg === null) return;
103
+ this.pingTimer = setInterval(() => this.send(pingMsg), intervalMs);
104
+ }
105
+ stopPing() {
106
+ if (this.pingTimer) {
107
+ clearInterval(this.pingTimer);
108
+ this.pingTimer = null;
109
+ }
110
+ }
111
+ }
112
+
113
+ export { BaseWs };
@@ -0,0 +1,19 @@
1
+ import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
+ import { BaseWs } from '../base-ws.js';
3
+ import { ExchangeWs } from '../exchange-ws.js';
4
+ import { BinanceUserDataWs, BinanceWsApi } from './ws.js';
5
+ import 'partysocket';
6
+
7
+ declare class BinanceExchangeWs extends ExchangeWs {
8
+ userData: BinanceUserDataWs;
9
+ wsApi: BinanceWsApi;
10
+ readonly exchange: "binance";
11
+ constructor(userData: BinanceUserDataWs, wsApi: BinanceWsApi);
12
+ protected connections(): BaseWs[];
13
+ static create(config: {
14
+ demo: boolean;
15
+ credentials: BinanceCredentialsDTO;
16
+ }): Promise<BinanceExchangeWs>;
17
+ }
18
+
19
+ export { BinanceExchangeWs };
@@ -0,0 +1,26 @@
1
+ import { ExchangeWs } from '../exchange-ws';
2
+ import { createListenKey } from './rest';
3
+ import { BinanceUserDataWs, BinanceWsApi } from './ws';
4
+
5
+ class BinanceExchangeWs extends ExchangeWs {
6
+ constructor(userData, wsApi) {
7
+ super();
8
+ this.userData = userData;
9
+ this.wsApi = wsApi;
10
+ }
11
+ userData;
12
+ wsApi;
13
+ exchange = "binance";
14
+ connections() {
15
+ return [this.userData, this.wsApi];
16
+ }
17
+ static async create(config) {
18
+ const listenKey = await createListenKey(config.credentials.read.api_key, config.demo);
19
+ const userData = new BinanceUserDataWs({ listenKey, demo: config.demo });
20
+ const wsApi = new BinanceWsApi({ demo: config.demo });
21
+ await Promise.all([userData.connect(), wsApi.connect()]);
22
+ return new BinanceExchangeWs(userData, wsApi);
23
+ }
24
+ }
25
+
26
+ export { BinanceExchangeWs };
@@ -1,8 +1,5 @@
1
1
  import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
- import { j as BinanceRawAccountStatus, k as BinanceRawPositionRisk, l as BinanceAssetIndex } from '../../../types-Caz2X4h0.js';
3
- import '../bybit/types.js';
4
- import '../hyperliquid/types.js';
5
- import '../okx/types.js';
2
+ import { BinanceRawAccountStatus, BinanceRawPositionRisk } from './types.js';
6
3
 
7
4
  declare function createListenKey(apiKey: string, demo?: boolean): Promise<string>;
8
5
  declare function keepAliveListenKey(apiKey: string, demo?: boolean): Promise<void>;
@@ -10,6 +7,5 @@ declare function fetchAccountStatus(creds: BinanceCredentialsDTO, demo: boolean)
10
7
  declare function fetchPositionRisk(creds: BinanceCredentialsDTO, symbol: string, demo: boolean): Promise<BinanceRawPositionRisk | undefined>;
11
8
  declare function fetchAllPositionRisk(creds: BinanceCredentialsDTO, demo: boolean): Promise<BinanceRawPositionRisk[]>;
12
9
  declare function fetchMultiAssetsMargin(creds: BinanceCredentialsDTO, demo: boolean): Promise<boolean>;
13
- declare function fetchAssetIndex(demo: boolean): Promise<BinanceAssetIndex[]>;
14
10
 
15
- export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchAssetIndex, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
11
+ export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
@@ -1,6 +1,7 @@
1
- import { hmacSha256Hex } from '../../../utils/hmac';
2
- import { BASE_URL_TESTNET, BASE_URL } from './const';
1
+ import { hmacSha256Hex } from '../hmac';
3
2
 
3
+ const BASE_URL = "https://fapi.binance.com";
4
+ const BASE_URL_TESTNET = "https://testnet.binancefuture.com";
4
5
  async function signedGet(creds, path, params, demo) {
5
6
  const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
6
7
  const timestamp = Date.now().toString();
@@ -53,13 +54,5 @@ async function fetchMultiAssetsMargin(creds, demo) {
53
54
  const res = await signedGet(creds, "/fapi/v1/multiAssetsMargin", {}, demo);
54
55
  return res.multiAssetsMargin;
55
56
  }
56
- async function fetchAssetIndex(demo) {
57
- const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
58
- const response = await fetch(`${baseUrl}/fapi/v1/assetIndex`);
59
- if (!response.ok) {
60
- throw new Error(`Binance API error: ${response.status} ${response.statusText}`);
61
- }
62
- return await response.json();
63
- }
64
57
 
65
- export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchAssetIndex, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
58
+ export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
@@ -0,0 +1,68 @@
1
+ import { MarginMode } from '@pear-protocol/types';
2
+
3
+ interface BinanceRawPositionRisk {
4
+ symbol: string;
5
+ leverage: string;
6
+ marginType: MarginMode;
7
+ isAutoAddMargin: string;
8
+ isolatedMargin: string;
9
+ positionAmt: string;
10
+ entryPrice: string;
11
+ breakEvenPrice: string;
12
+ unRealizedProfit: string;
13
+ liquidationPrice: string;
14
+ markPrice: string;
15
+ maxNotionalValue: string;
16
+ positionSide: string;
17
+ notional: string;
18
+ isolatedWallet: string;
19
+ updateTime: number;
20
+ }
21
+ interface BinanceRawAsset {
22
+ asset: string;
23
+ walletBalance: string;
24
+ availableBalance: string;
25
+ unrealizedProfit: string;
26
+ marginBalance: string;
27
+ initialMargin: string;
28
+ maintMargin: string;
29
+ marginAvailable: boolean;
30
+ }
31
+ interface BinanceRawAccountStatus {
32
+ totalWalletBalance: string;
33
+ totalMarginBalance: string;
34
+ availableBalance: string;
35
+ totalUnrealizedProfit: string;
36
+ totalInitialMargin: string;
37
+ totalMaintMargin: string;
38
+ assets?: BinanceRawAsset[];
39
+ }
40
+ interface BinanceMultiAssetsMarginResponse {
41
+ multiAssetsMargin: boolean;
42
+ }
43
+ interface BinanceAssetIndex {
44
+ symbol: string;
45
+ time: number;
46
+ index: string;
47
+ bidBuffer: string;
48
+ askBuffer: string;
49
+ bidRate: string;
50
+ askRate: string;
51
+ autoExchangeBidBuffer: string;
52
+ autoExchangeAskBuffer: string;
53
+ autoExchangeBidRate: string;
54
+ autoExchangeAskRate: string;
55
+ }
56
+ interface BinanceRawUserDataEvent {
57
+ e?: string;
58
+ ac?: {
59
+ s: string;
60
+ l: string;
61
+ };
62
+ a?: {
63
+ B?: unknown[];
64
+ P?: unknown[];
65
+ };
66
+ }
67
+
68
+ export type { BinanceAssetIndex, BinanceMultiAssetsMarginResponse, BinanceRawAccountStatus, BinanceRawAsset, BinanceRawPositionRisk, BinanceRawUserDataEvent };
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,30 @@
1
+ import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
+ import { BaseWs } from '../base-ws.js';
3
+ import 'partysocket';
4
+
5
+ type BinanceUserDataWsConfig = {
6
+ listenKey: string;
7
+ demo: boolean;
8
+ };
9
+ declare class BinanceUserDataWs extends BaseWs {
10
+ private readonly listenKey;
11
+ private readonly demo;
12
+ constructor(config: BinanceUserDataWsConfig);
13
+ protected getWsUrl(): string;
14
+ protected getPingIntervalMs(): number;
15
+ protected buildPingMessage(): null;
16
+ }
17
+ type BinanceWsApiConfig = {
18
+ demo: boolean;
19
+ };
20
+ declare class BinanceWsApi extends BaseWs {
21
+ private readonly demo;
22
+ private requestId;
23
+ constructor(config: BinanceWsApiConfig);
24
+ protected getWsUrl(): string;
25
+ protected getPingIntervalMs(): number;
26
+ protected buildPingMessage(): null;
27
+ sendSignedRequest(creds: BinanceCredentialsDTO, method: string, params?: Record<string, unknown>): Promise<number>;
28
+ }
29
+
30
+ export { BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig };
@@ -0,0 +1,54 @@
1
+ import { BaseWs } from '../base-ws';
2
+ import { hmacSha256Hex } from '../hmac';
3
+
4
+ const USER_DATA_URL = "wss://fstream.binance.com/ws";
5
+ const USER_DATA_URL_TESTNET = "wss://stream.binancefuture.com/ws";
6
+ const WS_API_URL = "wss://ws-fapi.binance.com/ws-fapi/v1";
7
+ const WS_API_URL_TESTNET = "wss://testnet.binancefuture.com/ws-fapi/v1";
8
+ class BinanceUserDataWs extends BaseWs {
9
+ listenKey;
10
+ demo;
11
+ constructor(config) {
12
+ super();
13
+ this.listenKey = config.listenKey;
14
+ this.demo = config.demo;
15
+ }
16
+ getWsUrl() {
17
+ const base = this.demo ? USER_DATA_URL_TESTNET : USER_DATA_URL;
18
+ return `${base}/${this.listenKey}`;
19
+ }
20
+ getPingIntervalMs() {
21
+ return 0;
22
+ }
23
+ buildPingMessage() {
24
+ return null;
25
+ }
26
+ }
27
+ class BinanceWsApi extends BaseWs {
28
+ demo;
29
+ requestId = 1;
30
+ constructor(config) {
31
+ super();
32
+ this.demo = config.demo;
33
+ }
34
+ getWsUrl() {
35
+ return this.demo ? WS_API_URL_TESTNET : WS_API_URL;
36
+ }
37
+ getPingIntervalMs() {
38
+ return 0;
39
+ }
40
+ buildPingMessage() {
41
+ return null;
42
+ }
43
+ async sendSignedRequest(creds, method, params = {}) {
44
+ const id = this.requestId++;
45
+ const timestamp = Date.now();
46
+ const allParams = { ...params, apiKey: creds.read.api_key, timestamp };
47
+ const queryString = Object.keys(allParams).sort().map((k) => `${k}=${allParams[k]}`).join("&");
48
+ const signature = await hmacSha256Hex(creds.read.api_secret, queryString);
49
+ this.send({ id, method, params: { ...allParams, signature } });
50
+ return id;
51
+ }
52
+ }
53
+
54
+ export { BinanceUserDataWs, BinanceWsApi };