zhouaini528 / binance-php

Binance API Like the official document interface, Support for arbitrary extension.
MIT License
107 stars 43 forks source link

I'm getting output 'Alarm Clock' and code refusing to do small loop #20

Open StevenFlecha opened 3 years ago

StevenFlecha commented 3 years ago

Hey,

Not an issue but more of a question.

I'm just testing a bit and currently have this code:

$binance->keysecret([
    'key' => $binanceConfig['key'],
    'secret' => $binanceConfig['secret'],
]);

$binance->subscribe([
    'btcusdt@markPrice'
]);

$x = 15;
while($x > 0){
    echo "<br />run $x";
    $data = $binance->getSubscribes();
    echo "<pre>";
    print_r(json_encode($data));
    echo "</pre>\n\n";
    sleep(3);
    $x = $x - 1;
}

$binance->unsubscribe([
    'btcusdt@markPrice'
]);

And this is the result: https://dl.dropbox.com/s/zxu4sfcjy7931h7/shot_210523_175315.png

I would expect it to run 15 times.. but it runs only once and it outputs this text 'Alarm Clock' it does not come from my code.. I searched your code based and the string 'Alarm Clock' is also nowhere to be found - so I have no idea where that is coming from.

Any ideas what is happening here?

Thanks! Steven

zhouaini528 commented 3 years ago

Thank you for your feedback. I'll check it. The problem is to quote it workerman You can try this way

//The third way is to guard the process
        $binance->getSubscribes(function($data){
            print_r(json_encode($data));
        },true);
StevenFlecha commented 3 years ago

Yeah I found out it comes from pcntl_alarm Haven't yet completely figured out why and how.

I keep getting it for either: $binance->getSubscribes(); And for

$binance->getSubscribe([ 'btcusdt@markPrice' ],function($data) use ($fundingRate) { if(is_array($data)){ $fundingRate = $data['btcusdt@markPrice']['data']['r']; }

    echo "Data: <pre>";
    print_r($data);
    echo "</pre>\n\n";
});

Will try and use the 'guard' version.

zhouaini528 commented 3 years ago

You try this 'symbol=btcusdt@depth' and comment out the code 'sleep(3)'.The main problem is sleep.

$binance->keysecret([
    'key' => $binanceConfig['key'],
    'secret' => $binanceConfig['secret'],
]);

$binance->subscribe([
    'btcusdt@depth'
]);

$x = 15;
while($x > 0){
    echo "<br />run $x";
    $data = $binance->getSubscribes();
    echo "<pre>";
    print_r(json_encode($data));
    echo "</pre>\n\n";
    //sleep(3);
    $x = $x - 1;
}

$binance->unsubscribe([
    'btcusdt@depth'
]);

You need to execute it twice, because the first time you need to subscribe, the second time you can get the data So I suggest you use this method

//The third way is to guard the process
        $binance->getSubscribes(function($data){
            print_r(json_encode($data));
        },true);
StevenFlecha commented 3 years ago

I read that pcntl_alarm gets triggered instantly when using sleep(..) indeed so removed that.

I then tried to use the 'guard' way to retrieve the data but then I get this problem: https://dl.dropbox.com/s/730vuiyiaukczib/shot_210523_230907.png When calling getSubscribes using the 'guard' method it gives that error each time.

When I use

    $binance->getSubscribe([
        'btcusdt@markPrice'
    ], function($data) use ($fundingRate){
        echo "Data: <pre>";
        print_r($data);
        echo "</pre>\n\n";

        if(is_array($data)){
            $fundingRate = $data['btcusdt@markPrice']['data']['r'];
        }
    }, true);

I also get the 'Usage: php yourfile [mode]' error.

When I use it without ', true' it runs.. but even then it sometimes works and sometimes doesn't.

Example when doesn't work: https://dl.dropbox.com/s/9733m4jz585zlt3/shot_210523_231708.png The callback function is never called. (I set it to 20 runs)

Then I tried again (this time with 50 run): https://dl.dropbox.com/s/klzvqbo5o0je0s1/shot_210523_231814.png This time it worked in first run.

