@imbingox/acex 0.3.0 → 0.4.0-beta.1

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.
package/README.md CHANGED
@@ -30,7 +30,7 @@ const book = client.market.getL1Book({
30
30
  symbol: "BTC/USDT:USDT",
31
31
  });
32
32
  const books = client.market.getL1Books("BTC/USDT:USDT");
33
- console.log(`bid=${book?.bidPrice.toFixed()} ask=${book?.askPrice.toFixed()}`);
33
+ console.log(`bid=${book?.bidPrice} ask=${book?.askPrice}`);
34
34
  console.log(`venues=${books.length}`);
35
35
  console.log(`book freshness=${book?.status.freshness}`);
36
36
 
@@ -44,14 +44,14 @@ const funding = client.market.getFundingRate({
44
44
  symbol: "BTC/USDT:USDT",
45
45
  });
46
46
  const fundingRates = client.market.getFundingRates("BTC/USDT:USDT");
47
- console.log(`funding=${funding?.fundingRate.toFixed()}`);
47
+ console.log(`funding=${funding?.fundingRate}`);
48
48
  console.log(`funding venues=${fundingRates.length}`);
49
49
 
50
50
  for await (const event of client.market.events.l1BookUpdates({
51
51
  venue: "binance",
52
52
  symbol: "BTC/USDT:USDT",
53
53
  })) {
54
- console.log(event.snapshot.bidPrice.toFixed());
54
+ console.log(event.snapshot.bidPrice);
55
55
  break;
56
56
  }
57
57
 
@@ -113,11 +113,11 @@ const juplendRisk = client.account.getRiskSnapshot("jup-loop-a");
113
113
  const juplendBalances = client.account.getBalances("jup-loop-a");
114
114
 
115
115
  for (const balance of juplendBalances) {
116
- console.log(balance.asset, balance.lending?.netAsset.toFixed());
116
+ console.log(balance.asset, balance.lending?.netAsset);
117
117
  }
118
118
  console.log({
119
- binanceRiskRatio: binanceRisk?.riskRatio?.toFixed(),
120
- juplendRiskRatio: juplendRisk?.riskRatio?.toFixed(),
119
+ binanceRiskRatio: binanceRisk?.riskRatio,
120
+ juplendRiskRatio: juplendRisk?.riskRatio,
121
121
  });
122
122
 
123
123
  await client.stop();
@@ -141,7 +141,7 @@ console.log(juplend.order.reason); // "read_only"
141
141
  const capabilities = client.listVenueCapabilities();
142
142
  ```
143
143
 
144
- 价格、数量等输出字段统一是 `BigNumber`;`createOrder()` 的 `price` / `amount` 输入仍接受 decimal string。详见手册 [§3 核心概念](./docs/api.md#3-核心概念)。
144
+ 价格、数量等公共输出字段统一是 canonical decimal string(无科学计数法、不补尾零);输入侧保持宽进严出,`createOrder()` 的 `price` / `amount` decimal string,`DecimalInput` 仍接受 string / number / `BigNumber`。如需运算,使用 SDK re-export 的 `BigNumber`:`new BigNumber(field)`。详见手册 [§3 核心概念](./docs/api.md#3-核心概念)。
145
145
 
146
146
  ## 核心能力
147
147
 
package/docs/api.md CHANGED
@@ -51,13 +51,13 @@ const book = client.market.getL1Book({
51
51
  venue: "binance",
52
52
  symbol: "BTC/USDT:USDT",
53
53
  });
54
- console.log(`bid=${book?.bidPrice.toFixed()} ask=${book?.askPrice.toFixed()}`);
54
+ console.log(`bid=${book?.bidPrice} ask=${book?.askPrice}`);
55
55
 
56
56
  for await (const event of client.market.events.l1BookUpdates({
57
57
  venue: "binance",
58
58
  symbol: "BTC/USDT:USDT",
59
59
  })) {
60
- console.log(event.snapshot.bidPrice.toFixed());
60
+ console.log(event.snapshot.bidPrice);
61
61
  break;
62
62
  }
63
63
 
@@ -114,8 +114,8 @@ await client.account.subscribeAccount({ accountId: "jup-loop-a" });
114
114
  const binanceRisk = client.account.getRiskSnapshot("main-binance");
115
115
  const juplendRisk = client.account.getRiskSnapshot("jup-loop-a");
116
116
 
117
- console.log(binanceRisk?.riskRatio?.toFixed());
118
- console.log(juplendRisk?.riskRatio?.toFixed());
117
+ console.log(binanceRisk?.riskRatio);
118
+ console.log(juplendRisk?.riskRatio);
119
119
  ```
