altangent / ccxws

WebSocket client for 38 cryptocurrency exchanges
MIT License
619 stars 187 forks source link

error handler #274

Open pro-git opened 3 years ago

pro-git commented 3 years ago

Seem that I can't install a error handler for each exchange, there is only one for all of them. If I use multiple exchanges, only the last one is firing for errors from all exchanges. So, how can I find the source of this error (exchange)?

Error: <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

404 Not Found

404 Not Found

at IncomingMessage.<anonymous> (/projects/ccxwscode/node_modules/ccxws/src/https.js:37:25)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
bmancini55 commented 3 years ago

Thanks for submitting the issue! Can you provide example code of how you're attaching the error handler to each client?

pro-git commented 3 years ago

the issue was my code but, maybe I'm wrong, but "error", "disconnect", "reconnecting" "connecting", "connected" should also emit the name of the exchange. Also, when there is a fatal connection error, maybe connection should be aborted after N tries in order to avoid the rate limit. How can I catch the error of subscribing to Level2Updates or Level2Snapshots? There is a debug mode?

import ccxws from 'ccxws';
import chalk from 'chalk'

const subscribeData1 = {
  id: "ETHUSDT",
  base: "ETH",
  quote: "USDT",
};

import ccxws from 'ccxws';
import chalk from 'chalk'

const subscribeData1 = {
  id: "ETHUSDT",
  base: "ETH",
  quote: "USDT",
};

var exchanges = [ 'bitfinex','coinbasepro', 'huobipro', 'bitstamp', 'okex', 'gateio', 'liquid', 'poloniex' ]
var ccxwsArray = {}
for ( var i = 0; i < exchanges.length; i++ ) {  
    var exchange = exchanges[i]
    ccxwsArray[exchange] = new ccxws[exchange]()
    ccxwsArray[exchange].on("l2updates", (updates, market) => console.log(updates));
    ccxwsArray[exchange].on("l2snapshot", (snapshot, market) => console.log(snapshot));
    ccxwsArray[exchange].on("error", err => console.error(chalk.red("error: ")+("%s"), err));
    ccxwsArray[exchange].on("disconnected", () => console.log("disconnected"));
    ccxwsArray[exchange].on("reconnecting", () => console.log("reconnecting"));
    ccxwsArray[exchange].on("connecting", () => console.log("connecting"));
    ccxwsArray[exchange].on("connected", () => console.log("connected"));
    ccxwsArray[exchange].subscribeLevel2Updates(subscribeData1);
    ccxwsArray[exchange].subscribeLevel2Snapshots(subscribeData1);
}
bmancini55 commented 3 years ago

Thanks for the reply! Error events currently do not include the name of the exchange or client scope of the error. There is an item #104 that tracks improving error handling. That covers both this type of error (additional information about errors) as well as tracking subscription failures. Unfortunately the library doesn't support a great way to detect subscription errors.

pro-git commented 3 years ago

Including name of the exchange in error events and disconnect/reconnecting/connected events at least should be easy.

bmancini55 commented 3 years ago

In the example code you posted your exchange is closure scoped. You can just reference the exchange in the error handler event.

ccxwsArray[exchange].on("error", err => console.error(chalk.red("error: ")+exchange+("%s"), err));

Alternative you could use a curry if you have a more complicated construct:

const errorHandler = function (exchange) {
    return err => console.error(chalk.red("error: ")+exchange+(" %s"), err)
}

ccxwsArray[exchange].on("error", errorHandler(exchange));
pro-git commented 3 years ago

that was what I did initially

ccxwsArray[exchange].on("error", err => console.error(chalk.red("%s: ")+("%s"), exchange, err));

but the error is always firing with the name of the last exchange in array. Maybe because that's the last state of "exchange" variable at the moment when "on" is firing.

pro-git commented 3 years ago

solved. using exchanges.forEach(myFunction) instead of "for" loop.

bmancini55 commented 3 years ago

Nice! I think you could have also changed the var to let or const so that variable doesn't get hoisted.

const exchange = exchanges[i]

With var, the hoisting breaks the per-iteration assignment and the closure used the last value. With forEach a var will be scoped to the function, so the hoisting has no effect.

pro-git commented 3 years ago

I got printed to console "warn: failure response {"event":"error","message":"Channel spot/depth_l2_tbt:ETHUSDT doesn't exist","errorCode":30040}" even without error handler. How can I find the source of the message? (exchange). This error shouldn't go trough the Error handler?

Also, I didn't get any l2updates from any exchange and after less than a minute all of the get disconnected & reconnect. BTW, there is a automatic re-subscription on reconnect?

bmancini55 commented 3 years ago

Looks like it's from okex. Some of the older clients don't emit errors and just log warnings. That needs to be fixed.

pro-git commented 3 years ago

Any ideea why I'm not receiving any data from any exchange?

using

const market1 = {
  id: "ETHUSDT", // remote_id used by the exchange
  base: "ETH",  // standardized base symbol for Bitcoin
  quote: "USDT", // standardized quote symbol for Tether
};
      ccxwsArray[exchange].on("l2updates", updates => console.log("%s", updates));
      ccxwsArray[exchange].subscribeLevel2Updates(market1);
      ccxwsArray[exchange].on("l2snapshots", snapshots => console.log("%s", snapshots));
      ccxwsArray[exchange].subscribeLevel2Snapshots(market1);
bmancini55 commented 3 years ago

Possibly that market id is unique to exchanges. Make sure you use the correct id for each exchange even if it's the same base and quote pair as other exchanges.