@nemesis-oss/binance-sdk 1.0.0 → 2.0.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.
package/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # binance-sdk
2
2
 
3
- TypeScript SDK for Binance — **Spot + USD-M Futures**, REST + WebSocket, public market data
4
- and authenticated trading, with zod-validated typed responses.
3
+ TypeScript SDK for Binance — **Spot, USD-M Futures, COIN-M Futures, Margin, Wallet, and
4
+ Sub-account**, REST + WebSocket, public market data and authenticated trading, with
5
+ zod-validated typed responses throughout.
5
6
 
6
7
  Canonical Binance client for the `trading-workspace` `sdk/` directory (mirrors `sdk/dhanhq-ts`'s
7
- role for DhanHQ). Feature-parity with `binance-client-js` (REST + WS), with typed schemas.
8
+ role for DhanHQ). Feature-parity with `binance-client-js` (REST + WS), with typed schemas, plus
9
+ production infrastructure (header-based rate-limit tracking, server time sync, HMAC/Ed25519/RSA
10
+ signing) and client-side safety guardrails for autonomous/LLM-driven callers.
8
11
 
9
12
  ## Install
10
13
 
@@ -91,6 +94,34 @@ client.closeUserStream();
91
94
  await client.startSpotUserStream();
92
95
  client.spot.wsUser.on('executionReport', (event) => console.log(event.s));
93
96
  client.closeSpotUserStream();
97
+
98
+ // COIN-M Futures (inverse contracts, margined in the base asset)
99
+ const coinmBalance = await client.coinm.account.balance();
100
+ await client.coinm.trading.createOrder({
101
+ symbol: 'BTCUSD_PERP',
102
+ side: 'BUY',
103
+ type: 'LIMIT',
104
+ price: 60000,
105
+ quantity: 1, // contracts, not base-asset quantity
106
+ timeInForce: 'GTC',
107
+ });
108
+ client.coinm.ws.subscribe([client.coinm.ws.kline('BTCUSD_PERP', '1m')]);
109
+ await client.startCoinMUserStream();
110
+
111
+ // Margin (cross + isolated)
112
+ const marginAccount = await client.margin.account.crossAccount();
113
+ await client.margin.account.borrow('USDT', 100);
114
+ await client.margin.trading.createOrder({ symbol: 'BTCUSDT', side: 'BUY', type: 'LIMIT', price: 60000, quantity: 0.001 });
115
+
116
+ // Wallet
117
+ await client.wallet.universalTransfer({ type: 'MAIN_UMFUTURE', asset: 'USDT', amount: 500 });
118
+ const deposits = await client.wallet.depositHistory({ coin: 'USDT' });
119
+
120
+ // Sub-accounts (master account only)
121
+ const subAccounts = await client.subaccount.list();
122
+
123
+ // Server time sync — mitigates -1021 (timestamp outside recvWindow) from local clock drift
124
+ await client.syncTime();
94
125
  ```
95
126
 
96
127
  ## API Surface
@@ -105,6 +136,49 @@ client.closeSpotUserStream();
105
136
  - `ws` — market WebSocket streams (kline, trade, aggTrade, depth incl. diff-depth, ticker incl.
106
137
  rolling-window, bookTicker, miniTicker, avgPrice + all-market/arr variants)
107
138
  - `wsUser` — spot user data stream (executionReport, outboundAccountPosition, balanceUpdate, listStatus)
139
+ - `wsApi` — Spot WebSocket API (`wss://ws-api.binance.com/ws-api/v3`): signed trading
140
+ (`order.place/test/cancel/cancelReplace/status`, `openOrders.status/cancelAll`,
141
+ `orderList.place/cancel/status`, `openOrderLists.status`), account (`account.status/commission`,
142
+ `allOrders`, `allOrderLists`, `myTrades`), `userDataStream.start/ping/stop`, and public market
143
+ data (`ping`, `time`, `exchangeInfo`, `depth`, `trades.recent/historical/aggregate`, `klines`,
144
+ `uiKlines`, `avgPrice`, `ticker.24hr/tradingDay/price/book`) — its own method names, distinct
145
+ from the futures WS API below.
146
+
147
+ ### COIN-M Futures (`client.coinm`)
148
+
149
+ Inverse contracts (e.g. `BTCUSD_PERP`) margined in the base asset rather than USDT — same shape
150
+ as `client.futures`, against `dapi.binance.com`.
151
+
152
+ - `market` — klines (incl. continuous/index/mark-price variants), funding-rate history, open
153
+ interest + history, premium index, plus the standard public REST inherited from spot/futures
154
+ - `account` — balance, account info, position risk, income history, user trades, leverage
155
+ brackets, commission rate, position mode
156
+ - `trading` — order lifecycle (create/test/get/cancel/cancelAll/all), leverage/margin-type
157
+ changes, position margin
158
+ - `userStream` — listenKey lifecycle (create / keep-alive / close)
159
+ - `ws` — market WebSocket streams, same naming scheme as `client.futures.ws`
160
+ - `wsUser` — user data stream (ACCOUNT_UPDATE, ORDER_TRADE_UPDATE, MARGIN_CALL)
161
+
162
+ ### Margin (`client.margin`)
163
+
164
+ Cross and isolated margin trading.
165
+
166
+ - `account` — cross/isolated account info, max borrowable/transferable, `borrow`/`repay` (via
167
+ the unified `borrow-repay` endpoint), cross/isolated transfers, interest history,
168
+ force-liquidation history, price index
169
+ - `trading` — order lifecycle (create/get/cancel/cancelAll/all), myTrades
170
+
171
+ ### Wallet (`client.wallet`)
172
+
173
+ - Universal transfer (+ history) between Spot/Margin/USD-M/COIN-M/Funding
174
+ - Deposit history, deposit address, withdraw history, withdraw submission
175
+ - Funding wallet / user asset queries, account snapshot, API key permissions, asset detail
176
+ - Dust log + dust-to-BNB conversion, trade fees
177
+
178
+ ### Sub-account (`client.subaccount`, master account only)
179
+
180
+ List/status, spot/futures/margin summaries, universal transfer (+ history), virtual sub-account
181
+ creation, futures/margin enablement, deposit address/history.
108
182
 
