├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── config └── binance.php └── src ├── BinanceAPI.php ├── BinanceAPIFacade.php └── BinanceServiceProvider.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | composer.phar 3 | /vendor/ 4 | 5 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 6 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 7 | # composer.lock 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 adman9000 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-binance 2 | Laravel implementation of the Binance crypto exchange trading API 3 | 4 | ## Install 5 | 6 | #### Install via Composer 7 | 8 | ``` 9 | composer require adman9000/laravel-binance 10 | ``` 11 | 12 | Utilises autoloading in Laravel 5.5+. For older versions add the following lines to your `config/app.php` 13 | 14 | ```php 15 | 'providers' => [ 16 | ... 17 | adman9000\binance\BinanceServiceProvider::class, 18 | ... 19 | ], 20 | 21 | 22 | 'aliases' => [ 23 | ... 24 | 'Kraken' => adman9000\binance\BinanceAPIFacade::class, 25 | ], 26 | ``` 27 | 28 | ## Features 29 | 30 | Price tickers, balances, trades 31 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "adman9000/laravel-binance", 3 | "description": "Implementation of Binance trading API for Laravel", 4 | "tags": ["binance", "api", "laravel"], 5 | "type": "library", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Adam Harding", 10 | "email": "myaddressistaken@googlemail.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.6.4", 15 | "ext-curl": "*", 16 | "laravel/framework": ">=5.3" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "adman9000\\binance\\": "src/" 21 | } 22 | }, 23 | "extra": { 24 | "laravel": { 25 | "providers": [ 26 | "adman9000\\binance\\BinanceServiceProvider" 27 | ], 28 | "aliases": { 29 | "Binance": "adman9000\\binance\\BinanceAPIFacade" 30 | } 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /config/binance.php: -------------------------------------------------------------------------------- 1 | [ 13 | 'key' => env('BINANCE_KEY', ''), 14 | 'secret' => env('BINANCE_SECRET', '') 15 | ], 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | API URLs 20 | |-------------------------------------------------------------------------- 21 | | 22 | | Binance API endpoints 23 | | 24 | */ 25 | 26 | 'urls' => [ 27 | 'api' => 'https://api.binance.com/api/', 28 | 'wapi' => 'https://api.binance.com/wapi/' 29 | ], 30 | 31 | 32 | /* 33 | |-------------------------------------------------------------------------- 34 | | API Settings 35 | |-------------------------------------------------------------------------- 36 | | 37 | | Binance API settings 38 | | 39 | */ 40 | 41 | 'settings' => [ 42 | 'timing' => env('BINANCE_TIMING', 5000), 43 | 'ssl' => env('BINANCE_SSL_VERIFYPEER', true) 44 | ], 45 | 46 | ]; 47 | -------------------------------------------------------------------------------- /src/BinanceAPI.php: -------------------------------------------------------------------------------- 1 | key = config('binance.auth.key'); 19 | $this->secret = config('binance.auth.secret'); 20 | $this->url = config('binance.urls.api'); 21 | $this->wapi_url = config('binance.urls.wapi'); 22 | $this->recvWindow = config('binance.settings.timing'); 23 | $this->curl = curl_init(); 24 | 25 | $curl_options = [ 26 | CURLOPT_SSL_VERIFYPEER => config('binance.settings.ssl'), 27 | CURLOPT_SSL_VERIFYHOST => 2, 28 | CURLOPT_USERAGENT => 'Binance PHP API Agent', 29 | CURLOPT_RETURNTRANSFER => true, 30 | CURLOPT_CONNECTTIMEOUT => 20, 31 | CURLOPT_TIMEOUT => 300 32 | ]; 33 | 34 | curl_setopt_array($this->curl, $curl_options); 35 | 36 | } 37 | 38 | /** 39 | * Close CURL 40 | */ 41 | function __destruct() 42 | { 43 | curl_close($this->curl); 44 | } 45 | 46 | /** 47 | * Key and Secret setter function. It's required for TRADE, USER_DATA, USER_STREAM, MARKET_DATA endpoints. 48 | * https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#endpoint-security-type 49 | * 50 | * @param string $key API Key 51 | * @param string $secret API Secret 52 | */ 53 | function setAPI($key, $secret) 54 | { 55 | $this->key = $key; 56 | $this->secret = $secret; 57 | } 58 | 59 | 60 | //------ PUBLIC API CALLS -------- 61 | /* 62 | * getTicker 63 | * getCurrencies 64 | * getMarkets 65 | * 66 | * 67 | * 68 | * 69 | * 70 | */ 71 | 72 | /** 73 | * Get ticker 74 | * 75 | * @return mixed 76 | * @throws \Exception 77 | */ 78 | public function getTickers() 79 | { 80 | return $this->request('v1/ticker/allPrices'); 81 | } 82 | 83 | /** 84 | * Get ticker 85 | * 86 | * @return mixed 87 | * @throws \Exception 88 | */ 89 | public function getTicker($symbol) 90 | { 91 | $data = [ 92 | 'symbol' => $symbol 93 | ]; 94 | return $this->request('v1/ticker/allPrices', $data); 95 | } 96 | 97 | 98 | public function getCurrencies() 99 | { 100 | //Seems to be no such functionality 101 | return false; 102 | } 103 | 104 | /** 105 | * Current exchange trading rules and symbol information 106 | * 107 | * @return mixed 108 | * @throws \Exception 109 | */ 110 | public function getMarkets() 111 | { 112 | $return = $this->request('v1/exchangeInfo'); 113 | return $return['symbols']; 114 | } 115 | 116 | 117 | 118 | //------ PRIVATE API CALLS ---------- 119 | /* 120 | * getBalances 121 | * getRecentTrades 122 | * getOpenOrders 123 | * getAllOrders 124 | * trade 125 | * marketSell 126 | * marketBuy 127 | * limitSell 128 | * limitBuy 129 | * depositAddress 130 | */ 131 | 132 | /** 133 | * Get current account information 134 | * 135 | * @return mixed 136 | * @throws \Exception 137 | */ 138 | public function getBalances() { 139 | 140 | $b = $this->privateRequest('v3/account'); 141 | return $b['balances']; 142 | 143 | } 144 | 145 | /** 146 | * Get trades for a specific account and symbol 147 | * 148 | * @param string $symbol Currency pair 149 | * @param int $limit Limit of trades. Max. 500 150 | * @return mixed 151 | * @throws \Exception 152 | */ 153 | public function getRecentTrades($symbol = 'BNBBTC', $limit = 500) 154 | { 155 | $data = [ 156 | 'symbol' => $symbol, 157 | 'limit' => $limit, 158 | ]; 159 | 160 | $b = $this->privateRequest('v3/myTrades', $data); 161 | return $b; 162 | 163 | } 164 | 165 | public function getOpenOrders() 166 | { 167 | 168 | 169 | $b = $this->privateRequest('v3/openOrders'); 170 | return $b; 171 | 172 | } 173 | 174 | public function getAllOrders($symbol) 175 | { 176 | 177 | $data = [ 178 | 'symbol' => $symbol 179 | ]; 180 | $b = $this->privateRequest('v3/allOrders', $data); 181 | return $b; 182 | 183 | } 184 | 185 | /** 186 | * Base trade function 187 | * 188 | * @param string $symbol Asset pair to trade 189 | * @param string $quantity Amount of trade asset 190 | * @param string $side BUY, SELL 191 | * @param string $type MARKET, LIMIT, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER 192 | * @param bool $price Limit price 193 | * @return mixed 194 | * @throws \Exception 195 | */ 196 | public function trade($symbol, $quantity, $side, $type = 'MARKET', $price = false) 197 | { 198 | $data = [ 199 | 'symbol' => $symbol, 200 | 'side' => $side, 201 | 'type' => $type, 202 | 'quantity' => $quantity 203 | ]; 204 | if($price !== false) 205 | { 206 | $data['price'] = $price; 207 | } 208 | 209 | $b = $this->privateRequest('v3/order', $data, 'POST'); 210 | 211 | return $b; 212 | } 213 | 214 | /** 215 | * Sell at market price 216 | * 217 | * @param string $symbol Asset pair to trade 218 | * @param string $quantity Amount of trade asset 219 | * @return mixed 220 | * @throws \Exception 221 | */ 222 | public function marketSell($symbol, $quantity) 223 | { 224 | return $this->trade($symbol, $quantity, 'SELL', 'MARKET'); 225 | } 226 | 227 | /** 228 | * Buy at market price 229 | * 230 | * @param string $symbol Asset pair to trade 231 | * @param string $quantity Amount of trade asset 232 | * @return mixed 233 | * @throws \Exception 234 | */ 235 | public function marketBuy($symbol, $quantity) 236 | { 237 | return $this->trade($symbol, $quantity, 'BUY', 'MARKET'); 238 | } 239 | 240 | /** 241 | * Sell limit 242 | * 243 | * @param string $symbol Asset pair to trade 244 | * @param string $quantity Amount of trade asset 245 | * @param float $price Limit price to sell 246 | * @return mixed 247 | * @throws \Exception 248 | */ 249 | public function limitSell($symbol, $quantity, $price) 250 | { 251 | return $this->trade($symbol, $quantity, 'SELL', 'LIMIT', $price); 252 | } 253 | 254 | /** 255 | * Buy limit 256 | * 257 | * @param string $symbol Asset pair to trade 258 | * @param string $quantity Amount of trade asset 259 | * @param float $price Limit price to buy 260 | * @return mixed 261 | * @throws \Exception 262 | */ 263 | public function limitBuy($symbol, $quantity, $price) 264 | { 265 | return $this->trade($symbol, $quantity, 'BUY', 'LIMIT', $price); 266 | } 267 | 268 | 269 | 270 | /** 271 | * Deposit Address 272 | * @param string $symbol Asset symbol 273 | * @return mixed 274 | **/ 275 | public function depositAddress($symbol) { 276 | 277 | return $this->wapiRequest("v3/depositAddress.html", ['asset' => $symbol]); 278 | 279 | } 280 | 281 | //------ REQUESTS FUNCTIONS ------ 282 | 283 | /** 284 | * Make public requests (Security Type: NONE) 285 | * 286 | * @param string $url URL Endpoint 287 | * @param array $params Required and optional parameters 288 | * @param string $method GET, POST, PUT, DELETE 289 | * @return mixed 290 | * @throws \Exception 291 | */ 292 | private function request($url, $params = [], $method = 'GET') 293 | { 294 | // Set URL & Header 295 | curl_setopt($this->curl, CURLOPT_URL, $this->url . $url); 296 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, array()); 297 | 298 | //Add post vars 299 | if($method == 'POST') 300 | { 301 | curl_setopt($this->curl, CURLOPT_POST, count($params)); 302 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, $params); 303 | } 304 | 305 | //Get result 306 | $result = curl_exec($this->curl); 307 | if($result === false) 308 | throw new \Exception('CURL error: ' . curl_error($this->curl)); 309 | 310 | // decode results 311 | $result = json_decode($result, true); 312 | 313 | if(!is_array($result) || json_last_error()) 314 | throw new \Exception('JSON decode error'); 315 | 316 | return $result; 317 | 318 | } 319 | 320 | /** 321 | * Make private requests (Security Type: TRADE, USER_DATA, USER_STREAM, MARKET_DATA) 322 | * 323 | * @param string $url URL Endpoint 324 | * @param array $params Required and optional parameters 325 | * @param string $method GET, POST, PUT, DELETE 326 | * @return mixed 327 | * @throws \Exception 328 | */ 329 | private function privateRequest($url, $params = [], $method = 'GET') 330 | { 331 | // build the POST data string 332 | $params['timestamp'] = number_format((microtime(true) * 1000), 0, '.', ''); 333 | $params['recvWindow'] = $this->recvWindow; 334 | 335 | $query = http_build_query($params, '', '&'); 336 | 337 | // set API key and sign the message 338 | $sign = hash_hmac('sha256', $query, $this->secret); 339 | 340 | $headers = array( 341 | 'X-MBX-APIKEY: ' . $this->key 342 | ); 343 | 344 | // make request 345 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers); 346 | 347 | // build the POST data string 348 | $postdata = $params; 349 | 350 | // Set URL & Header 351 | curl_setopt($this->curl, CURLOPT_URL, $this->url . $url."?{$query}&signature={$sign}"); 352 | 353 | //Add post vars 354 | if($method == "POST") { 355 | curl_setopt($this->curl,CURLOPT_POST, 1); 356 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, array()); 357 | } 358 | 359 | //Get result 360 | $result = curl_exec($this->curl); 361 | if($result === false) 362 | throw new \Exception('CURL error: ' . curl_error($this->curl)); 363 | 364 | // decode results 365 | $result = json_decode($result, true); 366 | if(!is_array($result) || json_last_error()) 367 | throw new \Exception('JSON decode error'); 368 | 369 | return $result; 370 | 371 | } 372 | 373 | /** 374 | * Make wapi requests 375 | * 376 | * @param string $url URL Endpoint 377 | * @param array $params Required and optional parameters 378 | * @param string $method GET, POST, PUT, DELETE 379 | * @return mixed 380 | * @throws \Exception 381 | */ 382 | private function wapiRequest($url, $params = [], $method = 'GET') 383 | { 384 | // build the POST data string 385 | $params['timestamp'] = number_format((microtime(true) * 1000), 0, '.', ''); 386 | $params['recvWindow'] = $this->recvWindow; 387 | 388 | $query = http_build_query($params, '', '&'); 389 | 390 | // set API key and sign the message 391 | $sign = hash_hmac('sha256', $query, $this->secret); 392 | 393 | $headers = array( 394 | 'X-MBX-APIKEY: ' . $this->key 395 | ); 396 | 397 | // make request 398 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers); 399 | 400 | // build the POST data string 401 | $postdata = $params; 402 | 403 | // Set URL & Header 404 | curl_setopt($this->curl, CURLOPT_URL, $this->wapi_url . $url."?{$query}&signature={$sign}"); 405 | 406 | //Add post vars 407 | if($method == "POST") { 408 | curl_setopt($this->curl,CURLOPT_POST, 1); 409 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, array()); 410 | } 411 | 412 | //Get result 413 | $result = curl_exec($this->curl); 414 | if($result === false) 415 | throw new \Exception('CURL error: ' . curl_error($this->curl)); 416 | 417 | // decode results 418 | $result = json_decode($result, true); 419 | if(!is_array($result) || json_last_error()) 420 | throw new \Exception('JSON decode error'); 421 | 422 | return $result; 423 | 424 | } 425 | 426 | } -------------------------------------------------------------------------------- /src/BinanceAPIFacade.php: -------------------------------------------------------------------------------- 1 | publishes([ 13 | __DIR__.'/../config/binance.php' => config_path('binance.php') 14 | ]); 15 | } // boot 16 | 17 | public function register() 18 | { 19 | $this->mergeConfigFrom(__DIR__.'/../config/binance.php', 'binance'); 20 | $this->app->bind('binance', function() { 21 | return new BinanceAPI(config('binance')); 22 | }); 23 | 24 | 25 | 26 | } // register 27 | } --------------------------------------------------------------------------------