tiagosiebler / binance

Node.js & JavaScript SDK for Binance REST APIs & WebSockets, with TypeScript & browser support, integration tests, beautification & more.
MIT License
751 stars 266 forks source link

subscribeSpotTrades does not emit `formattedMessage` #267

Closed caiusCitiriga closed 1 year ago

caiusCitiriga commented 1 year ago

When subscribing to spot trades with the ws client, the formattedMessage event is never emitted. The message instead works, providing a Buffer, that converted matches the Binance's trade indeed.

Isn't this feature supported yet or am I doing something wrong? Here's the code I'm using:

Instantiation

this.wsClient = new WebsocketClient({
  beautify: true,
  api_key: this.scannerConfig.thisScanner.exchangeKey,
  api_secret: this.scannerConfig.thisScanner.exchangeSecret,
});

Subscribtion

for (let market of markets) {
  // "market" is in form of BASEQUOTE eg: BTCUSDT
  const ws = this.wsClient.subscribeSpotTrades(market.id, true);
  ws.on('formattedMessage', (msg) => {
    console.log(msg)
  });
  ws.on('message', (msg) => {
    const data = String.fromCharCode.apply(null, new Uint16Array(msg));
    console.log(msg)
  });
}

Update:

Sorry, removed the debugger keyword, since I was running the code in debug mode, to try to stop with a breakpoint in there once the message was emitted.

As I said, the "formattedMessage" event never logs anything to the console, while the "message" event gets invoked as expected.

caiusCitiriga commented 1 year ago

@tiagosiebler sorry, fixed the snippet as explained under the "update" title 🙏🏻

tiagosiebler commented 1 year ago

@tiagosiebler sorry, fixed the snippet as explained under the "update" title 🙏🏻

No worries! You almost had it. So, yes, the subscribe* methods return the websocket object for that connection, but you shouldn't use it directly. Instead, listen to events on the wsClient (which handles the formatting).

I did a quick PR (#268) to add an example for your case (multiple symbol trade subscriptions). Also took liberty to add a type guard to use in a lazy if-block in your formattedMessage handler, in case you're in typescript land it also narrows down the type for you. Take a look at the example - the subscribe call is a fire-and-forget call (ignore the return value): https://github.com/tiagosiebler/binance/blob/master/examples/ws-public-spot-trades.ts#L47-L54

The ws client will emit events directly, and you can use that type guard to catch that exact event as it flows through: https://github.com/tiagosiebler/binance/blob/master/examples/ws-public-spot-trades.ts#L25-L29

The reason you don't want to use the raw websocket returned by the subscribeSpotTrades call directly is that this websocket may get killed and respawned (e.g. if the connection drops). This is done automatically to keep a healthy connection should your network or binance have any issues.

If you only listen to events on the ws object returned by this fn, you may end up missing events if the websocket is replaced with a fresh one. If you stick to wsClient event handlers, the ws client will make sure events are always emitted. You can test this by killing your internet/wifi/vpn a few times. It should respawn a fresh connection and keep emitting events via the websocket client as soon as your connection returns - without any extra code on your end.

caiusCitiriga commented 1 year ago

@tiagosiebler sorry, fixed the snippet as explained under the "update" title 🙏🏻

No worries! You almost had it. So, yes, the subscribe* methods return the websocket object for that connection, but you shouldn't use it directly. Instead, listen to events on the wsClient (which handles the formatting).

I did a quick PR (#268) to add an example for your case (multiple symbol trade subscriptions). Also took liberty to add a type guard to use in a lazy if-block in your formattedMessage handler, in case you're in typescript land it also narrows down the type for you. Take a look at the example - the subscribe call is a fire-and-forget call (ignore the return value): https://github.com/tiagosiebler/binance/blob/master/examples/ws-public-spot-trades.ts#L47-L54

The ws client will emit events directly, and you can use that type guard to catch that exact event as it flows through: https://github.com/tiagosiebler/binance/blob/master/examples/ws-public-spot-trades.ts#L25-L29

The reason you don't want to use the raw websocket returned by the subscribeSpotTrades call directly is that this websocket may get killed and respawned (e.g. if the connection drops). This is done automatically to keep a healthy connection should your network or binance have any issues.

If you only listen to events on the ws object returned by this fn, you may end up missing events if the websocket is replaced with a fresh one. If you stick to wsClient event handlers, the ws client will make sure events are always emitted. You can test this by killing your internet/wifi/vpn a few times. It should respawn a fresh connection and keep emitting events via the websocket client as soon as your connection returns - without any extra code on your end.

Wooooow that's super sweet! I'll get right to it and try with this new approach 😊 Also, thank you for the example you've added 😍