109
183
  ### Futures (`client.futures`)
110
184
 
@@ -134,13 +208,62 @@ client.closeSpotUserStream();
134
208
 
135
209
  ### Client options
136
210
 
137
- `apiKey`, `apiSecret`, `testnet`, `demo`, `recvWindow`, `apiBase`, `wsBase`, `wsUserBase`,
138
- `wsApiBase`, `timeoutMs`, `maxRetries`, `retryBaseDelayMs`, `retryMaxDelayMs`.
211
+ `apiKey`, `apiSecret`, `privateKey` + `signatureAlgorithm` (Ed25519/RSA, instead of HMAC),
212
+ `testnet`, `demo`, `recvWindow`, `apiBase`, `wsBase`, `wsUserBase`, `wsApiBase`, `dapiBase`,
213
+ `wsSpotApiBase`, `wsDapiBase`, `timeoutMs`, `maxRetries`, `retryBaseDelayMs`, `retryMaxDelayMs`,
214
+ `rateLimitWeightPerMinute`, `rateLimitSafetyMargin`, `httpsAgent`, `proxy`, `safety`
215
+ (see [Agent safety](#agent-safety)).
216
+
217
+ ### Reliability
218
+
219
+ - **Rate-limit tracking**: `RateLimitTracker` parses `X-MBX-USED-WEIGHT-*` /
220
+ `X-MBX-ORDER-COUNT-*` response headers and delays queued requests once usage crosses a
221
+ configurable safety margin (`rateLimitWeightPerMinute` / `rateLimitSafetyMargin`), to preempt
222
+ `-1003` IP bans rather than react to them. Inspect the live per-host snapshot via
223
+ `client.getRateLimitUsage()`.
224
+ - **Server time sync**: `client.syncTime()` fetches each REST host's server time and applies the
225
+ offset to every signed request's `timestamp`, mitigating `-1021` errors from local clock drift.
226
+ - **Retry**: exponential backoff with jitter on `429`/`418`/`5xx`, configurable via
227
+ `maxRetries`/`retryBaseDelayMs`/`retryMaxDelayMs`.
228
+
229
+ ### Agent safety
230
+
231
+ `BinanceClientOptions.safety` configures a `TradingPolicy`, evaluated on every mutating request
232
+ before it leaves the process — for autonomous/LLM-driven callers where a misread prompt
233
+ shouldn't be able to spend the account. Shared across every product namespace.
234
+
235
+ ```typescript
236
+ const client = new BinanceClient({
237
+ apiKey, apiSecret,
238
+ safety: {
239
+ dryRun: true, // throws DryRunError instead of sending the request
240
+ allowedSymbols: ['BTCUSDT', 'ETHUSDT'],
241
+ maxNotionalPerOrder: 100, // an order whose notional can't be verified is refused
242
+ allowWithdrawals: false, // default once `safety` is set at all
243
+ },
244
+ });
245
+ ```
246
+
247
+ - `dryRun` — intercepts `POST`/`PUT`/`DELETE` and throws `DryRunError` (carrying the request that
248
+ would have been sent, via `.describe()`) instead of sending it. It never returns a synthetic
249
+ success payload — a fabricated `orderId` would lead a caller to believe an order exists.
250
+ - `readOnly` — refuses mutating requests outright.
251
+ - `allowedSymbols` — rejects orders naming a symbol outside the list.
252
+ - `maxNotionalPerOrder` — caps a single order's notional (from `price*quantity` or
253
+ `quoteOrderQty`); an order whose notional can't be determined (e.g. a MARKET order with no
254
+ price) is refused rather than waved through.
255
+ - `allowWithdrawals` / `allowTransfers` / `blockedPaths` — withdrawals are denied by default the
256
+ moment any `safety` config is set; transfers and arbitrary endpoints can be pinned off too.
257
+
258
+ Omitting `safety` entirely leaves behavior exactly as without a policy.
139
259
 
