binance-exchange/node-binance-api

How to get Account info with User Data Stream?

bengrunfeld opened this issue ยท 6 comments

Sorry if this is a bit off topic (using raw Node with ws), but maybe someone who answers could explain how to do this with node-binance-api? Although just vanilla node answer would be GREATLY appreciated too =)))

I'm using Node and the ws npm package to work with WebSockets. Got the listenKey as stated in the docs, but I'm unable to get my account info used User Data Stream. I'd prefer to use a stream to read my most current account info (balances, etc) since using the Rest API to do it incurs a penalty (WEIGHT: 5) each time.

The User Data Stream docs say "Account state is updated with the outboundAccountInfo event." Does that mean that you can only update your account via the stream, but not read your current account info?

I've tried doing ws.send('outboundAccountInfo') and then have a ws.on('message', msg => { console.log(msg)}) but no joy.

DOCS: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md

outboundAccountInfo is one of the message types of the userDataStream websocket
The other is executionReport

It was originally (and may still be) a read only event, they send updates to you once you subscribe to the user data stream

The solution for doing this with my library is here:
https://github.com/jaggedsoft/node-binance-api/blob/master/examples/advanced.md#user-data-account-balance-updates-trade-updates-new-orders-filled-orders-cancelled-orders-via-websocket

User Data: Account Balance Updates, Trade Updates, New Orders, Filled Orders, Cancelled Orders via WebSocket

// The only time the user data (account balances) and order execution websockets will fire, is if you create or cancel an order, or an order gets filled or partially filled
function balance_update(data) {
	console.log("Balance Update");
	for ( let obj of data.B ) {
		let { a:asset, f:available, l:onOrder } = obj;
		if ( available == "0.00000000" ) continue;
		console.log(asset+"\tavailable: "+available+" ("+onOrder+" on order)");
	}
}
function execution_update(data) {
	let { x:executionType, s:symbol, p:price, q:quantity, S:side, o:orderType, i:orderId, X:orderStatus } = data;
	if ( executionType == "NEW" ) {
		if ( orderStatus == "REJECTED" ) {
			console.log("Order Failed! Reason: "+data.r);
		}
		console.log(symbol+" "+side+" "+orderType+" ORDER #"+orderId+" ("+orderStatus+")");
		console.log("..price: "+price+", quantity: "+quantity);
		return;
	}
	//NEW, CANCELED, REPLACED, REJECTED, TRADE, EXPIRED
	console.log(symbol+"\t"+side+" "+executionType+" "+orderType+" ORDER #"+orderId);
}
binance.websockets.userData(balance_update, execution_update);
View Response
BNBBTC  NEW BUY LIMIT ORDER #6407865 (NEW)
..price: 0.00035595, quantity: 5.00000000
Balance Update
BTC     available: 0.77206464 (0.00177975 on order)
ETH     available: 1.14109900 (0.00000000 on order)
BNB     available: 41.33761879 (0.00000000 on order)
SNM     available: 0.76352833 (0.00000000 on order)

@jaggedsoft Thank you very much for answering my above question. Can you help create a simple ws implementation? What am I missing in the code below? I really want to beat this one ;)

async function main() {
  const uds = await createUserDataStream()

  uds.on('message', msg => {
    console.log(msg)
  })
}

async function createUserDataStream() {
  // returns valid listenKey
  const listenKey = await getListenKey()

  const p = new Promise((resolve, reject) => {
    const endpoint = `${BINANCE_DATA_STREAM_ENDPOINT}/${listenKey}`
    const ws = new WebSocket(endpoint)

    ws.on('open', () => {
      resolve(ws)
    }, error => { 
      reject(error) 
    })
  })

  p.catch(error => console.log(error))

  return p
}

This looks great. I might reuse some of this in the upcoming rewrite v0.5.0 which includes async/await if that's okay with you

You're not seeing the data? Once we get the data in json format, it's as easy as this:

const data = JSON.parse(msg); // not sure if this part is necessary
const type = data.e; // binance data type flag
if ( type === 'outboundAccountInfo' ) {
    // copy logic from execution_update above
} else if ( type === 'executionReport' ) {
    // copy logic from balance_update above
} else {
    console.warn('Unexpected userData: '+type);
}

@jaggedsoft That's about the nicest compliment I've received in a while!!! It's all yours. Unfortunately my implementation above does not return any data, but also does not error out =(
Thanks for the help all the same!!

Could you solve it?

@ribas9521 No, I resorted to HTTP requests for the User Data that I needed. This was a better fit, although it still incurs a penalty (weight) from Binance.