php-binance-api icon indicating copy to clipboard operation
php-binance-api copied to clipboard

User Data Websocket didn't receive an update.

Open GalacticSun opened this issue 6 years ago • 12 comments

I placed an Order yesterday but I didn't get an update via the User Data websocket listener I had running. It had been getting updates before and had running for a couple of weeks just fine, though.

I was watching all my logs as I placed the order, but nothing came through. Normally this websocket works fine, but this one time it didn't get the update. This worries me a bit.

Has anyone else experienced this? I also have a Websocket listening ingesting the 1sec tick data - is there an issue running two sockets at the same time like this? I have them running as two separate scripts, though.

It would be nice if we could get error reporting / status about the health of the websocket in case it crashes / has issues / hears an error from the Binance API, etc...

Platform:

  • linux

php version:

  • 7..1.12

Thank you!

GalacticSun avatar Jul 29 '18 23:07 GalacticSun

Yes I have experienced this as well. The user data websocket has been unreliable for me at times.

jaggedsoft avatar Jul 30 '18 06:07 jaggedsoft

Do you mean the Binance side has been unreliable or do you think it has to do with the PHP side? Thanks.

GalacticSun avatar Jul 30 '18 15:07 GalacticSun

I experience the same problems with their node api

jaggedsoft avatar Jul 30 '18 15:07 jaggedsoft

Oh, interesting. Sounds like maybe the Rest API might be more reliable to get Order / Trade updates? Maybe I'll go back to using that. Do you know if there's a way to get REST updates to Orders & Trades without calling the allOrders endpoint ($api->orders()) and trades ($api->trades())? Just curious if there might be a way to get individual Order and Trade updates instead of all of them every time. Thanks.

GalacticSun avatar Jul 30 '18 15:07 GalacticSun

Unfortunately, no. The REST API is more reliable but you have to request it by symbol.

I think the problem here is that the PHP Websocket does not automatically reconnect if disconnected. This needs to be fixed

jaggedsoft avatar Jul 30 '18 15:07 jaggedsoft

Ok, thanks Jon. And thanks again for your guys' API, it is very good!

GalacticSun avatar Jul 30 '18 16:07 GalacticSun

I might actually bring this up in their Telegram chat (https://t.me/binance_api_english).

GalacticSun avatar Jul 30 '18 16:07 GalacticSun

I think it's a problem with my library, not with binance. I am still limited on time but I can look in to how to implement the reconnect properly.

jaggedsoft avatar Jul 30 '18 16:07 jaggedsoft

Ok, thanks.

GalacticSun avatar Jul 30 '18 16:07 GalacticSun

Hello,

I'm having the same issue on websocket to fetch balance data. As mentioned in the binance API doc, "Start a new user data stream. The stream will close after 60 minutes unless a keepalive is sent."

I'm guessing my issue is happening only after 60 minutes, I saw a keepAlive function in your lib but how to use it?

This doesn't work:

$api = new API(<KEY>,<KEY>);
$api->userData($balance_update);
$api->keepAlive();

The callback function $balance_update is never called

elcryptoninja avatar Aug 01 '18 20:08 elcryptoninja

The keepalive should happen automatically, but I couldn't get it to work with RatchetPHP's loop structure since we already had a loop running for the websockets and you're only allowed one at a time. I'll probably need help with this. I can fix the auto-reconnect, but the keepalive logic will need some refactoring

jaggedsoft avatar Aug 01 '18 21:08 jaggedsoft

Thanks for your answer, I understand what you mean. I'm sorry I'm not familiar enough with the project to do a PR but here's my working code to replace the "userData" WS function:

The idea is to use the loop and use Ratchet connector to have both periodicTimer and WS connection.

        $loop = \React\EventLoop\Factory::create();
        $loop->addPeriodicTimer(30, function () {
            $listenKey = $this->listenKey;
            $this->httpRequest("v1/userDataStream?listenKey={$listenKey}", "PUT", []);
        });
        $connector = new \Ratchet\Client\Connector($loop);

        // @codeCoverageIgnoreStart
        // phpunit can't cover async function
       $connector($this->stream . $this->listenKey)->then(function ($ws) {
            $ws->on('message', function ($data) use ($ws) {
                if ($this->subscriptions['@userdata'] === false) {
                    //$this->subscriptions[$endpoint] = null;
                    $ws->close();
                    return; //return $ws->close();
                }
                $json = json_decode($data);
                $type = $json->e;
                if ($type === "outboundAccountInfo") {
                    $balances = $this->balanceHandler($json->B);
                    $this->info['balanceCallback']($this, $balances);
                } elseif ($type === "executionReport") {
                    $report = $this->executionHandler($json);
                    if ($this->info['executionCallback']) {
                        $this->info['executionCallback']($this, $report);
                    }
                }
            });
            $ws->on('close', function ($code = null, $reason = null) {
                // WPCS: XSS OK.
                echo "userData: WebSocket Connection closed! ({$code} - {$reason})" . PHP_EOL;
            });
        }, function ($e) {
            // WPCS: XSS OK.
            echo "userData: Could not connect: {$e->getMessage()}" . PHP_EOL;
        });

        $loop->run();

EDIT: Periodic timer is in seconds so it should be 30 * 60 instead

elcryptoninja avatar Aug 01 '18 22:08 elcryptoninja