@pear-protocol/exchanges-sdk 0.0.9 → 0.0.11

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 (60) hide show
  1. package/README.md +59 -42
  2. package/dist/account/account-manager.d.ts +5 -11
  3. package/dist/account/account-manager.js +22 -60
  4. package/dist/account/exchange-account.d.ts +8 -10
  5. package/dist/account/exchange-account.js +30 -57
  6. package/dist/account/exchanges/base.d.ts +13 -15
  7. package/dist/account/exchanges/base.js +5 -27
  8. package/dist/account/exchanges/binance/asset-tracker.d.ts +25 -0
  9. package/dist/account/exchanges/binance/asset-tracker.js +38 -0
  10. package/dist/account/exchanges/binance/mapper.d.ts +4 -3
  11. package/dist/account/exchanges/binance/mapper.js +0 -1
  12. package/dist/account/exchanges/binance/orchestrator.d.ts +9 -12
  13. package/dist/account/exchanges/binance/orchestrator.js +61 -183
  14. package/dist/account/exchanges/binance/rest.d.ts +5 -4
  15. package/dist/account/exchanges/binance/rest.js +4 -20
  16. package/dist/account/exchanges/binance/state-handler.d.ts +32 -0
  17. package/dist/account/exchanges/binance/state-handler.js +113 -0
  18. package/dist/account/exchanges/binance/types.d.ts +3 -76
  19. package/dist/account/exchanges/binance/types.js +6 -0
  20. package/dist/account/exchanges/binance/ws.d.ts +3 -2
  21. package/dist/account/exchanges/binance/ws.js +6 -22
  22. package/dist/account/exchanges/bybit/asset-tracker.d.ts +25 -0
  23. package/dist/account/exchanges/bybit/asset-tracker.js +37 -0
  24. package/dist/account/exchanges/bybit/mapper.d.ts +4 -3
  25. package/dist/account/exchanges/bybit/mapper.js +5 -3
  26. package/dist/account/exchanges/bybit/orchestrator.d.ts +11 -12
  27. package/dist/account/exchanges/bybit/orchestrator.js +48 -134
  28. package/dist/account/exchanges/bybit/rest.d.ts +2 -3
  29. package/dist/account/exchanges/bybit/rest.js +4 -39
  30. package/dist/account/exchanges/bybit/state-handler.d.ts +22 -0
  31. package/dist/account/exchanges/bybit/state-handler.js +70 -0
  32. package/dist/account/exchanges/bybit/types.d.ts +14 -3
  33. package/dist/account/exchanges/bybit/types.js +7 -0
  34. package/dist/account/exchanges/bybit/ws.d.ts +1 -0
  35. package/dist/account/exchanges/bybit/ws.js +21 -12
  36. package/dist/account/exchanges/hyperliquid/asset-tracker.d.ts +34 -0
  37. package/dist/account/exchanges/hyperliquid/asset-tracker.js +83 -0
  38. package/dist/account/exchanges/hyperliquid/mapper.d.ts +4 -4
  39. package/dist/account/exchanges/hyperliquid/mapper.js +1 -0
  40. package/dist/account/exchanges/hyperliquid/orchestrator.d.ts +15 -28
  41. package/dist/account/exchanges/hyperliquid/orchestrator.js +79 -216
  42. package/dist/account/exchanges/hyperliquid/state-handler.d.ts +24 -0
  43. package/dist/account/exchanges/hyperliquid/state-handler.js +104 -0
  44. package/dist/account/exchanges/hyperliquid/types.d.ts +119 -5
  45. package/dist/account/exchanges/hyperliquid/types.js +9 -1
  46. package/dist/account/exchanges/index.d.ts +7 -5
  47. package/dist/account/exchanges/index.js +12 -4
  48. package/dist/account/index.d.ts +3 -1
  49. package/dist/account/types.d.ts +4 -73
  50. package/dist/account/types.js +17 -0
  51. package/dist/account/utils.d.ts +3 -1
  52. package/dist/index.d.ts +3 -1
  53. package/dist/types-D2dbAtin.d.ts +150 -0
  54. package/dist/utils/hmac.d.ts +1 -2
  55. package/dist/utils/hmac.js +1 -8
  56. package/dist/utils/ws.d.ts +6 -3
  57. package/dist/utils/ws.js +24 -7
  58. package/package.json +5 -5
  59. package/dist/account/exchanges/hyperliquid/rest.d.ts +0 -6
  60. package/dist/account/exchanges/hyperliquid/rest.js +0 -11
