From cda27449b61b59b673d65f865c9356c1a2f20051 Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:13:51 +0200 Subject: [PATCH 1/8] Implement rate limiting retrieval --- README.md | 27 +++++++++++++++++++++++++++ bitvavo.php | 54 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 552f361..0b6a45e 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,33 @@ $currentTime = $response["time"]; echo $currentTime ``` +#### Rate limiting + +After every request [rate limits](https://docs.bitvavo.com/#section/Rate-limiting) are remembered, and can be subsequentially acquired by following method `$bitvavo->getRatelimit($key);`. Key can be one of `limit`, `remaining`, or `resetat`. Here is an example code to that you can use to achieve high throughput without hitting a ban: + +``` +function handleRateimiting($bitvavo) { + $remaining = $bitvavo->getRatelimit('remaining'); + + if (empty($remaining) || $remaining > 200) { + return; + } + + $resetat = $$bitvavo->getRatelimit('resetat'); + $resetat *= 1000; + $now = time() * 1000000; + $delay = $resetat - $now; + + // If the last request has been done a while ago. + if ($delay <= 0) { + return; + } + + // Have to use usleep() for sub-second resolution. + usleep($delay); +} +``` + ### General #### Get time diff --git a/bitvavo.php b/bitvavo.php index f8ba8b6..9bc844f 100644 --- a/bitvavo.php +++ b/bitvavo.php @@ -126,9 +126,55 @@ function createCurl($url, $method, $params) { curl_setopt($curl, CURLOPT_URL, $url); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, true); + return $curl; } + function processRatelimit($header) { + + $this->ratelimit = []; + + $header = explode("\n", $header); + $header = array_map(function($line) {return trim($line);}, $header); + foreach ($header as $h) { + if (preg_match('/^bitvavo-ratelimit-(limit|remaining|resetat): +(\d+)$/', $h, $match)) { + list(, $key, $value) = $match; + $this->ratelimit[$key] = (int) $value; + } + } + } + + function getRatelimit($key) { + + if (!in_array($key, ['limit', 'remaining', 'resetat'])) { + errorToConsole("Invalid key ($key). Accepted valueas are: limit, remaining, resetat.\n"); + return; + } + + // No request has been performed. + if (empty($this->ratelimit)) { + return; + } + + // API has changed or is broken. + if (!array_key_exists($key, $this->ratelimit)) { + return; + } + + return $this->ratelimit[$key]; + } + + function execCurl($curl) { + $response = curl_exec($curl); + $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE); + $header = substr($response, 0, $header_size); + $this->processRatelimit($header); + $body = substr($response, $header_size); + $json = json_decode($body, true); + return $json; + } + function sendPublic($url, $params, $method, $data) { $curl = $this->createCurl($url, $method, $params); $endpoint = str_replace(array($this->base), array(''), $url); @@ -150,9 +196,7 @@ function sendPublic($url, $params, $method, $data) { ); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } - $output = curl_exec($curl); - $json = json_decode($output, true); - return $json; + return $this->execCurl($curl); } function sendPrivate($endpoint, $params, $body, $method, $apiSecret, $base, $apiKey) { @@ -180,9 +224,7 @@ function sendPrivate($endpoint, $params, $body, $method, $apiSecret, $base, $api curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body)); } - $output = curl_exec($curl); - $json = json_decode($output, true); - return $json; + return $this->execCurl($curl); } public function time() { From a75ad728c90eebef79f9d310958e1dbd86e981da Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:15:44 +0200 Subject: [PATCH 2/8] Remove PHP8 incompatibility --- bitvavo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitvavo.php b/bitvavo.php index 9bc844f..f37b7e1 100644 --- a/bitvavo.php +++ b/bitvavo.php @@ -403,7 +403,7 @@ function sortAndInsert($update, $book, $sortFunc) { } class Websocket { - public function __construct($bitvavo = null, $reconnect = false, $publicCommandArray, $privateCommandArray, $oldSocket) { + public function __construct($bitvavo, $reconnect, $publicCommandArray, $privateCommandArray, $oldSocket) { $this->parent = $bitvavo; $this->wsurl = $bitvavo->wsurl; $this->apiKey = $bitvavo->apiKey; From f5e4f400c956582ea9741bec61d0b00ac5f2a17c Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:17:35 +0200 Subject: [PATCH 3/8] Remove closing PHP tag. This is omitted by default from PHP libs. --- bitvavo.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/bitvavo.php b/bitvavo.php index f37b7e1..41599d3 100644 --- a/bitvavo.php +++ b/bitvavo.php @@ -879,5 +879,3 @@ public function subscriptionBook($market, callable $callback) { $this->sendPublic(["action" => "getBook", "market" => $market]); } } - -?> \ No newline at end of file From fa893ada717f50612923f8f1c1a2d4d1ad383d2f Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:21:08 +0200 Subject: [PATCH 4/8] Remove spaces from the end of the lines. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0b6a45e..f44ddce 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This is the PHP wrapper for the Bitvavo API. This project can be used to build y * Price Ticker [REST](https://github.com/bitvavo/php-bitvavo-api#get-price-ticker) [Websocket](https://github.com/bitvavo/php-bitvavo-api#get-price-ticker-1) * Book Ticker [REST](https://github.com/bitvavo/php-bitvavo-api#get-book-ticker) [Websocket](https://github.com/bitvavo/php-bitvavo-api#get-book-ticker-1) * 24 Hour Ticker [REST](https://github.com/bitvavo/php-bitvavo-api#get-24-hour-ticker) [Websocket](https://github.com/bitvavo/php-bitvavo-api#get-24-hour-ticker-1) -* Private +* Private * Place Order [REST](https://github.com/bitvavo/php-bitvavo-api#place-order) [Websocket](https://github.com/bitvavo/php-bitvavo-api#place-order-1) * Update Order [REST](https://github.com/bitvavo/php-bitvavo-api#update-order) [Websocket](https://github.com/bitvavo/php-bitvavo-api#update-order-1) * Get Order [REST](https://github.com/bitvavo/php-bitvavo-api#get-order) [Websocket](https://github.com/bitvavo/php-bitvavo-api#get-order-1) @@ -66,7 +66,7 @@ The API key and secret are required for private calls and optional for public ca require_once('bitvavo.php'); $bitvavo = new Bitvavo([ - "APIKEY" => "", + "APIKEY" => "", "APISECRET" => "", "RESTURL" => "https://api.bitvavo.com/v2", "WSURL" => "wss://ws.bitvavo.com/v2/", @@ -2006,7 +2006,7 @@ Cancels all orders in a market. If no market is specified, all orders of an acco // options: market $websock->cancelOrders(["market" => "BTC-EUR"], function($response) { foreach ($response as $deletion) { - echo json_encode($deletion) . "\n"; + echo json_encode($deletion) . "\n"; } }); ``` From 81ea190f2cc836799c18d68bb1f2dcc946468e20 Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:21:26 +0200 Subject: [PATCH 5/8] Fix missing newline at the end of the file. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f44ddce..2a36ed5 100644 --- a/README.md +++ b/README.md @@ -2599,4 +2599,4 @@ $websock->subscriptionBook("BTC-EUR", function($response) { "nonce": 18632 } ``` - \ No newline at end of file + From b0a9d028e562f6defb420a823eec743e8850c13b Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:23:12 +0200 Subject: [PATCH 6/8] Change heading level in README for Rate limiting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a36ed5..92923fa 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ $currentTime = $response["time"]; echo $currentTime ``` -#### Rate limiting +### Rate limiting After every request [rate limits](https://docs.bitvavo.com/#section/Rate-limiting) are remembered, and can be subsequentially acquired by following method `$bitvavo->getRatelimit($key);`. Key can be one of `limit`, `remaining`, or `resetat`. Here is an example code to that you can use to achieve high throughput without hitting a ban: From 721e94d53121c64e0b27ddb22b67915094cc7f5f Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:24:15 +0200 Subject: [PATCH 7/8] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92923fa..db9d881 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ echo $currentTime ### Rate limiting -After every request [rate limits](https://docs.bitvavo.com/#section/Rate-limiting) are remembered, and can be subsequentially acquired by following method `$bitvavo->getRatelimit($key);`. Key can be one of `limit`, `remaining`, or `resetat`. Here is an example code to that you can use to achieve high throughput without hitting a ban: +After every request [rate limits](https://docs.bitvavo.com/#section/Rate-limiting) are remembered, and can be subsequentially acquired by following method `$bitvavo->getRatelimit($key);`. Key can be one of `limit`, `remaining`, or `resetat`. Here is an example code that you can use to achieve high throughput without hitting a ban: ``` function handleRateimiting($bitvavo) { From d806cbd1358bf922b133b02680ee68603acfeedc Mon Sep 17 00:00:00 2001 From: Ragnar Kurm Date: Sun, 28 Feb 2021 21:25:36 +0200 Subject: [PATCH 8/8] Specify code language in README. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db9d881..b9c50dc 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,9 @@ echo $currentTime After every request [rate limits](https://docs.bitvavo.com/#section/Rate-limiting) are remembered, and can be subsequentially acquired by following method `$bitvavo->getRatelimit($key);`. Key can be one of `limit`, `remaining`, or `resetat`. Here is an example code that you can use to achieve high throughput without hitting a ban: -``` +```PHP function handleRateimiting($bitvavo) { + $remaining = $bitvavo->getRatelimit('remaining'); if (empty($remaining) || $remaining > 200) {