120
120
 
121
121
  需要账户或订单能力时,在 `start()` 前后任意时刻 `registerAccount()`:
@@ -182,19 +182,19 @@ await client.market.subscribeL1Book({ venue, symbol });
182
182
 
183
183
  退订后 `activity` 变为 `"inactive"`,但最后一份快照仍可读——不要把它当实时值。
184
184
 
185
- ### 3.5 BigNumber 约定
185
+ ### 3.5 Decimal string 约定
186
186
 
187
- 输出侧的价格、数量、金额统一是 `BigNumber`(来自 [bignumber.js](https://github.com/MikeMcl/bignumber.js),SDK 已 re-export):
187
+ 输出侧的价格、数量、金额统一是 canonical 十进制 string:无损、无科学计数法、不补尾零。SDK 仍 re-export `BigNumber`(来自 [bignumber.js](https://github.com/MikeMcl/bignumber.js))作为可选工具;需要运算时由调用方显式解析:
188
188
 
189
189
  ```ts
190
190
  import { BigNumber } from "@imbingox/acex";
191
191
 
192
192
  const book = client.market.getL1Book({ venue, symbol });
193
- const spread = book!.askPrice.minus(book!.bidPrice); // BigNumber
193
+ const spread = new BigNumber(book!.askPrice).minus(new BigNumber(book!.bidPrice));
194
194
  console.log(spread.toFixed());
195
195
  ```
196
196
 
197
- **输入侧不对称**:`createOrder()` 的 `price` / `amount` 仍接受 decimal string。这是为了让调用方直接从交易所精度(`MarketDefinition.priceStep` / `amountStep`)做字符串格式化,不必先转 BigNumber 再转字符串。
197
+ 不要用 `parseFloat()` 解析输出字段,否则会退回 JS 浮点精度。输入侧保持宽进严出:`createOrder()` 的 `price` / `amount` decimal string,`normalizeOrderInput()` 的 `DecimalInput` 仍接受 string / number / `BigNumber`,但公共输出一律是 canonical decimal string。
198
198
 
199
199
  ## 4. Client 生命周期
200
200
 
@@ -378,7 +378,7 @@ const allBtcPerp = client.market.getMarkets("BTC/USDT:USDT");
378
378
 
379
379
  `getMarkets(symbol)` 严格按完整统一 symbol 匹配。
380
380
 
381
- `MarketDefinition` 见 [§9](#9-数据类型参考)。价格/数量相关字段(`priceStep`、`amountStep`、`contractSize`、`minAmount`、`minNotional`)都是 `BigNumber`。
381
+ `MarketDefinition` 见 [§9](#9-数据类型参考)。价格/数量相关字段(`priceStep`、`amountStep`、`contractSize`、`minAmount`、`minNotional`)都是 canonical decimal string;需要运算时用 `new BigNumber(field)` 自行解析。
382
382
 
383
383
  归一化下单价格和数量:
384
384
 
@@ -459,7 +459,7 @@ const book = client.market.getL1Book({
459
459
  });
460
460
 
461
461
  if (book) {
462
- const spread = book.askPrice.minus(book.bidPrice);
462
+ const spread = new BigNumber(book.askPrice).minus(new BigNumber(book.bidPrice));
463
463
  console.log(`spread=${spread.toFixed()}`);
464
464
  }
465
465
  ```
@@ -471,7 +471,7 @@ for await (const event of client.market.events.l1BookUpdates({
471
471
  venue: "binance",
472
472
  symbol: "BTC/USDT:USDT",
473
473
  })) {
474
- console.log(event.snapshot.bidPrice.toFixed());
474
+ console.log(event.snapshot.bidPrice);
475
475
  }
476
476
  ```
477
477
 
@@ -529,9 +529,9 @@ const funding = client.market.getFundingRate({
529
529
  });
530
530
 
531
531
  if (funding) {
532
- console.log(funding.fundingRate.toFixed());
533
- console.log(funding.markPrice?.toFixed());
534
- console.log(funding.indexPrice?.toFixed());
532
+ console.log(funding.fundingRate);
533
+ console.log(funding.markPrice);
534
+ console.log(funding.indexPrice);
535
535
  console.log(funding.nextFundingTime);
536
536
  console.log(funding.status.freshness);
537
537
  }
@@ -544,7 +544,7 @@ for await (const event of client.market.events.fundingRateUpdates({
544
544
  venue: "binance",
545
545
  symbol: "BTC/USDT:USDT",
546
546
  })) {
547
- console.log(event.snapshot.fundingRate.toFixed());
547
+ console.log(event.snapshot.fundingRate);
548
548
  }
549
549
  ```
550
550
 
@@ -638,7 +638,7 @@ const btcPosition = client.account.getPosition({
638
638
  const risk = client.account.getRiskSnapshot("main-binance");
639
639
  ```
640
640
 
641
- 所有数量字段(`free` / `used` / `total` / `size` / `entryPrice` / `netEquity` / `riskEquity` / ...)都是 `BigNumber`。
641
+ 所有数量字段(`free` / `used` / `total` / `size` / `entryPrice` / `netEquity` / `riskEquity` / ...)都是 canonical decimal string;需要运算时用 `new BigNumber(field)` 自行解析。
642
642
 
643
643
  `RiskSnapshot.netEquity` 表示不含风控折算的净资产价值;`riskEquity` 表示抵押系数或清算阈值折算后的风控净权益。Binance 使用 `actualEquity` / `accountEquity` 映射这两个字段;Juplend 使用 `totalCollateralUsd - totalDebtUsd` / `Σ(suppliedValue × liquidationThreshold) - totalDebtUsd`。
644
644
 
@@ -652,13 +652,13 @@ for await (const event of client.account.events.updates({
652
652
  })) {
653
653
  switch (event.type) {
654
654
  case "balance.updated":
655
- console.log(event.asset, event.snapshot.free.toFixed());
655
+ console.log(event.asset, event.snapshot.free);
656
656
  break;
657
657
  case "position.updated":
658
- console.log(event.symbol, event.snapshot.size.toFixed());
658
+ console.log(event.symbol, event.snapshot.size);
659
659
  break;
660
660
  case "risk.updated":
661
- console.log(event.snapshot.riskRatio?.toFixed());
661
+ console.log(event.snapshot.riskRatio);
662
662
  break;
663
663
  case "account.snapshot_replaced":
664
664
  // 私有链路重连/重对账后的全量替换
@@ -801,10 +801,10 @@ for await (const event of client.order.events.updates({
801
801
  })) {
802
802
  switch (event.type) {
803
803
  case "order.updated":
804
- console.log("更新", event.snapshot.status, event.snapshot.filled.toFixed());
804
+ console.log("更新", event.snapshot.status, event.snapshot.filled);
805
805
  break;
806
806
  case "order.filled":
807
- console.log("全部成交", event.snapshot.avgFillPrice?.toFixed());
807
+ console.log("全部成交", event.snapshot.avgFillPrice);
808
808
  break;
809
809
  case "order.canceled":
810
810
  console.log("已撤单");
@@ -1100,13 +1100,13 @@ interface MarketDefinition {
1100
1100
  contract: boolean;
1101
1101
  linear?: boolean;
1102
1102
  inverse?: boolean;
1103
- contractSize?: BigNumber;
1103
+ contractSize?: string;
1104
1104
  pricePrecision: number;
1105
1105
  amountPrecision: number;
1106
- priceStep: BigNumber;
1107
- amountStep: BigNumber;
1108
- minAmount?: BigNumber;
1109
- minNotional?: BigNumber;
1106
+ priceStep: string;
1107
+ amountStep: string;
1108
+ minAmount?: string;
1109
+ minNotional?: string;
1110
1110
  expiry?: number;
1111
1111
  raw: Record<string, unknown>;
1112
1112
  }
@@ -1155,10 +1155,10 @@ interface MarketEventFilter {
1155
1155
  interface L1Book {
1156
1156
  venue: Venue;
1157
1157
  symbol: string;
1158
- bidPrice: BigNumber;
1159
- bidSize: BigNumber;
1160
- askPrice: BigNumber;
1161
- askSize: BigNumber;
1158
+ bidPrice: string;
1159
+ bidSize: string;
1160
+ askPrice: string;
1161
+ askSize: string;
1162
1162
  exchangeTs?: number;
1163
1163
  receivedAt: number;
1164
1164
  updatedAt: number;
@@ -1169,10 +1169,10 @@ interface L1Book {
1169
1169
  interface FundingRateSnapshot {
1170
1170
  venue: Venue;
1171
1171
  symbol: string;
1172
- fundingRate: BigNumber;
1172
+ fundingRate: string;
1173
1173
  nextFundingTime?: number;
1174
- markPrice?: BigNumber;
1175
- indexPrice?: BigNumber;
1174
+ markPrice?: string;
1175
+ indexPrice?: string;
1176
1176
  exchangeTs?: number;
1177
1177
  receivedAt: number;
1178
1178
  updatedAt: number;
@@ -1210,9 +1210,9 @@ interface BalanceSnapshot {
1210
1210
  accountId: string;
1211
1211
  venue: Venue;
1212
1212
  asset: string;
1213
- free: BigNumber;
1214
- used: BigNumber;
1215
- total: BigNumber;
1213
+ free: string;
1214
+ used: string;
1215
+ total: string;
1216
1216
  exchangeTs?: number;
1217
1217
  receivedAt: number;
1218
1218
  updatedAt: number;
@@ -1221,12 +1221,12 @@ interface BalanceSnapshot {
1221
1221
  }
1222
1222
 
1223
1223
  interface LendingBalanceFacet {
1224
- supplied: BigNumber;
1225
- borrowed: BigNumber;
1226
- interest: BigNumber;
1227
- netAsset: BigNumber;
1228
- supplyAPY?: BigNumber;
1229
- borrowAPY?: BigNumber;
1224
+ supplied: string;
1225
+ borrowed: string;
1226
+ interest: string;
1227
+ netAsset: string;
1228
+ supplyAPY?: string;
1229
+ borrowAPY?: string;
1230
1230
  }
1231
1231
 
1232
1232
  interface PositionSnapshot {
@@ -1234,12 +1234,12 @@ interface PositionSnapshot {
1234
1234
  venue: Venue;
1235
1235
  symbol: string;
1236
1236
  side: PositionSide;
1237
- size: BigNumber;
1238
- entryPrice?: BigNumber;
1239
- markPrice?: BigNumber;
1240
- unrealizedPnl?: BigNumber;
1241
- leverage?: BigNumber;
1242
- liquidationPrice?: BigNumber;
1237
+ size: string;
1238
+ entryPrice?: string;
1239
+ markPrice?: string;
1240
+ unrealizedPnl?: string;
1241
+ leverage?: string;
1242
+ liquidationPrice?: string;
1243
1243
  exchangeTs?: number;
1244
1244
  receivedAt: number;
1245
1245
  updatedAt: number;
@@ -1249,12 +1249,12 @@ interface PositionSnapshot {
1249
1249
  interface RiskSnapshot {
1250
1250
  accountId: string;
1251
1251
  venue: Venue;
1252
- netEquity?: BigNumber;
1253
- riskEquity?: BigNumber;
1254
- riskRatio?: BigNumber;
1255
- riskLeverage?: BigNumber;
1256
- initialMargin?: BigNumber;
1257
- maintenanceMargin?: BigNumber;
1252
+ netEquity?: string;
1253
+ riskEquity?: string;
1254
+ riskRatio?: string;
1255
+ riskLeverage?: string;
1256
+ initialMargin?: string;
1257
+ maintenanceMargin?: string;
1258
1258
  exchangeTs?: number;
1259
1259
  receivedAt: number;
1260
1260
  updatedAt: number;
@@ -1263,12 +1263,12 @@ interface RiskSnapshot {
1263
1263
  }
1264
1264
 
1265
1265
  interface LendingRiskFacet {
1266
- marginLevel?: BigNumber;
1267
- healthFactor?: BigNumber;
1268
- ltv?: BigNumber;
1269
- liquidationThreshold?: BigNumber;
1270
- totalCollateralUSD?: BigNumber;
1271
- totalDebtUSD?: BigNumber;
1266
+ marginLevel?: string;
1267
+ healthFactor?: string;
1268
+ ltv?: string;
1269
+ liquidationThreshold?: string;
1270
+ totalCollateralUSD?: string;
1271
+ totalDebtUSD?: string;
1272
1272
  }
1273
1273
 
1274
1274
  interface AccountSnapshot {
@@ -1350,14 +1350,14 @@ interface OrderSnapshot {
1350
1350
  side: OrderSide;
1351
1351
  type: string; // 交易所原始 type 字符串
1352
1352
  status: OrderStatus;
1353
- price?: BigNumber;
1354
- triggerPrice?: BigNumber;
1355
- amount: BigNumber;
1356
- filled: BigNumber;
1357
- remaining?: BigNumber;
1353
+ price?: string;
1354
+ triggerPrice?: string;
1355
+ amount: string;
1356
+ filled: string;
1357
+ remaining?: string;
1358
1358
  reduceOnly?: boolean;
1359
1359
  positionSide?: PositionSide;
1360
- avgFillPrice?: BigNumber;
1360
+ avgFillPrice?: string;
1361
1361
  exchangeTs?: number;
1362
1362
  receivedAt: number;
1363
1363
  updatedAt: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imbingox/acex",
3
- "version": "0.3.0",
3
+ "version": "0.4.0-beta.1",
4
4
  "description": "Multi-exchange trading SDK for market data, account, and order management",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,4 @@
1
+ import { SubscriptionMultiplexer } from "../../internal/subscription-multiplexer.ts";
1
2
  import type {
2
3
  MarketDefinition,
3
4
  VenueMarketCapabilities,
@@ -10,12 +11,34 @@ import type {
10
11
  MarketAdapter,
11
12
  StreamHandle,
12
13
  } from "../types.ts";
13
- import { subscribeBinanceBookTicker } from "./book-ticker.ts";
14
- import { subscribeBinanceMarkPrice } from "./mark-price.ts";
15
14
  import {
16
15
  type BinanceMarketDefinition,
17
16
  loadBinanceMarkets,
18
17
  } from "./market-catalog.ts";
18
+ import {
19
+ type BinanceStreamDescriptor,
20
+ type BinanceStreamMessage,
21
+ type BinanceStreamPayload,
22
+ BinanceStreamProtocol,
23
+ } from "./stream-protocol.ts";
24
+
25
+ const BINANCE_CONTROL_FRAME_MAX_PER_SEC = 5;
26
+ // Binance allows up to 1024 streams per connection; keep a conservative pool cap.
27
+ const BINANCE_MAX_SUBSCRIPTIONS_PER_CONNECTION = 200;
28
+
29
+ type BinanceMarketMultiplexer = SubscriptionMultiplexer<
30
+ BinanceStreamMessage,
31
+ BinanceStreamDescriptor,
32
+ BinanceStreamPayload
33
+ >;
34
+
35
+ interface BinanceMultiplexerConfig {
36
+ readonly initialMessageTimeoutMs: number;
37
+ readonly staleAfterMs: number;
38
+ readonly reconnectDelayMs: number;
39
+ readonly reconnectMaxDelayMs: number;
40
+ readonly now?: () => number;
41
+ }
19
42
 
20
43
  export class BinanceMarketAdapter implements MarketAdapter {
21
44
  readonly venue = "binance" as const;
@@ -27,6 +50,8 @@ export class BinanceMarketAdapter implements MarketAdapter {
27
50
  };
28
51
 
29
52
  private readonly definitions = new Map<string, BinanceMarketDefinition>();
53
+ private multiplexer: BinanceMarketMultiplexer | undefined;
54
+ private multiplexerConfig: BinanceMultiplexerConfig | undefined;
30
55
 
31
56
  async loadMarkets(): Promise<MarketDefinition[]> {
32
57
  const markets = await loadBinanceMarkets();
@@ -49,18 +74,38 @@ export class BinanceMarketAdapter implements MarketAdapter {
49
74
  throw new Error(`Unknown Binance market: ${market.symbol}`);
50
75
  }
51
76
 
52
- return subscribeBinanceBookTicker(
53
- binanceMarket,
77
+ const handle = this.getMultiplexer(options).subscribe(
78
+ {
79
+ channel: "l1book",
80
+ market: binanceMarket,
81
+ },
54
82
  {
55
- onBookTicker(update) {
56
- callbacks.onUpdate(update);
83
+ onPayload(payload, receivedAt) {
84
+ if (payload.channel !== "l1book") {
85
+ return;
86
+ }
87
+
88
+ callbacks.onUpdate({
89
+ bidPrice: payload.bidPrice,
90
+ bidSize: payload.bidSize,
91
+ askPrice: payload.askPrice,
92
+ askSize: payload.askSize,
93
+ exchangeTs: payload.exchangeTs,
94
+ receivedAt,
95
+ });
57
96
  },
58
97
  onFreshnessChange: callbacks.onFreshnessChange,
59
98
  onDisconnected: callbacks.onDisconnected,
60
99
  onError: callbacks.onError,
61
100
  },
62
- options,
63
101
  );
102
+
103
+ return {
104
+ ready: handle.ready,
105
+ close(): void {
106
+ handle.close();
107
+ },
108
+ };
64
109
  }
65
110
 
66
111
  createFundingRateStream(
@@ -73,17 +118,91 @@ export class BinanceMarketAdapter implements MarketAdapter {
73
118
  throw new Error(`Unknown Binance market: ${market.symbol}`);
74
119
  }
75
120
 
76
- return subscribeBinanceMarkPrice(
77
- binanceMarket,
121
+ const handle = this.getMultiplexer(options).subscribe(
78
122
  {
79
- onFundingRate(update) {
80
- callbacks.onUpdate(update);
123
+ channel: "fundingRate",
124
+ market: binanceMarket,
125
+ },
126
+ {
127
+ onPayload(payload, receivedAt) {
128
+ if (payload.channel !== "fundingRate") {
129
+ return;
130
+ }
131
+
132
+ callbacks.onUpdate({
133
+ fundingRate: payload.fundingRate,
134
+ nextFundingTime: payload.nextFundingTime,
135
+ markPrice: payload.markPrice,
136
+ indexPrice: payload.indexPrice,
137
+ exchangeTs: payload.exchangeTs,
138
+ receivedAt,
139
+ });
81
140
  },
82
141
  onFreshnessChange: callbacks.onFreshnessChange,
83
142
  onDisconnected: callbacks.onDisconnected,
84
143
  onError: callbacks.onError,
85
144
  },
86
- options,
87
145
  );
146
+
147
+ return {
148
+ ready: handle.ready,
149
+ close(): void {
150
+ handle.close();
151
+ },
152
+ };
153
+ }
154
+
155
+ private getMultiplexer(
156
+ options: L1BookStreamOptions | FundingRateStreamOptions,
157
+ ): BinanceMarketMultiplexer {
158
+ const config: BinanceMultiplexerConfig = {
159
+ initialMessageTimeoutMs: options.initialMessageTimeoutMs,
160
+ staleAfterMs: options.staleAfterMs,
161
+ reconnectDelayMs: options.reconnectDelayMs,
162
+ reconnectMaxDelayMs: options.reconnectMaxDelayMs,
163
+ now: options.now,
164
+ };
165
+
166
+ if (!this.multiplexer) {
167
+ this.multiplexer = new SubscriptionMultiplexer(
168
+ new BinanceStreamProtocol(),
169
+ {
170
+ initialMessageTimeoutMs: config.initialMessageTimeoutMs,
171
+ staleAfterMs: config.staleAfterMs,
172
+ reconnectDelayMs: config.reconnectDelayMs,
173
+ reconnectMaxDelayMs: config.reconnectMaxDelayMs,
174
+ controlFrameMaxPerSec: BINANCE_CONTROL_FRAME_MAX_PER_SEC,
175
+ maxSubscriptionsPerConnection:
176
+ BINANCE_MAX_SUBSCRIPTIONS_PER_CONNECTION,
177
+ now: config.now,
178
+ },
179
+ );
180
+ this.multiplexerConfig = config;
181
+ return this.multiplexer;
182
+ }
183
+
184
+ if (
185
+ !this.multiplexerConfig ||
186
+ !sameMultiplexerConfig(config, this.multiplexerConfig)
187
+ ) {
188
+ throw new Error(
189
+ "Binance market stream options differ from the active multiplexer; create a new adapter instance for different stream timing options",
190
+ );
191
+ }
192
+
193
+ return this.multiplexer;
88
194
  }
89
195
  }
196
+
197
+ function sameMultiplexerConfig(
198
+ left: BinanceMultiplexerConfig,
199
+ right: BinanceMultiplexerConfig,
200
+ ): boolean {
201
+ return (
202
+ left.initialMessageTimeoutMs === right.initialMessageTimeoutMs &&
203
+ left.staleAfterMs === right.staleAfterMs &&
204
+ left.reconnectDelayMs === right.reconnectDelayMs &&
205
+ left.reconnectMaxDelayMs === right.reconnectMaxDelayMs &&
206
+ left.now === right.now
207
+ );
208
+ }
@@ -1,4 +1,4 @@
1
- import BigNumber from "bignumber.js";
1
+ import { toCanonical } from "../../internal/decimal.ts";
2
2
  import type { MarketDefinition, MarketType } from "../../types/index.ts";
3
3
 
4
4
  type FetchLike = typeof fetch;
@@ -146,12 +146,12 @@ function normalizeSpotSymbol(
146
146
  contract: false,
147
147
  pricePrecision: precisionFromStep(priceStep),
148
148
  amountPrecision: precisionFromStep(amountStep),
149
- priceStep: new BigNumber(priceStep),
150
- amountStep: new BigNumber(amountStep),
149
+ priceStep: toCanonical(priceStep),
150
+ amountStep: toCanonical(amountStep),
151
151
  minAmount: lotSizeFilter?.minQty
152
- ? new BigNumber(lotSizeFilter.minQty)
152
+ ? toCanonical(lotSizeFilter.minQty)
153
153
  : undefined,
154
- minNotional: notionalValue ? new BigNumber(notionalValue) : undefined,
154
+ minNotional: notionalValue ? toCanonical(notionalValue) : undefined,
155
155
  raw: toRecord(symbol),
156
156
  };
157
157
  }
@@ -198,15 +198,15 @@ function normalizeDerivativesSymbol(
198
198
  contract: true,
199
199
  linear: family === "usdm",
200
200
  inverse: family === "coinm",
201
- contractSize: contractSize ? new BigNumber(contractSize) : undefined,
201
+ contractSize: contractSize ? toCanonical(contractSize) : undefined,
202
202
  pricePrecision: precisionFromStep(priceStep),
203
203
  amountPrecision: precisionFromStep(amountStep),
204
- priceStep: new BigNumber(priceStep),
205
- amountStep: new BigNumber(amountStep),
204
+ priceStep: toCanonical(priceStep),
205
+ amountStep: toCanonical(amountStep),
206
206
  minAmount: lotSizeFilter?.minQty
207
- ? new BigNumber(lotSizeFilter.minQty)
207
+ ? toCanonical(lotSizeFilter.minQty)
208
208
  : undefined,
209
- minNotional: notionalValue ? new BigNumber(notionalValue) : undefined,
209
+ minNotional: notionalValue ? toCanonical(notionalValue) : undefined,
210
210
  expiry: type === "future" ? symbol.deliveryDate : undefined,
211
211
  raw: toRecord(symbol),
212
212
  };