Skip to content

Commit a0a08d1

Browse files
committed
Merge branch 'master' of github.com:ccxt/binance-api-node
2 parents 95b2bab + 44ec46a commit a0a08d1

11 files changed

Lines changed: 1515 additions & 18 deletions

File tree

README.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Import the module and create a new client. Passing api keys is optional only if
2828
you don't plan on doing authenticated calls. You can create an api key
2929
[here](https://www.binance.com/userCenter/createApi.html). If you want to create demo/testnet keys click [here](https://demo.binance.com/)
3030

31+
3132
```js
3233
import Binance from 'binance-api-node'
3334

@@ -91,6 +92,7 @@ client.ws.ticker('BTCUSDT', ticker => console.log(ticker))
9192
```
9293

9394
**Notes:**
95+
- `binance-api-node` fully supports the new algo service introduced on the Decemeber 9th of 2025
9496
- Proxy support is only available in Node.js environment
9597
- Browsers use system/OS proxy settings automatically
9698
- Supports HTTP and HTTPS proxies (use `http://` or `https://` protocol)
@@ -153,6 +155,7 @@ Following examples will use the `await` form, which requires some configuration
153155
- [delivery markPrice](#delivery-markprice)
154156
- [Authenticated REST Endpoints](#authenticated-rest-endpoints)
155157
- [order](#order)
158+
- [updateOrder](#updateorder)
156159
- [orderTest](#ordertest)
157160
- [orderOco](#orderoco)
158161
- [getOrder](#getorder)
@@ -205,6 +208,8 @@ Following examples will use the `await` form, which requires some configuration
205208
- [Portfolio Margin Endpoints](#portfolio-margin-endpoints)
206209
- [getPortfolioMarginAccountInfo](#getportfoliomarginaccountinfo)
207210
- [Futures Authenticated REST endpoints](#futures-authenticated-rest-endpoints)
211+
- [futuresOrder](#futuresorder)
212+
- [futuresUpdateOrder](#futuresupdateorder)
208213
- [futuresGetOrder](#futuresgetorder)
209214
- [futuresAllOrders](#futuresallorders)
210215
- [futuresBatchOrders](#futuresbatchorders)
@@ -1375,7 +1380,8 @@ the request.
13751380

13761381
#### order
13771382

1378-
Creates a new order.
1383+
- Creates a new order.
1384+
- see https://developers.binance.com/docs/binance-spot-api-docs/rest-api/trading-endpoints#new-order-trade
13791385

13801386
```js
13811387
console.log(
@@ -1451,6 +1457,26 @@ Test new order creation and signature/recvWindow. Creates and validates a new or
14511457

14521458
Same API as above, but does not return any output on success.
14531459

1460+
1461+
#### updateOrder
1462+
1463+
- updates an order
1464+
- see https://developers.binance.com/docs/binance-spot-api-docs/rest-api/trading-endpoints#cancel-an-existing-order-and-send-a-new-order-trade
1465+
1466+
```Js
1467+
1468+
const order = await client.updateOrder({
1469+
symbol: 'LTCUSDT',
1470+
cancelOrderId: 12345678,
1471+
side: 'BUY',
1472+
type: 'LIMIT',
1473+
quantity: 1,
1474+
price: 80,
1475+
timeInForce: 'GTC',
1476+
})
1477+
1478+
```
1479+
14541480
#### orderOco
14551481

14561482
Creates a new OCO order.
@@ -3615,6 +3641,42 @@ console.log(await client.getPortfolioMarginAccountInfo())
36153641

36163642
### Futures Authenticated REST endpoints
36173643

3644+
#### futuresOrder
3645+
3646+
- Creates a futures order
3647+
- see https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
3648+
3649+
```js
3650+
console.log(
3651+
await client.futuresOrder({
3652+
symbol: 'LTCUSDT',
3653+
side: 'BUY',
3654+
type: 'LIMIT',
3655+
quantity: 1,
3656+
price: 80,
3657+
timeInForce: 'GTC',
3658+
})
3659+
)
3660+
```
3661+
3662+
#### futuresUpdateOrder
3663+
- Updates a futures order
3664+
- see https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Order
3665+
3666+
```js
3667+
console.log(
3668+
await client.futuresUpdateOrder({
3669+
orderId: 23423423423,
3670+
symbol: 'LTCUSDT',
3671+
side: 'BUY',
3672+
type: 'LIMIT',
3673+
quantity: 1,
3674+
price: 80,
3675+
timeInForce: 'GTC',
3676+
})
3677+
)
3678+
```
3679+
36183680
#### futuresGetOrder
36193681

36203682
Check an order's status.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "binance-api-node",
3-
"version": "0.13.4",
3+
"version": "0.13.5",
44
"description": "A node API wrapper for Binance",
55
"main": "dist",
66
"browser": {
@@ -22,7 +22,7 @@
2222
"build": "rm -rf dist && babel src -d dist",
2323
"prepare": "npm run build",
2424
"test": "npm run test:ava && npm run test:browser",
25-
"test:ava": "ava --timeout=10s -v",
25+
"test:ava": "ava --timeout=90s -v",
2626
"test:browser": "node test/browser/browser-test-runner.mjs && ava test/browser/crypto-browser-playwright.js test/browser/websocket-browser.test.js --timeout=15s -v",
2727
"test:browser:signature": "node test/browser/browser-test-runner.mjs",
2828
"test:browser:websocket": "ava test/browser/websocket-browser.test.js --timeout=15s -v",

src/http-client.js

Lines changed: 148 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,27 @@ const orderOco = (privCall, payload = {}, url) => {
404404
)
405405
}
406406

407+
const updateOrder = (privCall, payload = {}, url) => {
408+
const newPayload = { ...payload }
409+
410+
if (!newPayload.cancelReplaceMode) {
411+
newPayload.cancelReplaceMode = 'STOP_ON_FAILURE'
412+
}
413+
414+
if (!newPayload.timeInForce) {
415+
newPayload.timeInForce = 'GTC'
416+
}
417+
418+
if (!newPayload.newClientOrderId) {
419+
newPayload.newClientOrderId = spotP()
420+
}
421+
422+
return (
423+
checkParams('updateOrder', newPayload, ['symbol', 'side', 'type']) &&
424+
privCall(url, newPayload, 'POST')
425+
)
426+
}
427+
407428
/**
408429
* Zip asks and bids reponse from order book
409430
*/
@@ -486,6 +507,7 @@ export default opts => {
486507

487508
// Order endpoints
488509
order: payload => order(privCall, payload, '/api/v3/order'),
510+
updateOrder: payload => updateOrder(privCall, payload, '/api/v3/order/cancelReplace'),
489511
orderOco: payload => orderOco(privCall, payload, '/api/v3/order/oco'),
490512
orderTest: payload => order(privCall, payload, '/api/v3/order/test'),
491513
getOrder: payload => privCall('/api/v3/order', payload),
@@ -570,15 +592,114 @@ export default opts => {
570592
futuresFundingRate: payload =>
571593
checkParams('fundingRate', payload, ['symbol']) &&
572594
pubCall('/fapi/v1/fundingRate', payload),
573-
futuresOrder: payload => order(privCall, payload, '/fapi/v1/order'),
595+
futuresOrder: payload => {
596+
// Check if this is a conditional order type that should be routed to algo endpoint
597+
const orderType = payload?.type?.toUpperCase()
598+
const conditionalTypes = [
599+
'STOP',
600+
'STOP_MARKET',
601+
'TAKE_PROFIT',
602+
'TAKE_PROFIT_MARKET',
603+
'TRAILING_STOP_MARKET',
604+
]
605+
606+
if (orderType && conditionalTypes.includes(orderType)) {
607+
// Route to algo order endpoint
608+
const algoPayload = { ...payload }
609+
if (!algoPayload.clientAlgoId) {
610+
algoPayload.clientAlgoId = futuresP()
611+
}
612+
delete algoPayload.newClientOrderId
613+
algoPayload.algoType = 'CONDITIONAL'
614+
if (algoPayload.stopPrice && !algoPayload.triggerPrice) {
615+
algoPayload.triggerPrice = algoPayload.stopPrice
616+
delete algoPayload.stopPrice
617+
}
618+
return privCall('/fapi/v1/algoOrder', algoPayload, 'POST')
619+
}
620+
// Use regular order endpoint
621+
return order(privCall, payload, '/fapi/v1/order')
622+
},
623+
futuresUpdateOrder: payload => {
624+
if (payload && 'conditional' in payload) {
625+
// for now it is not supported
626+
// const payloadCopy = { ...payload }
627+
// delete payloadCopy.conditional
628+
// return privCall('/fapi/v1/algoOrder', payloadCopy, 'PUT')
629+
}
630+
return privCall('/fapi/v1/order', payload, 'PUT')
631+
},
574632
futuresBatchOrders: payload => privCall('/fapi/v1/batchOrders', payload, 'POST'),
575-
futuresGetOrder: payload => privCall('/fapi/v1/order', payload),
576-
futuresCancelOrder: payload => privCall('/fapi/v1/order', payload, 'DELETE'),
577-
futuresCancelAllOpenOrders: payload =>
578-
privCall('/fapi/v1/allOpenOrders', payload, 'DELETE'),
633+
futuresGetOrder: payload => {
634+
// Check if this is a request for a conditional/algo order
635+
const isConditional = payload?.conditional
636+
const hasAlgoId = payload?.algoId || payload?.clientAlgoId
637+
let payloadCopy = payload
638+
if (payload && 'conditional' in payload) {
639+
payloadCopy = { ...payload }
640+
delete payloadCopy.conditional
641+
}
642+
643+
if (isConditional || hasAlgoId) {
644+
return privCall('/fapi/v1/algoOrder', payloadCopy)
645+
}
646+
return privCall('/fapi/v1/order', payloadCopy)
647+
},
648+
futuresCancelOrder: payload => {
649+
// Check if this is a request for a conditional/algo order
650+
const isConditional = payload?.conditional
651+
const hasAlgoId = payload?.algoId || payload?.clientAlgoId
652+
let payloadCopy = payload
653+
if (payload && 'conditional' in payload) {
654+
payloadCopy = { ...payload }
655+
delete payloadCopy.conditional
656+
}
657+
658+
if (isConditional || hasAlgoId) {
659+
return privCall('/fapi/v1/algoOrder', payloadCopy, 'DELETE')
660+
}
661+
return privCall('/fapi/v1/order', payloadCopy, 'DELETE')
662+
},
663+
futuresCancelAllOpenOrders: payload => {
664+
const isConditional = payload?.conditional
665+
let payloadCopy = payload
666+
if (payload && 'conditional' in payload) {
667+
payloadCopy = { ...payload }
668+
delete payloadCopy.conditional
669+
}
670+
671+
if (isConditional) {
672+
return privCall('/fapi/v1/algoOpenOrders', payloadCopy, 'DELETE')
673+
}
674+
return privCall('/fapi/v1/allOpenOrders', payloadCopy, 'DELETE')
675+
},
579676
futuresCancelBatchOrders: payload => privCall('/fapi/v1/batchOrders', payload, 'DELETE'),
580-
futuresOpenOrders: payload => privCall('/fapi/v1/openOrders', payload),
581-
futuresAllOrders: payload => privCall('/fapi/v1/allOrders', payload),
677+
futuresOpenOrders: payload => {
678+
const isConditional = payload?.conditional
679+
let payloadCopy = payload
680+
if (payload && 'conditional' in payload) {
681+
payloadCopy = { ...payload }
682+
delete payloadCopy.conditional
683+
}
684+
685+
if (isConditional) {
686+
return privCall('/fapi/v1/openAlgoOrders', payloadCopy)
687+
}
688+
return privCall('/fapi/v1/openOrders', payloadCopy)
689+
},
690+
futuresAllOrders: payload => {
691+
const isConditional = payload?.conditional
692+
let payloadCopy = payload
693+
if (payload && 'conditional' in payload) {
694+
payloadCopy = { ...payload }
695+
delete payloadCopy.conditional
696+
}
697+
698+
if (isConditional) {
699+
return privCall('/fapi/v1/allAlgoOrders', payloadCopy)
700+
}
701+
return privCall('/fapi/v1/allOrders', payloadCopy)
702+
},
582703
futuresPositionRisk: payload => privCall('/fapi/v2/positionRisk', payload),
583704
futuresLeverageBracket: payload => privCall('/fapi/v1/leverageBracket', payload),
584705
futuresAccountBalance: payload => privCall('/fapi/v2/balance', payload),
@@ -594,6 +715,26 @@ export default opts => {
594715
futuresIncome: payload => privCall('/fapi/v1/income', payload),
595716
getMultiAssetsMargin: payload => privCall('/fapi/v1/multiAssetsMargin', payload),
596717
setMultiAssetsMargin: payload => privCall('/fapi/v1/multiAssetsMargin', payload, 'POST'),
718+
futuresRpiDepth: payload => book(pubCall, payload, '/fapi/v1/rpiDepth'),
719+
futuresSymbolAdlRisk: payload => pubCall('/fapi/v1/symbolAdlRisk', payload),
720+
futuresCommissionRate: payload => privCall('/fapi/v1/commissionRate', payload),
721+
722+
// Algo Orders (Conditional Orders)
723+
futuresCreateAlgoOrder: payload => {
724+
if (!payload.clientAlgoId) {
725+
payload.clientAlgoId = futuresP()
726+
}
727+
if (!payload.algoType) {
728+
payload.algoType = 'CONDITIONAL'
729+
}
730+
return privCall('/fapi/v1/algoOrder', payload, 'POST')
731+
},
732+
futuresCancelAlgoOrder: payload => privCall('/fapi/v1/algoOrder', payload, 'DELETE'),
733+
futuresCancelAllAlgoOpenOrders: payload =>
734+
privCall('/fapi/v1/algoOpenOrders', payload, 'DELETE'),
735+
futuresGetAlgoOrder: payload => privCall('/fapi/v1/algoOrder', payload),
736+
futuresGetOpenAlgoOrders: payload => privCall('/fapi/v1/openAlgoOrders', payload),
737+
futuresGetAllAlgoOrders: payload => privCall('/fapi/v1/allAlgoOrders', payload),
597738

598739
// Delivery endpoints
599740
deliveryPing: () => pubCall('/dapi/v1/ping').then(() => true),

src/websocket.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,24 @@ const depth = (payload, cb, transform = true, variator) => {
8282
)
8383
}
8484

85+
const futuresRpiDepth = (payload, cb, transform = true) => {
86+
const cache = (Array.isArray(payload) ? payload : [payload]).map(symbol => {
87+
const symbolName = symbol.toLowerCase()
88+
const w = openWebSocket(`${endpoints.futures}/${symbolName}@rpiDepth@500ms`)
89+
w.onmessage = msg => {
90+
const obj = JSONbig.parse(msg.data)
91+
cb(transform ? futuresDepthTransform(obj) : obj)
92+
}
93+
94+
return w
95+
})
96+
97+
return options =>
98+
cache.forEach(w =>
99+
w.close(1000, 'Close handle was called', { keepClosed: true, ...options }),
100+
)
101+
}
102+
85103
const partialDepthTransform = (symbol, level, m) => ({
86104
symbol,
87105
level,
@@ -1017,6 +1035,7 @@ export default opts => {
10171035

10181036
futuresDepth: (payload, cb, transform) => depth(payload, cb, transform, 'futures'),
10191037
deliveryDepth: (payload, cb, transform) => depth(payload, cb, transform, 'delivery'),
1038+
futuresRpiDepth,
10201039
futuresPartialDepth: (payload, cb, transform) =>
10211040
partialDepth(payload, cb, transform, 'futures'),
10221041
deliveryPartialDepth: (payload, cb, transform) =>

0 commit comments

Comments
 (0)