@@ -1,21 +1,19 @@
1
- import { reconnectDelay, clearTimer } from '../../utils/ws';
2
-
3
1
  class BaseOrchestrator {
4
2
  onStateUpdate;
5
3
  onError;
6
4
  demo;
7
5
  credentials = null;
8
- manualClose = false;
9
- reconnectAttempts = 0;
10
- reconnectTimer = null;
6
+ stopped = false;
11
7
  trackedCoins = /* @__PURE__ */ new Set();
12
- startGeneration = 0;
13
- starting = false;
14
8
  constructor(config) {
15
9
  this.onStateUpdate = config.onStateUpdate;
16
10
  this.onError = config.onError;
17
11
  this.demo = config.demo;
18
12
  }
13
+ /** Awaitable first-time connection. Errors propagate to caller. */
14
+ async start() {
15
+ await this.initAsync();
16
+ }
19
17
  trackAsset(coin) {
20
18
  if (this.trackedCoins.has(coin)) return;
21
19
  this.trackedCoins.add(coin);
@@ -38,26 +36,6 @@ class BaseOrchestrator {
38
36
  canUntrackAsset(_coin) {
39
37
  return true;
40
38
  }
41
- scheduleReconnect() {
42
- if (this.manualClose || !this.credentials) return;
43
- this.reconnectAttempts += 1;
44
- const delay = reconnectDelay(this.reconnectAttempts);
45
- this.reconnectTimer = setTimeout(() => {
46
- if (this.credentials && !this.starting) {
47
- this.guardedStart(this.credentials);
48
- }
49
- }, delay);
50
- }
51
- clearReconnectTimer() {
52
- this.reconnectTimer = clearTimer(this.reconnectTimer);
53
- }
54
- guardedStart(credentials) {
55
- if (this.starting) return;
56
- this.starting = true;
57
- this.start(credentials).catch((err) => this.onError(err instanceof Error ? err : new Error(String(err)))).finally(() => {
58
- this.starting = false;
59
- });
60
- }
61
39
  }
62
40
 
63
41
  export { BaseOrchestrator };
@@ -0,0 +1,25 @@
1
+ import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
+ import { S as StateUpdate, h as TrackedAssetInfo } from '../../../types-D2dbAtin.js';
3
+ import '../bybit/types.js';
4
+ import '../hyperliquid/types.js';
5
+
6
+ type OnStateUpdate = (update: StateUpdate) => void;
7
+ type OnError = (error: Error) => void;
8
+ declare class BinanceAssetTracker {
9
+ private onStateUpdate;
10
+ private onError;
11
+ private getCreds;
12
+ private getDemo;
13
+ private trackedAssetInfos;
14
+ constructor(deps: {
15
+ onStateUpdate: OnStateUpdate;
16
+ onError: OnError;
17
+ getCreds: () => BinanceCredentialsDTO;
18
+ getDemo: () => boolean;
19
+ });
20
+ getInfos(): Map<string, TrackedAssetInfo>;
21
+ onAssetTracked(coin: string): void;
22
+ onAssetUntracked(coin: string): void;
23
+ }
24
+
25
+ export { BinanceAssetTracker };
@@ -0,0 +1,38 @@
1
+ import { fetchPositionRisk } from './rest';
2
+
3
+ class BinanceAssetTracker {
4
+ onStateUpdate;
5
+ onError;
6
+ getCreds;
7
+ getDemo;
8
+ trackedAssetInfos = /* @__PURE__ */ new Map();
9
+ constructor(deps) {
10
+ this.onStateUpdate = deps.onStateUpdate;
11
+ this.onError = deps.onError;
12
+ this.getCreds = deps.getCreds;
13
+ this.getDemo = deps.getDemo;
14
+ }
15
+ getInfos() {
16
+ return this.trackedAssetInfos;
17
+ }
18
+ onAssetTracked(coin) {
19
+ fetchPositionRisk(this.getCreds(), coin, this.getDemo()).then((risk) => {
20
+ if (!risk) return;
21
+ const leverage = risk.leverage;
22
+ const marginType = risk.marginType === "isolated" ? "isolated" : "cross";
23
+ const info = { coin, leverage, marginType };
24
+ this.trackedAssetInfos.set(coin, info);
25
+ const trackedAssets = /* @__PURE__ */ new Map();
26
+ trackedAssets.set(coin, info);
27
+ this.onStateUpdate({ trackedAssets });
28
+ }).catch((err) => {
29
+ this.onError(err instanceof Error ? err : new Error(String(err)));
30
+ });
31
+ }
32
+ onAssetUntracked(coin) {
33
+ this.trackedAssetInfos.delete(coin);
34
+ this.onStateUpdate({ trackedAssets: new Map(this.trackedAssetInfos) });
35
+ }
36
+ }
37
+
38
+ export { BinanceAssetTracker };
@@ -1,8 +1,9 @@
1
- import { AccountBalance, AccountPosition } from '../../types.js';
2
- import { BinanceRawAccountStatus, BinanceRawPositionRisk } from './types.js';
1
+ import { j as BinanceRawAccountStatus, a as AccountBalance, k as BinanceRawPositionRisk, c as AccountPosition } from '../../../types-D2dbAtin.js';
3
2
  import '@pear-protocol/types';
3
+ import '../bybit/types.js';
4
+ import '../hyperliquid/types.js';
4
5
 
5
- declare function mapBalance(raw: BinanceRawAccountStatus): AccountBalance;
6
+ declare function mapBalance(raw: BinanceRawAccountStatus): Omit<AccountBalance, 'accountType'>;
6
7
  declare function mapPositions(raw: BinanceRawPositionRisk[]): Map<string, AccountPosition>;
7
8
  declare function mergePositions(incoming: Map<string, AccountPosition>, existing: Map<string, AccountPosition>): Map<string, AccountPosition>;
8
9
 
@@ -30,7 +30,6 @@ function mapBalance(raw) {
30
30
  const maintMargin = parseFloat(totalMaintMargin);
31
31
  const marginRatio = marginBalance > 0 ? (maintMargin / marginBalance).toFixed(4) : "0.0000";
32
32
  return {
33
- accountType: raw.multiAssetsMargin ? "multi-asset" : "single-asset",
34
33
  free,
35
34
  used,
36
35
  total,
@@ -1,6 +1,8 @@
1
- import { SupportedCredentials } from '../../types.js';
1
+ import { g as SupportedCredentials } from '../../../types-D2dbAtin.js';
2
2
  import { BaseOrchestrator, OrchestratorConfig } from '../base.js';
3
3
  import '@pear-protocol/types';
4
+ import '../bybit/types.js';
5
+ import '../hyperliquid/types.js';
4
6
 
5
7
  type BinanceOrchestratorConfig = OrchestratorConfig & {
6
8
  listenKeyRefreshMs?: number;
@@ -11,23 +13,18 @@ declare class BinanceOrchestrator extends BaseOrchestrator {
11
13
  private listenKeyTimer;
12
14
  private pollTimer;
13
15
  private creds;
14
- private trackedAssetInfos;
15
- private currentPositions;
16
16
  private readonly listenKeyRefreshMs;
17
17
  private readonly accountPollMs;
18
- constructor(config: BinanceOrchestratorConfig);
19
- start(credentials: SupportedCredentials): Promise<void>;
20
- stop(): void;
18
+ private stateHandler;
19
+ private assetTracker;
20
+ constructor(config: BinanceOrchestratorConfig, credentials: SupportedCredentials);
21
+ protected initAsync(): Promise<void>;
22
+ protected cleanupConnections(): void;
23
+ stop(): Promise<void>;
21
24
  get isConnected(): boolean;
22
25
  onAssetTracked(coin: string): void;
23
26
  onAssetUntracked(coin: string): void;
24
- setLeverage(symbol: string, leverage: string): Promise<void>;
25
- private stopAll;
26
27
  private pollAccountStatus;
27
- private handleUserDataEvent;
28
- private handleAccountStatus;
29
- private handlePositionRisk;
30
- private refreshAllPositions;
31
28
  }
32
29
 
33
30
  export { BinanceOrchestrator };
@@ -1,212 +1,90 @@
1
- import { positionKey } from '../../utils';
2
1
  import { BaseOrchestrator } from '../base';
3
2
  import { DEFAULT_LISTEN_KEY_REFRESH_MS, DEFAULT_ACCOUNT_POLL_MS } from './const';
4
- import { mapBalance, mapPositions, mergePositions } from './mapper';
5
- import { fetchAccountStatus, fetchAllPositionRisk, createListenKey, keepAliveListenKey, fetchPositionRisk, setLeverage } from './rest';
3
+ import { fetchAccountStatus, fetchAllPositionRisk, fetchMultiAssetsMargin, createListenKey, keepAliveListenKey } from './rest';
4
+ import './types';
6
5
  import { BinanceWs } from './ws';
6
+ import { BinanceStateHandler } from './state-handler';
7
+ import { BinanceAssetTracker } from './asset-tracker';
7
8
 
8
9
  class BinanceOrchestrator extends BaseOrchestrator {
9
10
  ws = null;
10
11
  listenKeyTimer = null;
11
12
  pollTimer = null;
12
- creds = null;
13
- trackedAssetInfos = /* @__PURE__ */ new Map();
14
- currentPositions = /* @__PURE__ */ new Map();
13
+ creds;
15
14
  listenKeyRefreshMs;
16
15
  accountPollMs;
17
- constructor(config) {
16
+ stateHandler;
17
+ assetTracker;
18
+ constructor(config, credentials) {
18
19
  super(config);
20
+ this.credentials = credentials;
21
+ this.creds = credentials;
19
22
  this.listenKeyRefreshMs = config.listenKeyRefreshMs ?? DEFAULT_LISTEN_KEY_REFRESH_MS;
20
23
  this.accountPollMs = config.accountPollMs ?? DEFAULT_ACCOUNT_POLL_MS;
24
+ this.assetTracker = new BinanceAssetTracker({
25
+ onStateUpdate: (update) => this.onStateUpdate(update),
26
+ onError: (err) => this.onError(err),
27
+ getCreds: () => this.creds,
28
+ getDemo: () => this.demo
29
+ });
30
+ this.stateHandler = new BinanceStateHandler({
31
+ onStateUpdate: (update) => this.onStateUpdate(update),
32
+ onError: (err) => this.onError(err),
33
+ getCreds: () => this.creds,
34
+ getDemo: () => this.demo,
35
+ getTrackedCoins: () => this.trackedCoins,
36
+ getTrackedAssetInfos: () => this.assetTracker.getInfos()
37
+ });
21
38
  }
22
- async start(credentials) {
23
- const gen = ++this.startGeneration;
24
- this.manualClose = false;
25
- this.credentials = credentials;
26
- this.creds = credentials;
27
- this.stopAll();
28
- try {
29
- const [snapshot, positionRisk] = await Promise.all([
30
- fetchAccountStatus(this.creds, this.demo),
31
- fetchAllPositionRisk(this.creds, this.demo)
32
- ]);
33
- if (gen !== this.startGeneration) return;
34
- this.handleAccountStatus(snapshot);
35
- this.handlePositionRisk(positionRisk, false);
36
- const listenKey = await createListenKey(this.creds.read.api_key, this.demo);
37
- this.ws = new BinanceWs(
38
- {
39
- onUserDataEvent: (event) => this.handleUserDataEvent(event),
40
- onWsApiResponse: (_id, result) => this.handleAccountStatus(result),
41
- onClose: () => {
42
- if (!this.manualClose) {
43
- this.stopAll();
44
- this.scheduleReconnect();
45
- }
46
- }
47
- },
48
- this.demo
39
+ async initAsync() {
40
+ const [snapshot, positionRisk, multiAssetsMargin] = await Promise.all([
41
+ fetchAccountStatus(this.creds, this.demo),
42
+ fetchAllPositionRisk(this.creds, this.demo),
43
+ fetchMultiAssetsMargin(this.creds, this.demo)
44
+ ]);
45
+ this.stateHandler.setMultiAssetsMargin(multiAssetsMargin);
46
+ this.stateHandler.handleAccountStatus(snapshot);
47
+ this.stateHandler.handlePositionRisk(positionRisk, false);
48
+ const listenKey = await createListenKey(this.creds.read.api_key, this.demo);
49
+ this.ws = new BinanceWs(
50
+ {
51
+ onUserDataEvent: (event) => this.stateHandler.handleUserDataEvent(event),
52
+ onWsApiResponse: (_id, result) => this.stateHandler.handleAccountStatus(result)
53
+ },
54
+ this.demo
55
+ );
56
+ await this.ws.connectUserDataStream(listenKey);
57
+ this.listenKeyTimer = setInterval(() => {
58
+ keepAliveListenKey(this.creds.read.api_key, this.demo).catch(
59
+ (err) => this.onError(err instanceof Error ? err : new Error(String(err)))
49
60
  );
50
- await this.ws.connectUserDataStream(listenKey);
51
- this.listenKeyTimer = setInterval(() => {
52
- if (this.creds) {
53
- keepAliveListenKey(this.creds.read.api_key, this.demo).catch(
54
- (err) => this.onError(err instanceof Error ? err : new Error(String(err)))
55
- );
56
- }
57
- }, this.listenKeyRefreshMs);
58
- await this.ws.connectWsApi(this.creds);
59
- this.reconnectAttempts = 0;
60
- this.pollAccountStatus();
61
- this.pollTimer = setInterval(() => this.pollAccountStatus(), this.accountPollMs);
62
- } catch (err) {
63
- if (gen !== this.startGeneration) return;
64
- this.stopAll();
65
- this.onError(err instanceof Error ? err : new Error(String(err)));
66
- this.scheduleReconnect();
67
- }
61
+ }, this.listenKeyRefreshMs);
62
+ await this.ws.connectWsApi(this.creds);
63
+ this.pollAccountStatus();
64
+ this.pollTimer = setInterval(() => this.pollAccountStatus(), this.accountPollMs);
68
65
  }
69
- stop() {
70
- this.manualClose = true;
71
- this.stopAll();
72
- this.credentials = null;
73
- this.creds = null;
74
- this.trackedAssetInfos.clear();
75
- this.currentPositions.clear();
66
+ cleanupConnections() {
67
+ if (this.listenKeyTimer) clearInterval(this.listenKeyTimer);
68
+ if (this.pollTimer) clearInterval(this.pollTimer);
69
+ this.ws?.close();
70
+ }
71
+ async stop() {
72
+ this.stopped = true;
73
+ this.cleanupConnections();
76
74
  }
77
75
  get isConnected() {
78
76
  return this.ws?.isConnected ?? false;
79
77
  }
80
78
  onAssetTracked(coin) {
81
- if (!this.creds) return;
82
- fetchPositionRisk(this.creds, coin, this.demo).then((risk) => {
83
- if (!risk) return;
84
- const leverage = risk?.leverage;
85
- const marginType = risk?.marginType === "isolated" ? "isolated" : "cross";
86
- const info = {
87
- coin,
88
- leverage,
89
- marginType
90
- };
91
- this.trackedAssetInfos.set(coin, info);
92
- const trackedAssets = /* @__PURE__ */ new Map();
93
- trackedAssets.set(coin, info);
94
- this.onStateUpdate({ trackedAssets });
95
- }).catch((err) => {
96
- this.onError(err instanceof Error ? err : new Error(String(err)));
97
- });
79
+ this.assetTracker.onAssetTracked(coin);
98
80
  }
99
81
  onAssetUntracked(coin) {
100
- this.trackedAssetInfos.delete(coin);
101
- this.onStateUpdate({ trackedAssets: new Map(this.trackedAssetInfos) });
102
- }
103
- async setLeverage(symbol, leverage) {
104
- if (!this.creds) throw new Error("Not connected");
105
- await setLeverage(this.creds, symbol, leverage, this.demo);
106
- }
107
- stopAll() {
108
- if (this.listenKeyTimer) {
109
- clearInterval(this.listenKeyTimer);
110
- this.listenKeyTimer = null;
111
- }
112
- if (this.pollTimer) {
113
- clearInterval(this.pollTimer);
114
- this.pollTimer = null;
115
- }
116
- this.clearReconnectTimer();
117
- this.ws?.close();
118
- this.ws = null;
82
+ this.assetTracker.onAssetUntracked(coin);
119
83
  }
120
84
  pollAccountStatus() {
121
- if (!this.ws?.isConnected || !this.creds) return;
85
+ if (!this.ws?.isConnected) return;
122
86
  const id = this.ws.nextRequestId();
123
- this.ws.sendSignedRequest(id, "v3/account.status");
124
- }
125
- handleUserDataEvent(event) {
126
- if (event.e === "ACCOUNT_CONFIG_UPDATE" && event.ac) {
127
- const symbol = event.ac.s ?? "";
128
- const leverage = event.ac.l ?? "0";
129
- if (symbol && leverage !== "0") {
130
- const leverageSettings = /* @__PURE__ */ new Map();
131
- leverageSettings.set(symbol, leverage);
132
- const existing = this.trackedAssetInfos.get(symbol);
133
- if (existing) {
134
- const updated = { ...existing, leverage };
135
- this.trackedAssetInfos.set(symbol, updated);
136
- const trackedAssets = /* @__PURE__ */ new Map();
137
- trackedAssets.set(symbol, updated);
138
- this.onStateUpdate({ leverageSettings, trackedAssets });
139
- } else {
140
- this.onStateUpdate({ leverageSettings });
141
- }
142
- }
143
- this.refreshAllPositions();
144
- }
145
- if (event.e === "ACCOUNT_UPDATE") {
146
- this.refreshAllPositions();
147
- }
148
- }
149
- handleAccountStatus(result) {
150
- const balance = mapBalance(result);
151
- this.onStateUpdate({ balance });
152
- }
153
- handlePositionRisk(risk, merge) {
154
- let positions = mapPositions(risk);
155
- if (merge && this.currentPositions.size > 0) {
156
- positions = mergePositions(positions, this.currentPositions);
157
- }
158
- this.currentPositions = positions;
159
- const leverageSettings = /* @__PURE__ */ new Map();
160
- for (const p of risk) {
161
- if (p.symbol && p.leverage) {
162
- leverageSettings.set(p.symbol, p.leverage);
163
- }
164
- }
165
- this.onStateUpdate({ positions, leverageSettings });
166
- }
167
- refreshAllPositions() {
168
- if (!this.creds) return;
169
- const symbols = /* @__PURE__ */ new Set();
170
- for (const pos of this.currentPositions.values()) {
171
- symbols.add(pos.symbol);
172
- }
173
- for (const coin of this.trackedCoins) {
174
- symbols.add(coin);
175
- }
176
- if (symbols.size === 0) return;
177
- const creds = this.creds;
178
- const promises = Array.from(symbols).map(
179
- (symbol) => fetchPositionRisk(creds, symbol, this.demo).catch(() => void 0)
180
- );
181
- Promise.all(promises).then((results) => {
182
- const freshPositions = /* @__PURE__ */ new Map();
183
- for (const risk of results) {
184
- if (!risk) continue;
185
- const amt = risk.positionAmt ?? "0";
186
- if (amt === "0" || amt === "") continue;
187
- const symbol = risk.symbol ?? "";
188
- const side = amt.startsWith("-") ? "short" : "long";
189
- freshPositions.set(positionKey(symbol, side), {
190
- symbol,
191
- side,
192
- size: amt,
193
- entryPrice: risk.entryPrice ?? "0",
194
- unrealizedPnl: risk.unRealizedProfit ?? "0",
195
- leverage: risk.leverage ?? "0",
196
- marginType: risk.marginType === "isolated" ? "isolated" : "cross",
197
- liquidationPrice: risk.liquidationPrice || null
198
- });
199
- }
200
- for (const [key, pos] of this.currentPositions) {
201
- if (!symbols.has(pos.symbol) && !freshPositions.has(key)) {
202
- freshPositions.set(key, pos);
203
- }
204
- }
205
- this.currentPositions = freshPositions;
206
- this.onStateUpdate({ positions: freshPositions });
207
- }).catch((err) => {
208
- this.onError(err instanceof Error ? err : new Error(String(err)));
209
- });
87
+ this.ws.sendSignedRequest(id, "v2/account.status");
210
88
  }
211
89
  }
212
90
 
@@ -1,13 +1,14 @@
1
1
  import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
- import { BinanceRawAccountStatus, BinanceRawPositionRisk, BinanceAssetIndex, BinanceRawLeverageResponse } from './types.js';
3
- import '../../types.js';
2
+ import { j as BinanceRawAccountStatus, k as BinanceRawPositionRisk, l as BinanceAssetIndex } from '../../../types-D2dbAtin.js';
3
+ import '../bybit/types.js';
4
+ import '../hyperliquid/types.js';
4
5
 
5
6
  declare function createListenKey(apiKey: string, demo?: boolean): Promise<string>;
6
7
  declare function keepAliveListenKey(apiKey: string, demo?: boolean): Promise<void>;
7
8
  declare function fetchAccountStatus(creds: BinanceCredentialsDTO, demo: boolean): Promise<BinanceRawAccountStatus>;
8
9
  declare function fetchPositionRisk(creds: BinanceCredentialsDTO, symbol: string, demo: boolean): Promise<BinanceRawPositionRisk | undefined>;
9
10
  declare function fetchAllPositionRisk(creds: BinanceCredentialsDTO, demo: boolean): Promise<BinanceRawPositionRisk[]>;
10
- declare function setLeverage(creds: BinanceCredentialsDTO, symbol: string, leverage: string, demo: boolean): Promise<BinanceRawLeverageResponse>;
11
+ declare function fetchMultiAssetsMargin(creds: BinanceCredentialsDTO, demo: boolean): Promise<boolean>;
11
12
  declare function fetchAssetIndex(demo: boolean): Promise<BinanceAssetIndex[]>;
12
13
 
13
- export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchAssetIndex, fetchPositionRisk, keepAliveListenKey, setLeverage };
14
+ export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchAssetIndex, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
@@ -17,23 +17,6 @@ async function signedGet(creds, path, params, demo) {
17
17
  }
18
18
  return await response.json();
19
19
  }
20
- async function signedPost(creds, path, params, demo) {
21
- const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
22
- const timestamp = Date.now().toString();
23
- const allParams = { ...params, timestamp, recvWindow: "5000" };
24
- const queryString = new URLSearchParams(allParams).toString();
25
- const signature = await hmacSha256Hex(creds.read.api_secret, queryString);
26
- const response = await fetch(`${baseUrl}${path}?${queryString}&signature=${signature}`, {
27
- method: "POST",
28
- headers: { "X-MBX-APIKEY": creds.read.api_key }
29
- });
30
- if (!response.ok) {
31
- const body = await response.json().catch(() => null);
32
- const msg = body?.msg ?? response.statusText;
33
- throw new Error(`Binance API error ${response.status}: ${msg}`);
34
- }
35
- return await response.json();
36
- }
37
20
  async function createListenKey(apiKey, demo = false) {
38
21
  const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
39
22
  const response = await fetch(`${baseUrl}/fapi/v1/listenKey`, {
@@ -66,8 +49,9 @@ async function fetchPositionRisk(creds, symbol, demo) {
66
49
  async function fetchAllPositionRisk(creds, demo) {
67
50
  return signedGet(creds, "/fapi/v2/positionRisk", {}, demo);
68
51
  }
69
- async function setLeverage(creds, symbol, leverage, demo) {
70
- return signedPost(creds, "/fapi/v1/leverage", { symbol, leverage }, demo);
52
+ async function fetchMultiAssetsMargin(creds, demo) {
53
+ const res = await signedGet(creds, "/fapi/v1/multiAssetsMargin", {}, demo);
54
+ return res.multiAssetsMargin;
71
55
  }
72
56
  async function fetchAssetIndex(demo) {
73
57
  const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
@@ -78,4 +62,4 @@ async function fetchAssetIndex(demo) {
78
62
  return await response.json();
79
63
  }
80
64
 
81
- export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchAssetIndex, fetchPositionRisk, keepAliveListenKey, setLeverage };
65
+ export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchAssetIndex, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
@@ -0,0 +1,32 @@
1
+ import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
+ import { S as StateUpdate, h as TrackedAssetInfo, j as BinanceRawAccountStatus, k as BinanceRawPositionRisk, m as BinanceRawUserDataEvent } from '../../../types-D2dbAtin.js';
3
+ import '../bybit/types.js';
4
+ import '../hyperliquid/types.js';
5
+
6
+ type OnStateUpdate = (update: StateUpdate) => void;
7
+ type OnError = (error: Error) => void;
8
+ declare class BinanceStateHandler {
9
+ private onStateUpdate;
10
+ private onError;
11
+ private getCreds;
12
+ private getDemo;
13
+ private getTrackedCoins;
14
+ private getTrackedAssetInfos;
15
+ private currentPositions;
16
+ private accountType;
17
+ constructor(deps: {
18
+ onStateUpdate: OnStateUpdate;
19
+ onError: OnError;
20
+ getCreds: () => BinanceCredentialsDTO;
21
+ getDemo: () => boolean;
22
+ getTrackedCoins: () => ReadonlySet<string>;
23
+ getTrackedAssetInfos: () => Map<string, TrackedAssetInfo>;
24
+ });
25
+ setMultiAssetsMargin(value: boolean): void;
26
+ handleAccountStatus(result: BinanceRawAccountStatus): void;
27
+ handlePositionRisk(risk: BinanceRawPositionRisk[], merge: boolean): void;
28
+ handleUserDataEvent(event: BinanceRawUserDataEvent): void;
29
+ private refreshAllPositions;
30
+ }
31
+
32
+ export { BinanceStateHandler };
@@ -0,0 +1,113 @@
1
+ import { positionKey } from '../../utils';
2
+ import { mapBalance, mapPositions, mergePositions } from './mapper';
3
+ import { fetchPositionRisk } from './rest';
4
+ import { BinanceAccountType } from './types';
5
+
6
+ class BinanceStateHandler {
7
+ onStateUpdate;
8
+ onError;
9
+ getCreds;
10
+ getDemo;
11
+ getTrackedCoins;
12
+ getTrackedAssetInfos;
13
+ currentPositions = /* @__PURE__ */ new Map();
14
+ accountType = BinanceAccountType.SINGLE_ASSET;
15
+ constructor(deps) {
16
+ this.onStateUpdate = deps.onStateUpdate;
17
+ this.onError = deps.onError;
18
+ this.getCreds = deps.getCreds;
19
+ this.getDemo = deps.getDemo;
20
+ this.getTrackedCoins = deps.getTrackedCoins;
21
+ this.getTrackedAssetInfos = deps.getTrackedAssetInfos;
22
+ }
23
+ setMultiAssetsMargin(value) {
24
+ this.accountType = value ? BinanceAccountType.MULTI_ASSET : BinanceAccountType.SINGLE_ASSET;
25
+ }
26
+ handleAccountStatus(result) {
27
+ const balance = { ...mapBalance(result), accountType: this.accountType };
28
+ this.onStateUpdate({ balance });
29
+ }
30
+ handlePositionRisk(risk, merge) {
31
+ let positions = mapPositions(risk);
32
+ if (merge && this.currentPositions.size > 0) {
33
+ positions = mergePositions(positions, this.currentPositions);
34
+ }
35
+ this.currentPositions = positions;
36
+ const leverageSettings = /* @__PURE__ */ new Map();
37
+ for (const p of risk) {
38
+ if (p.symbol && p.leverage) {
39
+ leverageSettings.set(p.symbol, p.leverage);
40
+ }
41
+ }
42
+ this.onStateUpdate({ positions, leverageSettings });
43
+ }
44
+ handleUserDataEvent(event) {
45
+ if (event.e === "ACCOUNT_CONFIG_UPDATE" && event.ac) {
46
+ const symbol = event.ac.s ?? "";
47
+ const leverage = event.ac.l ?? "0";
48
+ if (symbol && leverage !== "0") {
49
+ const leverageSettings = /* @__PURE__ */ new Map();
50
+ leverageSettings.set(symbol, leverage);
51
+ const trackedAssetInfos = this.getTrackedAssetInfos();
52
+ const existing = trackedAssetInfos.get(symbol);
53
+ if (existing) {
54
+ const updated = { ...existing, leverage };
55
+ trackedAssetInfos.set(symbol, updated);
56
+ const trackedAssets = /* @__PURE__ */ new Map();
57
+ trackedAssets.set(symbol, updated);
58
+ this.onStateUpdate({ leverageSettings, trackedAssets });
59
+ } else {
60
+ this.onStateUpdate({ leverageSettings });
61
+ }
62
+ }
63
+ this.refreshAllPositions();
64
+ }
65
+ if (event.e === "ACCOUNT_UPDATE") {
66
+ this.refreshAllPositions();
67
+ }
68
+ }
69
+ refreshAllPositions() {
70
+ const creds = this.getCreds();
71
+ const demo = this.getDemo();
72
+ const symbols = /* @__PURE__ */ new Set();
73
+ for (const pos of this.currentPositions.values()) {
74
+ symbols.add(pos.symbol);
75
+ }
76
+ for (const coin of this.getTrackedCoins()) {
77
+ symbols.add(coin);
78
+ }
79
+ if (symbols.size === 0) return;
80
+ const promises = Array.from(symbols).map((symbol) => fetchPositionRisk(creds, symbol, demo).catch(() => void 0));
81
+ Promise.all(promises).then((results) => {
82
+ const freshPositions = /* @__PURE__ */ new Map();
83
+ for (const risk of results) {
84
+ if (!risk) continue;
85
+ const amt = risk.positionAmt ?? "0";
86
+ if (amt === "0" || amt === "") continue;
87
+ const symbol = risk.symbol ?? "";
88
+ const side = amt.startsWith("-") ? "short" : "long";
89
+ freshPositions.set(positionKey(symbol, side), {
90
+ symbol,
91
+ side,
92
+ size: amt,
93
+ entryPrice: risk.entryPrice ?? "0",
94
+ unrealizedPnl: risk.unRealizedProfit ?? "0",
95
+ leverage: risk.leverage ?? "0",
96
+ marginType: risk.marginType === "isolated" ? "isolated" : "cross",
97
+ liquidationPrice: risk.liquidationPrice || null
98
+ });
99
+ }
100
+ for (const [key, pos] of this.currentPositions) {
101
+ if (!symbols.has(pos.symbol) && !freshPositions.has(key)) {
102
+ freshPositions.set(key, pos);
103
+ }
104
+ }
105
+ this.currentPositions = freshPositions;
106
+ this.onStateUpdate({ positions: freshPositions });
107
+ }).catch((err) => {
108
+ this.onError(err instanceof Error ? err : new Error(String(err)));
109
+ });
110
+ }
111
+ }
112
+
113
+ export { BinanceStateHandler };