BTW if I change btcusdt@markPrice to symbol=btcusdt@markPrice then it doesn't work at all anymore.

StevenFlecha commented 3 years ago

ok so I have it working ... sometimes. When I run the script sometimes it works and sometimes I still get 'Alarm clock'

my code

function Finish($binance, $fundingRate){
    $fundingRate = sprintf('%f', $fundingRate*100);
    $fundingRate = rtrim($fundingRate,'0');
    echo "Funding rate for btcusdt is: ".$fundingRate."%";

    echo "\n going to unsub now \n";
    $binance->unsubscribe([
        'btcusdt@markPrice'
    ]);

    echo "<br />Stopping server:\n";
    $a = exec("php binanceSocketServer.php stop");
    if($a !== false){
        echo "<br /> server stopped\n";
    }
    else{
        echo "failed to stop Binance Socket server.. exitting\n";
        exit;
    }
}

$run = true;
while($run === true){
    $t = $binance->getSubscribe([
        'btcusdt@markPrice'
    ], function($data) use ($fundingRate, $run, $binance){

        //echo "\nData: <pre>";
        //print_r($data);
        //echo "</pre>\n\n";

        if(is_array($data)){
            $fundingRate = $data['btcusdt@markPrice']['data']['r'];
            echo "Fundingrate: $fundingRate% \n";
            Finish($binance, $fundingRate);
        }
    });

    if( isset($t['btcusdt@markPrice']['data']['r']) ) break;

}

I feel I'm doing something wrong conceptually - it can't be using sockets and Binance API are so unreliable that sometimes it works and sometimes it doesn't: https://dl.dropbox.com/s/nsp8mudsz719mwv/shot_210524_003639.png

Thanks for the help!

zhouaini528 commented 3 years ago

I'm sorry I just told you wrong. I subscribed to'btcusdt@markPrice' but the exchange did not push data, so the data cannot be obtained by'getSubscribe'. The code I gave is to let you subscribe to it'btcusdt@depth', so that you can better analyze the SDK problem or the exchange problem.You copy the code and run directly demo

For the stability and maintainability of websocket, I suggest that you should use a cache method for storage, such as redis. Then read the data from redis. Here is a use case to get the market quotation websocket-market (you need to translate it) You can see the source code.

numairawan commented 3 years ago

@zhouaini528 and @StevenFlecha did you guys fixed the issue? Facing the same problem,

loop is not working when getting the data from websockets or subscribing the stream, i also tried the third way to guard the processor but no luck.



$getTickerPrice = '';
$binanceWSSpot->getSubscribe([$symbol],function($data){
    $getTickerPrice = $data;
},true);

//$getTickerPrice = $binanceWSSpot->getSubscribe(["$symbol"]);

