@nemesis-oss/binance-sdk 1.0.0 → 3.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/LICENSE +21 -0
- package/README.md +409 -10
- package/dist/index-C06A22Dz.d.cts +6240 -0
- package/dist/index-C06A22Dz.d.ts +6240 -0
- package/dist/index.cjs +11749 -2826
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1955 -295
- package/dist/index.d.ts +1955 -295
- package/dist/index.js +11554 -2825
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.cjs +8666 -2128
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +8667 -2129
- package/dist/mcp/index.js.map +1 -1
- package/dist/tools/index.cjs +578 -481
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.cts +3 -1
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.js +577 -481
- package/dist/tools/index.js.map +1 -1
- package/package.json +13 -5
- package/dist/index-D2T_Rhwj.d.cts +0 -2055
- package/dist/index-D2T_Rhwj.d.ts +0 -2055
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shubham Taywade
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# binance-sdk
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for Binance — **Spot
|
|
4
|
-
and authenticated trading, with
|
|
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
|
|
|
@@ -23,6 +26,11 @@ const client = new BinanceClient({
|
|
|
23
26
|
testnet: true, // or demo: true; defaults to live
|
|
24
27
|
});
|
|
25
28
|
|
|
29
|
+
// v3: lazy product namespaces over one shared CoreContext — nothing is built
|
|
30
|
+
// until first access, and `client.core` exposes the shared runtime.
|
|
31
|
+
client.core.credentials.canSign; // true
|
|
32
|
+
client.core.http('fapi'); // cached per-host transport
|
|
33
|
+
|
|
26
34
|
// Public market data (no keys needed)
|
|
27
35
|
const klines = await client.spot.market.klines('SOLUSDT', '15m', { limit: 500 });
|
|
28
36
|
const funding = await client.futures.data.fundingRateHistory('ETHUSDT', { limit: 100 });
|
|
@@ -91,6 +99,34 @@ client.closeUserStream();
|
|
|
91
99
|
await client.startSpotUserStream();
|
|
92
100
|
client.spot.wsUser.on('executionReport', (event) => console.log(event.s));
|
|
93
101
|
client.closeSpotUserStream();
|
|
102
|
+
|
|
103
|
+
// COIN-M Futures (inverse contracts, margined in the base asset)
|
|
104
|
+
const coinmBalance = await client.coinm.account.balance();
|
|
105
|
+
await client.coinm.trading.createOrder({
|
|
106
|
+
symbol: 'BTCUSD_PERP',
|
|
107
|
+
side: 'BUY',
|
|
108
|
+
type: 'LIMIT',
|
|
109
|
+
price: 60000,
|
|
110
|
+
quantity: 1, // contracts, not base-asset quantity
|
|
111
|
+
timeInForce: 'GTC',
|
|
112
|
+
});
|
|
113
|
+
client.coinm.ws.subscribe([client.coinm.ws.kline('BTCUSD_PERP', '1m')]);
|
|
114
|
+
await client.startCoinMUserStream();
|
|
115
|
+
|
|
116
|
+
// Margin (cross + isolated)
|
|
117
|
+
const marginAccount = await client.margin.account.crossAccount();
|
|
118
|
+
await client.margin.account.borrow('USDT', 100);
|
|
119
|
+
await client.margin.trading.createOrder({ symbol: 'BTCUSDT', side: 'BUY', type: 'LIMIT', price: 60000, quantity: 0.001 });
|
|
120
|
+
|
|
121
|
+
// Wallet
|
|
122
|
+
await client.wallet.universalTransfer({ type: 'MAIN_UMFUTURE', asset: 'USDT', amount: 500 });
|
|
123
|
+
const deposits = await client.wallet.depositHistory({ coin: 'USDT' });
|
|
124
|
+
|
|
125
|
+
// Sub-accounts (master account only)
|
|
126
|
+
const subAccounts = await client.subaccount.list();
|
|
127
|
+
|
|
128
|
+
// Server time sync — mitigates -1021 (timestamp outside recvWindow) from local clock drift
|
|
129
|
+
await client.syncTime();
|
|
94
130
|
```
|
|
95
131
|
|
|
96
132
|
## API Surface
|
|
@@ -105,6 +141,49 @@ client.closeSpotUserStream();
|
|
|
105
141
|
- `ws` — market WebSocket streams (kline, trade, aggTrade, depth incl. diff-depth, ticker incl.
|
|
106
142
|
rolling-window, bookTicker, miniTicker, avgPrice + all-market/arr variants)
|
|
107
143
|
- `wsUser` — spot user data stream (executionReport, outboundAccountPosition, balanceUpdate, listStatus)
|
|
144
|
+
- `wsApi` — Spot WebSocket API (`wss://ws-api.binance.com/ws-api/v3`): signed trading
|
|
145
|
+
(`order.place/test/cancel/cancelReplace/status`, `openOrders.status/cancelAll`,
|
|
146
|
+
`orderList.place/cancel/status`, `openOrderLists.status`), account (`account.status/commission`,
|
|
147
|
+
`allOrders`, `allOrderLists`, `myTrades`), `userDataStream.start/ping/stop`, and public market
|
|
148
|
+
data (`ping`, `time`, `exchangeInfo`, `depth`, `trades.recent/historical/aggregate`, `klines`,
|
|
149
|
+
`uiKlines`, `avgPrice`, `ticker.24hr/tradingDay/price/book`) — its own method names, distinct
|
|
150
|
+
from the futures WS API below.
|
|
151
|
+
|
|
152
|
+
### COIN-M Futures (`client.coinm`)
|
|
153
|
+
|
|
154
|
+
Inverse contracts (e.g. `BTCUSD_PERP`) margined in the base asset rather than USDT — same shape
|
|
155
|
+
as `client.futures`, against `dapi.binance.com`.
|
|
156
|
+
|
|
157
|
+
- `market` — klines (incl. continuous/index/mark-price variants), funding-rate history, open
|
|
158
|
+
interest + history, premium index, plus the standard public REST inherited from spot/futures
|
|
159
|
+
- `account` — balance, account info, position risk, income history, user trades, leverage
|
|
160
|
+
brackets, commission rate, position mode
|
|
161
|
+
- `trading` — order lifecycle (create/test/get/cancel/cancelAll/all), leverage/margin-type
|
|
162
|
+
changes, position margin
|
|
163
|
+
- `userStream` — listenKey lifecycle (create / keep-alive / close)
|
|
164
|
+
- `ws` — market WebSocket streams, same naming scheme as `client.futures.ws`
|
|
165
|
+
- `wsUser` — user data stream (ACCOUNT_UPDATE, ORDER_TRADE_UPDATE, MARGIN_CALL)
|
|
166
|
+
|
|
167
|
+
### Margin (`client.margin`)
|
|
168
|
+
|
|
169
|
+
Cross and isolated margin trading.
|
|
170
|
+
|
|
171
|
+
- `account` — cross/isolated account info, max borrowable/transferable, `borrow`/`repay` (via
|
|
172
|
+
the unified `borrow-repay` endpoint), cross/isolated transfers, interest history,
|
|
173
|
+
force-liquidation history, price index
|
|
174
|
+
- `trading` — order lifecycle (create/get/cancel/cancelAll/all), myTrades
|
|
175
|
+
|
|
176
|
+
### Wallet (`client.wallet`)
|
|
177
|
+
|
|
178
|
+
- Universal transfer (+ history) between Spot/Margin/USD-M/COIN-M/Funding
|
|
179
|
+
- Deposit history, deposit address, withdraw history, withdraw submission
|
|
180
|
+
- Funding wallet / user asset queries, account snapshot, API key permissions, asset detail
|
|
181
|
+
- Dust log + dust-to-BNB conversion, trade fees
|
|
182
|
+
|
|
183
|
+
### Sub-account (`client.subaccount`, master account only)
|
|
184
|
+
|
|
185
|
+
List/status, spot/futures/margin summaries, universal transfer (+ history), virtual sub-account
|
|
186
|
+
creation, futures/margin enablement, deposit address/history.
|
|
108
187
|
|
|
109
188
|
### Futures (`client.futures`)
|
|
110
189
|
|
|
@@ -134,13 +213,180 @@ client.closeSpotUserStream();
|
|
|
134
213
|
|
|
135
214
|
### Client options
|
|
136
215
|
|
|
137
|
-
`apiKey`, `apiSecret`, `
|
|
138
|
-
`
|
|
216
|
+
`apiKey`, `apiSecret`, `privateKey` + `signatureAlgorithm` (Ed25519/RSA, instead of HMAC),
|
|
217
|
+
`testnet`, `demo`, `recvWindow`, `apiBase`, `wsBase`, `wsUserBase`, `wsApiBase`, `dapiBase`,
|
|
218
|
+
`wsSpotApiBase`, `wsDapiBase`, `timeoutMs`, `maxRetries`, `retryBaseDelayMs`, `retryMaxDelayMs`,
|
|
219
|
+
`retryPolicy` (`strict` default / `legacy`), `idempotentPaths`, `rateLimitWeightPerMinute`,
|
|
220
|
+
`rateLimitSafetyMargin`, `httpsAgent`, `proxy`, `events` (observability bus),
|
|
221
|
+
`safety` (see [Agent safety](#agent-safety)).
|
|
222
|
+
|
|
223
|
+
Product aliases: `client.futures.usdm` and `client.futures.coinm` point at the USDⓈ-M and
|
|
224
|
+
COIN-M surfaces; `client.products` gives the product-oriented view
|
|
225
|
+
(`spot` / `usdm` / `coinm` / `margin` / `wallet` / `subaccount`).
|
|
226
|
+
|
|
227
|
+
### Reliability
|
|
228
|
+
|
|
229
|
+
- **Rate-limit tracking**: `RateLimitTracker` parses `X-MBX-USED-WEIGHT-*` /
|
|
230
|
+
`X-MBX-ORDER-COUNT-*` response headers and delays queued requests once usage crosses a
|
|
231
|
+
configurable safety margin (`rateLimitWeightPerMinute` / `rateLimitSafetyMargin`), to preempt
|
|
232
|
+
`-1003` IP bans rather than react to them. Inspect the live per-host snapshot via
|
|
233
|
+
`client.getRateLimitUsage()`.
|
|
234
|
+
- **Server time sync**: `client.syncTime()` fetches each REST host's server time and applies the
|
|
235
|
+
offset to every signed request's `timestamp`, mitigating `-1021` errors from local clock drift.
|
|
236
|
+
- **Endpoint-aware retries (strict by default)**: exponential backoff with jitter on `429`/`418`
|
|
237
|
+
(rejected before processing — safe for any method) and `5xx`/network errors on idempotent
|
|
238
|
+
methods (GET/DELETE, whitelisted paths such as `order/test`). A `POST` order placement that
|
|
239
|
+
times out is **not** blindly retried — the request may already be live on the exchange.
|
|
240
|
+
Retried signed requests are re-signed with a fresh timestamp. Set `retryPolicy: 'legacy'` to
|
|
241
|
+
restore retry-everything behavior.
|
|
242
|
+
- **WebSocket lifecycle**: every WS client is an explicit state machine
|
|
243
|
+
(`IDLE → CONNECTING → OPEN → RECONNECTING → CLOSING → CLOSED`, via `ws.getState()` and
|
|
244
|
+
`ws.state` events) with race-free reconnection (a retired socket can never trigger a duplicate
|
|
245
|
+
connection) and **proactive 24-hour rotation**: Binance kills stream connections at 24h, so the
|
|
246
|
+
SDK opens a replacement at T-23h and swaps traffic with no data gap.
|
|
247
|
+
- **Subscription acknowledgement**: `await ws.subscribe([...])` resolves only after the server
|
|
248
|
+
confirms the subscription, and every (re)connect verifies the live subscription set with
|
|
249
|
+
`LIST_SUBSCRIPTIONS` and repairs drift automatically.
|
|
250
|
+
- **Exact numbers**: all WS frames are parsed with large-integer preservation (identifiers above
|
|
251
|
+
2^53 surface as decimal strings instead of silently-corrupted floats — also available as
|
|
252
|
+
`parseJsonLossless` for your own payloads), and money math in the execution/risk/state layers
|
|
253
|
+
runs on a BigInt-backed `Decimal` (`0.1 + 0.2 === 0.3`, exactly).
|
|
254
|
+
|
|
255
|
+
### Execution (idempotent placement + reconciliation)
|
|
256
|
+
|
|
257
|
+
`client.futures.execution` and `client.spot.execution` are the safe way to place orders — one
|
|
258
|
+
execution semantics across USDⓈ-M, spot and the paper simulator (see
|
|
259
|
+
[Multi-backend execution](#multi-backend-execution-live--paper) below):
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
const execution = await client.futures.execution.placeOrder({
|
|
263
|
+
symbol: 'BTCUSDT',
|
|
264
|
+
side: 'BUY',
|
|
265
|
+
type: 'MARKET',
|
|
266
|
+
quantity: 0.001,
|
|
267
|
+
intentId: 'my-strategy-signal-42', // idempotency key: replays return the original execution
|
|
268
|
+
});
|
|
269
|
+
// {
|
|
270
|
+
// intentId, clientOrderId, exchangeOrderId, status, executedQuantity: '0.001',
|
|
271
|
+
// averagePrice: '…', fills: [...], reconciliationState: 'acked' | 'reconciled' | …
|
|
272
|
+
// }
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
- Every order carries a deterministic `newClientOrderId` derived from the intent — the exchange
|
|
276
|
+
itself becomes the idempotency guard; duplicate intents return the recorded execution.
|
|
277
|
+
- On a transport failure the outcome is **reconciled** by polling
|
|
278
|
+
`GET /fapi/v1/order?origClientOrderId=…`: found → the execution is recovered and returned;
|
|
279
|
+
`-2013` (order does not exist) → one safe resubmission with the same clientOrderId; still
|
|
280
|
+
ambiguous → `ExecutionUnknownError` carrying the intent for manual follow-up — never a guess.
|
|
281
|
+
- With a user-data stream attached (`execution.setUserStream(wsUser)`), execution reports
|
|
282
|
+
(`ORDER_TRADE_UPDATE` on futures, `executionReport` on spot) stream live fills into the ledger.
|
|
283
|
+
- `cancelOrder` reconciles the same way, and `execution.reconcile(intentId)` forces a refresh.
|
|
284
|
+
|
|
285
|
+
### Multi-backend execution (live + paper)
|
|
286
|
+
|
|
287
|
+
Product specifics live behind `ExecutionAdapter` implementations
|
|
288
|
+
(`FuturesExecutionAdapter`, `SpotExecutionAdapter`, `PaperExecutionAdapter`), so paper trading
|
|
289
|
+
is a first-class execution backend — the same envelope, idempotency and reconciliation
|
|
290
|
+
semantics, zero exchange traffic:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// Paper manager: identical API to client.futures.execution
|
|
294
|
+
const paper = client.createPaperExecutionManager({ initialBalance: 50_000 });
|
|
295
|
+
const fill = await paper.placeOrder({
|
|
296
|
+
symbol: 'BTCUSDT', side: 'BUY', type: 'MARKET', quantity: 0.01, intentId: 'strategy-1',
|
|
297
|
+
});
|
|
298
|
+
// fill.status === 'FILLED', fill.fills[0].price — exact decimal strings
|
|
299
|
+
|
|
300
|
+
// Gateway: route live/paper through one interface, independent ledgers
|
|
301
|
+
const gateway = client.createExecutionGateway({ defaultBackend: 'paper' });
|
|
302
|
+
await gateway.placeOrder({ ... }); // paper (default)
|
|
303
|
+
await gateway.placeOrder({ ...order }, { backend: 'live' }); // one live order
|
|
304
|
+
gateway.paperEngine.getAccountInfo(); // simulation state
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Standalone single-product clients for focused integrations. v2 factories
|
|
308
|
+
still ship for back-compat; the v3 first-class `ProductClient` classes
|
|
309
|
+
(`SpotClient`, `USDMClient`, `CoinMClient`) own their own `CoreContext`,
|
|
310
|
+
the v3 execution platform (Spot / USDⓈ-M) and the v3 state engine
|
|
311
|
+
(Spot / USDⓈ-M):
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import { createSpotClient, createUSDMClient } from '@nemesis-oss/binance-sdk';
|
|
315
|
+
const spot = createSpotClient({ apiKey, apiSecret }); // v2 factory
|
|
316
|
+
await spot.syncTime();
|
|
317
|
+
await spot.market.depth('BTCUSDT', 20);
|
|
318
|
+
spot.close();
|
|
319
|
+
|
|
320
|
+
// v3 first-class product client — owns CoreContext, owns the platform
|
|
321
|
+
import { CoreContext, SpotClient, USDMClient, CoinMClient } from '@nemesis-oss/binance-sdk';
|
|
322
|
+
const core = new CoreContext({ apiKey, apiSecret });
|
|
323
|
+
const usdm = new USDMClient(core);
|
|
324
|
+
await usdm.executionPlatform.startUserSession(); // managed listen-key + 30-min keep-alive
|
|
325
|
+
const book = await usdm.books.watch('BTCUSDT'); // local L2 book, synced
|
|
326
|
+
usdm.close();
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Local order books
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
const books = client.createFuturesOrderBookEngine();
|
|
333
|
+
const btc = await books.subscribe('BTCUSDT');
|
|
334
|
+
btc.metrics(); // bestBid / bestAsk / midPrice / spread / spreadBps / microprice /
|
|
335
|
+
// imbalance / bidDepth / askDepth / lastUpdateId / synced
|
|
336
|
+
btc.vwap('bids', 5); // size-weighted VWAP of the top 5 levels (exact decimal string)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
The engine seeds each book from a REST snapshot, applies `@depth@100ms` diffs in sequence,
|
|
340
|
+
detects gaps (`pu` / sequence discontinuity) and self-heals with a fresh snapshot.
|
|
341
|
+
|
|
342
|
+
### Agent safety
|
|
343
|
+
|
|
344
|
+
`BinanceClientOptions.safety` configures a `RiskGateway` (a superset of the v2.0
|
|
345
|
+
`TradingPolicy`), evaluated on every mutating request before it leaves the process — for
|
|
346
|
+
autonomous/LLM-driven callers where a misread prompt shouldn't be able to spend the account.
|
|
347
|
+
Shared across every product namespace, and fed live state by `client.futures.execution`.
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
const client = new BinanceClient({
|
|
351
|
+
apiKey, apiSecret,
|
|
352
|
+
safety: {
|
|
353
|
+
dryRun: true, // throws DryRunError instead of sending the request
|
|
354
|
+
allowedSymbols: ['BTCUSDT', 'ETHUSDT'],
|
|
355
|
+
maxNotionalPerOrder: 100, // an order whose notional can't be verified is refused
|
|
356
|
+
maxLeverage: 20, // leverage changes above this are refused
|
|
357
|
+
maxOpenNotional: 5_000, // aggregate tracked open-order notional budget
|
|
358
|
+
maxDailyLoss: 1_000, // realized-loss kill switch (UTC day window)
|
|
359
|
+
maxConsecutiveFailures: 5, // exchange-rejection streak circuit breaker
|
|
360
|
+
allowWithdrawals: false, // default once `safety` is set at all
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
client.getRiskStatus(); // { circuitBreaker, openNotional: '500', dailyPnl: '-12.5', ... }
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
- `dryRun` — intercepts `POST`/`PUT`/`DELETE` and throws `DryRunError` (carrying the request that
|
|
367
|
+
would have been sent, via `.describe()`) instead of sending it. It never returns a synthetic
|
|
368
|
+
success payload — a fabricated `orderId` would lead a caller to believe an order exists.
|
|
369
|
+
- `readOnly` — refuses mutating requests outright.
|
|
370
|
+
- `allowedSymbols` — rejects orders naming a symbol outside the list.
|
|
371
|
+
- `maxNotionalPerOrder` — caps a single order's notional (from `price*quantity` or
|
|
372
|
+
`quoteOrderQty`); an order whose notional can't be determined (e.g. a MARKET order with no
|
|
373
|
+
price) is refused rather than waved through.
|
|
374
|
+
- `maxLeverage` / `maxOpenNotional` / `maxDailyLoss` / `maxConsecutiveFailures` — layered
|
|
375
|
+
account-state limits. The circuit breaker trips on the daily loss limit or a rejection streak,
|
|
376
|
+
refuses every mutating request while tripped, and rolls over at the UTC day boundary (or via
|
|
377
|
+
`resetBreaker()` after human review).
|
|
378
|
+
- `allowWithdrawals` / `allowTransfers` / `blockedPaths` — withdrawals are denied by default the
|
|
379
|
+
moment any `safety` config is set; transfers and arbitrary endpoints can be pinned off too.
|
|
380
|
+
|
|
381
|
+
Omitting `safety` entirely leaves behavior exactly as without a policy.
|
|
139
382
|
|
|
140
383
|
### Errors
|
|
141
384
|
|
|
142
|
-
`BinanceError` base, `BinanceAuthError`, `BinanceApiError` (code
|
|
143
|
-
`
|
|
385
|
+
`BinanceError` base, `BinanceAuthError`, `BinanceApiError` (`code`, `status`, `endpoint`,
|
|
386
|
+
`method`, response `headers`, plus `isRateLimitError()`/`isTimestampError()`/
|
|
387
|
+
`isInsufficientBalance()`), `RateLimitError` (`retryAfterMs`), `NetworkError`,
|
|
388
|
+
`PolicyViolationError` (a `TradingPolicy` rule blocked the request), `DryRunError` (dry-run
|
|
389
|
+
suppressed the request).
|
|
144
390
|
|
|
145
391
|
### Paper trading
|
|
146
392
|
|
|
@@ -148,13 +394,141 @@ Simulates fills against live public prices — nothing is sent to the exchange.
|
|
|
148
394
|
at the requested leverage and released pro-rata as a position is reduced.
|
|
149
395
|
|
|
150
396
|
```typescript
|
|
151
|
-
import { PaperTradingEngine } from '@nemesis-oss/binance-sdk';
|
|
397
|
+
import { PaperTradingEngine, SlippageModel, BinanceUsdmFeeModel } from '@nemesis-oss/binance-sdk';
|
|
152
398
|
|
|
399
|
+
// Legacy behaviour (instant fills, zero fees) is the default:
|
|
153
400
|
const engine = new PaperTradingEngine({ initialBalance: 10_000 });
|
|
154
401
|
await engine.placeOrder({ symbol: 'BTCUSDT', side: 'BUY', type: 'MARKET', quantity: 0.05, leverage: 5 });
|
|
155
402
|
await engine.updatePositions(); // re-mark against live prices
|
|
156
403
|
const close = await engine.placeOrder({ symbol: 'BTCUSDT', side: 'SELL', type: 'MARKET', quantity: 0.05 });
|
|
157
404
|
console.log(close.realizedPnl, engine.getAccountInfo().balance);
|
|
405
|
+
|
|
406
|
+
// Or approximate reality in layers:
|
|
407
|
+
const realistic = new PaperTradingEngine({
|
|
408
|
+
initialBalance: 10_000,
|
|
409
|
+
executionModel: new SlippageModel(10), // 10 bps market impact
|
|
410
|
+
feeModel: new BinanceUsdmFeeModel(), // 5 bps taker / 2 bps maker
|
|
411
|
+
});
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Execution models compose: `SlippageModel`, `PartialFillModel`, `OrderBookModel` (VWAP walks
|
|
415
|
+
against a real/injected book), `LatencyModel`, `CompositeModel`. Fee models implement
|
|
416
|
+
`FeeModel` (`TakerMakerFeeModel` / `BinanceUsdmFeeModel`).
|
|
417
|
+
|
|
418
|
+
### Observability
|
|
419
|
+
|
|
420
|
+
`client.events` is a structured, JSON-serializable event bus wired through every subsystem:
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
client.events.on('execution.', (event) => console.log(event.scope, event.name, event.payload));
|
|
424
|
+
client.events.on('risk.denied', (event) => audit(event.payload));
|
|
425
|
+
client.events.on('ws.', (event) => console.log(event.name, event.payload));
|
|
426
|
+
// http.request.start / http.request.end / http.request.retry / http.request.error
|
|
427
|
+
// — each carrying contract metadata: product, operation, security, declaredWeight
|
|
428
|
+
// ws.connecting / ws.open / ws.state / ws.reconnecting / ws.rotated / ws.resynced / ws.stale
|
|
429
|
+
// execution.submitted / execution.acked / execution.reconciled / execution.retry / risk.*
|
|
430
|
+
// orderBook.synced / orderBook.desync
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Events carry `ts`/`seq`/`scope`/`name`/`payload`; subscribe with exact names, trailing-dot
|
|
434
|
+
prefixes (`'ws.'`) or `'*'`. Pass your own bus via `new BinanceClient({ events })`, or forward
|
|
435
|
+
everything to a logger with `forwardEventsToLogger(bus, logger)`.
|
|
436
|
+
|
|
437
|
+
### Endpoint maps & agent-native docs
|
|
438
|
+
|
|
439
|
+
- `llms.txt` / `llms-full.txt` — machine-oriented SDK index and flattened endpoint list
|
|
440
|
+
(Binance Agent-Native convention).
|
|
441
|
+
- `docs/endpoint-map/*.md` — per-product tables of every implemented endpoint
|
|
442
|
+
(operation → method → path → auth → SDK surface).
|
|
443
|
+
- **`contracts/` (v3)** — machine-readable inventory of the SDK surface:
|
|
444
|
+
`endpoint-catalog.json` (every REST operation: product, method, path, security, weight,
|
|
445
|
+
implementer), `security-catalog.json` (auth matrix per product),
|
|
446
|
+
`websocket-catalog.json` (WS families, stream ceilings, renewal/liveness policy),
|
|
447
|
+
`catalog.json` (index).
|
|
448
|
+
Generated with `npm run contracts:generate` and CI-validated against the registry —
|
|
449
|
+
the input layer for generated bindings, tool metadata and coverage accounting.
|
|
450
|
+
- `ENDPOINT_REGISTRY` / `listEndpoints({ product, method, authentication })` in code.
|
|
451
|
+
- **Contract layer**: `getContract(product, operation)` / `findContract(path, method)` /
|
|
452
|
+
`contractFor(baseURL, method, path)` — registry entries with normalized security schemes
|
|
453
|
+
(`none`/`apiKey`/`signature`) and declared request weights; `describeContract()` renders a
|
|
454
|
+
one-line description for logs and agents.
|
|
455
|
+
- Regenerate everything from the registry with `npm run docs:generate` (the generator
|
|
456
|
+
cross-checks the registry against the actual `http.<verb>()` calls in `src/resources`)
|
|
457
|
+
and `npm run contracts:generate`.
|
|
458
|
+
- `docs/architecture/v3-foundation.md` — the v3 platform architecture and migration plan.
|
|
459
|
+
- `docs/architecture/v3-websocket.md` — the v3 WebSocket platform design (milestone 2).
|
|
460
|
+
- `docs/architecture/v3-execution.md` — the v3 execution platform design (milestone 3).
|
|
461
|
+
- `docs/architecture/v3-state.md` — the v3 state engine + paper backend design (milestone 4).
|
|
462
|
+
|
|
463
|
+
## v3 Platform (stable since 3.0.0)
|
|
464
|
+
|
|
465
|
+
`3.0.0` ships the platform rewrite: the foundation (see
|
|
466
|
+
`docs/architecture/v3-foundation.md`), the WebSocket platform (see
|
|
467
|
+
`docs/architecture/v3-websocket.md`), the execution platform (see
|
|
468
|
+
`docs/architecture/v3-execution.md`), the state engine + paper execution
|
|
469
|
+
backend (see `docs/architecture/v3-state.md`), the first-class
|
|
470
|
+
Spot / USDⓈ-M / COIN-M product clients, and the execution audit sink;
|
|
471
|
+
every v2.x surface keeps
|
|
472
|
+
working unchanged.
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
import { BinanceClient, CoreContext, USDMClient, Credentials } from '@nemesis-oss/binance-sdk';
|
|
476
|
+
|
|
477
|
+
// Standalone product client over a caller-owned shared runtime
|
|
478
|
+
const core = new CoreContext({ apiKey, apiSecret });
|
|
479
|
+
const usdm = new USDMClient(core);
|
|
480
|
+
await core.syncTime(); // one clock sync, every host
|
|
481
|
+
const fill = await usdm.execution.placeOrder({
|
|
482
|
+
symbol: 'BTCUSDT', side: 'BUY', type: 'MARKET', quantity: '0.01',
|
|
483
|
+
});
|
|
484
|
+
usdm.close(); // product-scoped cleanup
|
|
485
|
+
|
|
486
|
+
// Two products, one runtime: shared transports, shared event bus
|
|
487
|
+
const other = new USDMClient(core); // same weight budget, same events
|
|
488
|
+
|
|
489
|
+
// The multi-product facade is lazy now — namespaces build on first access
|
|
490
|
+
// (stable identity) and share client.core:
|
|
491
|
+
const client = new BinanceClient({ apiKey, apiSecret });
|
|
492
|
+
client.core.credentials.describe(); // 'hmac key ****xxxx'
|
|
493
|
+
client.futures.execution === client.futures.execution; // true — cached
|
|
494
|
+
|
|
495
|
+
// --- WebSocket platform (milestone 2): client.ws ---
|
|
496
|
+
const sub = await client.ws.usdm.subscribe('btcusdt@aggTrade');
|
|
497
|
+
sub.on('message', (tick) => console.log(tick.p)); // parsed payload
|
|
498
|
+
await sub.waitForReady();
|
|
499
|
+
client.ws.stats(); // pools, renewal deadlines, WS API state
|
|
500
|
+
await client.ws.api.usdm.accountStatus(); // persistent multiplexed WS API
|
|
501
|
+
sub.close(); // refcounted UNSUBSCRIBE
|
|
502
|
+
|
|
503
|
+
// --- Execution platform (milestone 3): usdm.executionPlatform ---
|
|
504
|
+
const session = await usdm.executionPlatform.startUserSession();
|
|
505
|
+
// listen key created + WS connected + 30-min keep-alive + auto key rotation;
|
|
506
|
+
// the product's execution manager now tracks live fills from the stream:
|
|
507
|
+
|
|
508
|
+
const execution = await usdm.execution.placeOrder({
|
|
509
|
+
symbol: 'BTCUSDT', side: 'BUY', type: 'MARKET', quantity: '0.001',
|
|
510
|
+
});
|
|
511
|
+
const record = usdm.executionPlatform.orders.get(execution.clientOrderId);
|
|
512
|
+
// → live OrderRecord: status, exact decimal quantities, per-trade fills
|
|
513
|
+
await usdm.executionPlatform.orders.waitForTerminal(execution.clientOrderId);
|
|
514
|
+
usdm.executionPlatform.positions.get('BTCUSDT'); // from ACCOUNT_UPDATE
|
|
515
|
+
usdm.executionPlatform.classify(err).safety;
|
|
516
|
+
// → 'safe' | 'idempotent' | 'reconciliation-required' | 'never-retry'
|
|
517
|
+
|
|
518
|
+
// --- State engine + paper backend (milestone 4) ---
|
|
519
|
+
const book = await usdm.books.watch('BTCUSDT'); // local L2 book, synced
|
|
520
|
+
book.bestBid; // exact decimal strings
|
|
521
|
+
book.metrics(); // spread, microprice, imbalance
|
|
522
|
+
await usdm.executionPlatform.reconcile(); // REST fold: startup gap-fill
|
|
523
|
+
|
|
524
|
+
import { createPaperExecutionPlatform } from '@nemesis-oss/binance-sdk';
|
|
525
|
+
const paper = createPaperExecutionPlatform(client.core, { initialBalance: 25_000 });
|
|
526
|
+
await paper.platform.startUserSession(); // local session, zero network
|
|
527
|
+
const fill = await paper.execution.placeOrder({
|
|
528
|
+
symbol: 'BTCUSDT', side: 'BUY', type: 'MARKET', quantity: '0.01',
|
|
529
|
+
});
|
|
530
|
+
paper.platform.orders.get(fill.clientOrderId); // same OrderRecord as live
|
|
531
|
+
paper.platform.positions.get('BTCUSDT'); // same PositionRecord as live
|
|
158
532
|
```
|
|
159
533
|
|
|
160
534
|
## LLM Tools & MCP
|
|
@@ -169,11 +543,31 @@ const { openai, anthropic, mcp } = toolkitToFormats(tk); // tool schemas per for
|
|
|
169
543
|
```
|
|
170
544
|
|
|
171
545
|
- **Tool groups**: `market`, `account`, `trading` (USD-M futures), `spot` (Spot), `ws`
|
|
172
|
-
(streams + WS API), `derived` (composites like size/close/bracket), `paper
|
|
546
|
+
(streams + WS API), `derived` (composites like size/close/bracket), `paper`, and
|
|
547
|
+
`execution` (v2.3).
|
|
548
|
+
- **Execution tools (v2.3)** — order tools routed through the `ExecutionGateway`, so agents
|
|
549
|
+
get idempotency, reconciliation and backend routing for free:
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
// Run the whole toolkit against the simulator — no API-key trading risk
|
|
553
|
+
const tk = createFuturesToolkit(client, { executionBackend: 'paper', paper: { initialBalance: 50_000 } });
|
|
554
|
+
|
|
555
|
+
// Same schema, one extra param per call: backend: 'live' | 'paper' (optional)
|
|
556
|
+
const fill = await call('execution_place_order', {
|
|
557
|
+
symbol: 'BTCUSDT', side: 'BUY', type: 'MARKET', quantity: 0.01,
|
|
558
|
+
intentId: 'strategy-1', // idempotency: retries return the original execution
|
|
559
|
+
});
|
|
560
|
+
// execution_get_order finds intents across both ledgers; execution_status returns
|
|
561
|
+
// default backend + risk-gateway state + paper account; execution_cancel_order
|
|
562
|
+
// resolves already-gone orders to a terminal CANCELED execution (never a thrown -2011).
|
|
563
|
+
```
|
|
564
|
+
|
|
173
565
|
- **MCP server**: `npx binance-sdk-mcp` (stdio) auto-registers every tool plus reference
|
|
174
566
|
resources (`binance://futures/symbols`, `binance://futures/premium-index`, `binance://spot/symbols`).
|
|
175
567
|
For local development against source instead of the published package, point your MCP host at
|
|
176
568
|
`mcp-config/local-dev.json` (runs `npx tsx src/mcp/index.ts` directly).
|
|
569
|
+
`createBinanceMcpServer(client, { executionBackend: 'paper' })` builds a paper-mode server —
|
|
570
|
+
every order tool routes through the simulator, safe to expose to untrusted hosts.
|
|
177
571
|
- **Agent skills**: Markdown skills under `skills/` — futures trading / market-data / algo /
|
|
178
572
|
portfolio-margin, plus spot trading / market-data — for Skills-Hub-style agents.
|
|
179
573
|
|
|
@@ -193,6 +587,11 @@ npm test # vitest, HTTP/WS mocked
|
|
|
193
587
|
npm run typecheck
|
|
194
588
|
npm run build # tsup -> dist/ (ESM + CJS + .d.ts)
|
|
195
589
|
npm run smoke # hits live public Binance endpoints, no keys needed
|
|
590
|
+
npm run smoke:testnet # exercises COIN-M/Margin/Wallet/Sub-account/Spot-WS-API against
|
|
591
|
+
# Binance testnet (see script header for the required env vars);
|
|
592
|
+
# unauthenticated sections still run without keys
|
|
196
593
|
```
|
|
197
594
|
|
|
198
|
-
CI runs typecheck, build and tests on Node
|
|
595
|
+
CI runs typecheck, build and tests on Node LTS and latest. Publishing to npm happens by
|
|
596
|
+
cutting a GitHub Release (`.github/workflows/release.yml` runs on `release: published`), a
|
|
597
|
+
separate, deliberate step — not on every push or tag.
|