140
260
  ### Errors
141
261
 
142
- `BinanceError` base, `BinanceAuthError`, `BinanceApiError` (code + status), `RateLimitError`,
143
- `NetworkError`.
262
+ `BinanceError` base, `BinanceAuthError`, `BinanceApiError` (`code`, `status`, `endpoint`,
263
+ `method`, response `headers`, plus `isRateLimitError()`/`isTimestampError()`/
264
+ `isInsufficientBalance()`), `RateLimitError` (`retryAfterMs`), `NetworkError`,
265
+ `PolicyViolationError` (a `TradingPolicy` rule blocked the request), `DryRunError` (dry-run
266
+ suppressed the request).
144
267
 
145
268
  ### Paper trading
146
269
 
@@ -193,6 +316,11 @@ npm test # vitest, HTTP/WS mocked
193
316
  npm run typecheck
194
317
  npm run build # tsup -> dist/ (ESM + CJS + .d.ts)
195
318
  npm run smoke # hits live public Binance endpoints, no keys needed
319
+ npm run smoke:testnet # exercises COIN-M/Margin/Wallet/Sub-account/Spot-WS-API against
320
+ # Binance testnet (see script header for the required env vars);
321
+ # unauthenticated sections still run without keys
196
322
  ```
197
323
 
198
- CI runs typecheck, build and tests on Node 18/20/22; pushing a `v*` tag publishes to npm.
324
+ CI runs typecheck, build and tests on Node LTS and latest. Publishing to npm happens by
325
+ cutting a GitHub Release (`.github/workflows/release.yml` runs on `release: published`), a
326
+ separate, deliberate step — not on every push or tag.