if (empty($getTickerPrice)) {
     $binanceWSSpot->subscribe(["$symbol"]);
} else {
    $tickerPrice = json_encode($getTickerPrice["$symbol"]['data']['c']);
    $tickerPrice = str_replace('"', "", $tickerPrice);

zhouaini528 commented 3 years ago

@NumairAwan The 'Alarm Clock' problem occurred because I used the Workerman shared process component. To solve this problem, we need to adopt the daemon mode of the component (client_spot.php start -d).

The first and second methods I have given can only be executed once in the current process life cycle. If the loop mode is used, the "Alarm Clock" will appear, so the best method is to use the third method.

//The first way
$data=$binance->getSubscribe();
print_r(json_encode($data));

//The second way callback
$binance->getSubscribe(function($data){
    print_r(json_encode($data));
});

//****Recommended way
//The third way is to guard the process
$binance->getSubscribe(function($data){
    print_r(json_encode($data));
},true);

The third method uses the closure method. You cannot use variables in this way. The correct way is as follows.

$getTickerPrice = '';
$binanceWSSpot->getSubscribe([$symbol],function($data) use($getTickerPrice,$binanceWSSpot){
    $getTickerPrice = $data;
    //$getTickerPrice = $binanceWSSpot->getSubscribe(["$symbol"]);
    if (empty($getTickerPrice)) {
    $binanceWSSpot->subscribe(["$symbol"]);
    } else {
    $tickerPrice = json_encode($getTickerPrice["$symbol"]['data']['c']);
    $tickerPrice = str_replace('"', "", $tickerPrice);
},true);
numairawan commented 3 years ago

@zhouaini528 did you update something? It was working fine before like a months ago. I am using the loop to get and update the PnL of open trades. Tried your thirdway, yeah its working but its not working inside any loop. Also i need to start the processor with workerman.

$binanceWSSpot->getSubscribe([$symbol],function($data) use($getTickerPrice,$binanceWSSpot){
    $getTickerPrice = $data;
    //$getTickerPrice = $binanceWSSpot->getSubscribe(["$symbol"]);
    if (empty($getTickerPrice)) {
    $binanceWSSpot->subscribe(["$symbol"]);
    } else {
    $tickerPrice = json_encode($getTickerPrice["$symbol"]['data']['c']);
    $tickerPrice = str_replace('"', "", $tickerPrice);
}
},true);

When i start the process, loop dont work. But if i remove "true" processor stopped and print alarm clock.

$binanceWSSpot->getSubscribe([$symbol],function($data) use($getTickerPrice,$binanceWSSpot){
    $getTickerPrice = $data;
    //$getTickerPrice = $binanceWSSpot->getSubscribe(["$symbol"]);
    if (empty($getTickerPrice)) {
    $binanceWSSpot->subscribe(["$symbol"]);
    } else {
    $tickerPrice = json_encode($getTickerPrice["$symbol"]['data']['c']);
    $tickerPrice = str_replace('"', "", $tickerPrice);
}
});

image

here is the simple code that was working fine few months back. (sleep is not the issue, even if i dont use delay the loop will stop after 20 to 30 loops)

 while (true){
   $getTickerPrice = $binanceWSSpot->getSubscribe(["$symbol"]);
$tickerPrice = json_encode($getTickerPrice["$symbol"]['data']['c']);
    $tickerPrice = str_replace('"', "", $tickerPrice);

    print $tickerPrice;
    sleep(1);
 }

Check this out.

$x = 10;
while($x > 0){

$symbol = 'btcusdt@miniTicker';
$binanceWSSpot->getSubscribe([$symbol],function($data) use ($binanceWSSpot, $symbol){
    $getTickerPrice = $data;
    //$getTickerPrice = $binanceWSSpot->getSubscribe(["$symbol"]);
    if (empty($getTickerPrice)) {
    $binanceWSSpot->subscribe(["$symbol"]);
    } else {
    $tickerPrice = json_encode($getTickerPrice["$symbol"]['data']['c']);
    $tickerPrice = str_replace('"', "", $tickerPrice);

    print $tickerPrice  . PHP_EOL;

    }
    sleep(1);
},true);

print 'This code never work' . PHP_EOL;

$x = $x - 1;
}

Result;

image

zhouaini528 commented 3 years ago

@NumairAwan I use the Workerman sdk. The official documentation explains that there can be no infinite loop or sleep. "If you use GlobalData/Client in the Workerman environment, please instantiate the GlobalData/Client object in the onXXX callback, for example, instantiate it in onWorkerStart ."

The first and second methods of obtaining data are suitable for one-time access. If you want the current process to obtain data multiple times, you must use the "Timer" timer to obtain. You can see my source code (Here). The third method is "Timer".

Although the demo you gave is successful, its efficiency is not high, so this method is not recommended.

zhouaini528 commented 3 years ago

@NumairAwan @StevenFlecha I have found the problem, because I use 'workerman', and it uses 'pcntl_alarm', it will alarm when using sleep, the correct solution is as follows

while(1){
    pcntl_alarm(0);
    sleep(1);
    $data=$binance->getSubscribes();
    print_r(json_encode($data));
}
numairawan commented 3 years ago

@zhouaini528 Thank you very much now its working fine, but sometimes getSubscribe returning the same value for 10 to 30 minutes, to fix it in loop, subscribe to the same stream in each loop will fix it.