Issues (11)

src/BinanceAPI.php (10 issues)

1
<?php
2
3
namespace sabramooz\binance;
4
5
use Exception;
6
7
class BinanceAPI
8
{
9
    protected $key;         // API key
10
    protected $secret;      // API secret
11
    protected $url;         // API base URL
12
    protected $recvWindow;  // API base URL
13
    protected $version;     // API version
14
    protected $curl;        // curl handle
15
16
    /**
17
     * Constructor for BinanceAPI
18
     */
19
    function __construct()
20
    {
21
        $this->key = config('binance.auth.key');
22
        $this->secret = config('binance.auth.secret');
23
        $this->url = config('binance.urls.api');
24
        $this->wapi_url = config('binance.urls.wapi');
0 ignored issues
show
Bug Best Practice introduced by
The property wapi_url does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
25
        $this->recvWindow = config('binance.settings.timing');
26
        $this->curl = curl_init();
27
28
        $curl_options = [
29
            CURLOPT_SSL_VERIFYPEER => config('binance.settings.ssl'),
30
            CURLOPT_SSL_VERIFYHOST => 2,
31
            CURLOPT_USERAGENT => 'Binance PHP API Agent',
32
            CURLOPT_RETURNTRANSFER => true,
33
            CURLOPT_CONNECTTIMEOUT => 20,
34
            CURLOPT_TIMEOUT => 300
35
        ];
36
37
        curl_setopt_array($this->curl, $curl_options);
38
39
    }
40
41
    /**
42
     * Close CURL
43
     */
44
    function __destruct()
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
45
    {
46
        curl_close($this->curl);
47
    }
48
49
    /**
50
     * Key and Secret setter function. It's required for TRADE, USER_DATA, USER_STREAM, MARKET_DATA endpoints.
51
     * https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#endpoint-security-type
52
     *
53
     * @param string $key API Key
54
     * @param string $secret API Secret
55
     */
56
    function setAPI($key, $secret)
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
57
    {
58
        $this->key = $key;
59
        $this->secret = $secret;
60
    }
61
62
63
    //------ PUBLIC API CALLS --------
64
    /*
65
    * getTicker
66
    * getCurrencies
67
    * getMarkets
68
    * getAvgPrice
69
    */
70
71
    /**
72
     * Get ticker
73
     *
74
     * @return mixed
75
     * @throws Exception
76
     */
77
    public function getTickers()
78
    {
79
        return $this->request('v3/ticker/price');
80
    }
81
82
    /**
83
     * Make public requests (Security Type: NONE)
84
     *
85
     * @param string $url URL Endpoint
86
     * @param array $params Required and optional parameters
87
     * @param string $method GET, POST, PUT, DELETE
88
     * @return mixed
89
     * @throws Exception
90
     */
91
    private function request($url, $params = [], $method = 'GET')
92
    {
93
        // Set URL & Header
94
        curl_setopt($this->curl, CURLOPT_URL, $this->url . $url);
95
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, array());
96
97
        //Add post vars
98
        if ($method == 'POST') {
99
            curl_setopt($this->curl, CURLOPT_POST, count($params));
100
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, $params);
101
        }
102
103
        //Get result
104
        $result = curl_exec($this->curl);
105
        if ($result === false)
106
            throw new Exception('CURL error: ' . curl_error($this->curl));
107
108
        // decode results
109
        $result = json_decode($result, true);
0 ignored issues
show
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

109
        $result = json_decode(/** @scrutinizer ignore-type */ $result, true);
Loading history...
110
111
        if (!is_array($result) || json_last_error())
112
            throw new Exception('JSON decode error');
113
114
        return $result;
115
116
    }
117
118
    /**
119
     * Get ticker
120
     *
121
     * @return mixed
122
     * @throws Exception
123
     */
124
    public function getTicker($symbol)
125
    {
126
        $data = [
127
            'symbol' => $symbol
128
        ];
129
        return $this->request('v3/ticker/price?symbol=' . $symbol , $data);
130
    }
131
132
    /**
133
     * Get ticker
134
     *
135
     * @param $symbol
136
     * @return mixed
137
     * @throws Exception
138
     */
139
    public function getAvgPrice($symbol)
140
    {
141
        $data = [
142
            'symbol' => $symbol
143
        ];
144
        return $this->request('v3/avgPrice?symbol='.$symbol, $data);
145
    }
146
147
    public function getCurrencies()
148
    {
149
        //Seems to be no such functionality
150
        return false;
151
    }
152
153
154
    //------ PRIVATE API CALLS ----------
155
    /*
156
    * getBalances
157
    * getRecentTrades
158
    * getOpenOrders
159
    * getAllOrders
160
    * trade
161
    * marketSell
162
    * marketBuy
163
    * limitSell
164
    * limitBuy
165
    * depositAddress
166
    */
167
168
    /**
169
     * Current exchange trading rules and symbol information
170
     *
171
     * @return mixed
172
     * @throws Exception
173
     */
174
    public function getMarkets()
175
    {
176
        $return = $this->request('v3/exchangeInfo');
177
        return $return['symbols'];
178
    }
179
180
    /**
181
     * Get current account information
182
     *
183
     * @return mixed
184
     * @throws Exception
185
     */
186
    public function getBalances()
187
    {
188
        $b = $this->privateRequest('v3/account');
189
        return $b['balances'];
190
    }
191
192
    /**
193
     * Make private requests (Security Type: TRADE, USER_DATA, USER_STREAM, MARKET_DATA)
194
     *
195
     * @param string $url URL Endpoint
196
     * @param array $params Required and optional parameters
197
     * @param string $method GET, POST, PUT, DELETE
198
     * @return mixed
199
     * @throws Exception
200
     */
201
    private function privateRequest($url, $params = [], $method = 'GET')
202
    {
203
        // build the POST data string
204
        $params['timestamp'] = number_format((microtime(true) * 1000), 0, '.', '');
205
        $params['recvWindow'] = $this->recvWindow;
206
207
        $query = http_build_query($params, '', '&');
208
209
        // set API key and sign the message
210
        $sign = hash_hmac('sha256', $query, $this->secret);
211
212
        $headers = array(
213
            'X-MBX-APIKEY: ' . $this->key
214
        );
215
216
        // make request
217
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers);
218
219
        // build the POST data string
220
        $postdata = $params;
0 ignored issues
show
The assignment to $postdata is dead and can be removed.
Loading history...
221
222
        // Set URL & Header
223
        curl_setopt($this->curl, CURLOPT_URL, $this->url . $url . "?{$query}&signature={$sign}");
224
225
        //Add post vars
226
        if ($method == "POST") {
227
            curl_setopt($this->curl, CURLOPT_POST, 1);
228
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, array());
229
        }
230
231
        //Get result
232
        $result = curl_exec($this->curl);
233
        if ($result === false)
234
            throw new Exception('CURL error: ' . curl_error($this->curl));
235
236
        // decode results
237
        $result = json_decode($result, true);
0 ignored issues
show
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

237
        $result = json_decode(/** @scrutinizer ignore-type */ $result, true);
Loading history...
238
        if (!is_array($result) || json_last_error())
239
            throw new Exception('JSON decode error');
240
241
        return $result;
242
243
    }
244
245
    /**
246
     * Get trades for a specific account and symbol
247
     *
248
     * @param string $symbol Currency pair
249
     * @param int $limit Limit of trades. Max. 500
250
     * @return mixed
251
     * @throws Exception
252
     */
253
    public function getRecentTrades($symbol = 'BNBBTC', $limit = 500)
254
    {
255
        $data = [
256
            'symbol' => $symbol,
257
            'limit' => $limit,
258
        ];
259
260
        $b = $this->privateRequest('v3/myTrades', $data);
261
        return $b;
262
263
    }
264
265
    public function getOpenOrders()
266
    {
267
        $b = $this->privateRequest('v3/openOrders');
268
        return $b;
269
    }
270
271
    public function getAllOrders($symbol)
272
    {
273
        $data = [
274
            'symbol' => $symbol
275
        ];
276
        $b = $this->privateRequest('v3/allOrders', $data);
277
        return $b;
278
    }
279
280
    /**
281
     * Sell at market price
282
     *
283
     * @param string $symbol Asset pair to trade
284
     * @param string $quantity Amount of trade asset
285
     * @return mixed
286
     * @throws Exception
287
     */
288
    public function marketSell($symbol, $quantity)
289
    {
290
        return $this->trade($symbol, $quantity, 'SELL', 'MARKET');
291
    }
292
293
    /**
294
     * Base trade function
295
     *
296
     * @param string $symbol Asset pair to trade
297
     * @param string $quantity Amount of trade asset
298
     * @param string $side BUY, SELL
299
     * @param string $type MARKET, LIMIT, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER
300
     * @param bool $price Limit price
301
     * @return mixed
302
     * @throws Exception
303
     */
304
    public function trade($symbol, $quantity, $side, $type = 'MARKET', $price = false)
305
    {
306
        $data = [
307
            'symbol' => $symbol,
308
            'side' => $side,
309
            'type' => $type,
310
            'quantity' => $quantity
311
        ];
312
        if ($price !== false) {
313
            $data['price'] = $price;
314
        }
315
316
        $b = $this->privateRequest('v3/order', $data, 'POST');
317
318
        return $b;
319
    }
320
321
    /**
322
     * Buy at market price
323
     *
324
     * @param string $symbol Asset pair to trade
325
     * @param string $quantity Amount of trade asset
326
     * @return mixed
327
     * @throws Exception
328
     */
329
    public function marketBuy($symbol, $quantity)
330
    {
331
        return $this->trade($symbol, $quantity, 'BUY', 'MARKET');
332
    }
333
334
    /**
335
     * Sell limit
336
     *
337
     * @param string $symbol Asset pair to trade
338
     * @param string $quantity Amount of trade asset
339
     * @param float $price Limit price to sell
340
     * @return mixed
341
     * @throws Exception
342
     */
343
    public function limitSell($symbol, $quantity, $price)
344
    {
345
        return $this->trade($symbol, $quantity, 'SELL', 'LIMIT', $price);
0 ignored issues
show
$price of type double is incompatible with the type boolean expected by parameter $price of sabramooz\binance\BinanceAPI::trade(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

345
        return $this->trade($symbol, $quantity, 'SELL', 'LIMIT', /** @scrutinizer ignore-type */ $price);
Loading history...
346
    }
347
348
    //------ REQUESTS FUNCTIONS ------
349
350
    /**
351
     * Buy limit
352
     *
353
     * @param string $symbol Asset pair to trade
354
     * @param string $quantity Amount of trade asset
355
     * @param float $price Limit price to buy
356
     * @return mixed
357
     * @throws Exception
358
     */
359
    public function limitBuy($symbol, $quantity, $price)
360
    {
361
        return $this->trade($symbol, $quantity, 'BUY', 'LIMIT', $price);
0 ignored issues
show
$price of type double is incompatible with the type boolean expected by parameter $price of sabramooz\binance\BinanceAPI::trade(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

361
        return $this->trade($symbol, $quantity, 'BUY', 'LIMIT', /** @scrutinizer ignore-type */ $price);
Loading history...
362
    }
363
364
    /**
365
     * Deposit Address
366
     * @param string $symbol Asset symbol
367
     * @return mixed
368
     *
369
     * @throws Exception
370
     */
371
    public function depositAddress($symbol)
372
    {
373
        return $this->wapiRequest("v3/depositAddress.html", ['asset' => $symbol]);
374
    }
375
376
    /**
377
     * Make wapi requests
378
     *
379
     * @param string $url URL Endpoint
380
     * @param array $params Required and optional parameters
381
     * @param string $method GET, POST, PUT, DELETE
382
     * @return mixed
383
     * @throws Exception
384
     */
385
    private function wapiRequest($url, $params = [], $method = 'GET')
386
    {
387
        // build the POST data string
388
        $params['timestamp'] = number_format((microtime(true) * 1000), 0, '.', '');
389
        $params['recvWindow'] = $this->recvWindow;
390
391
        $query = http_build_query($params, '', '&');
392
393
        // set API key and sign the message
394
        $sign = hash_hmac('sha256', $query, $this->secret);
395
396
        $headers = array(
397
            'X-MBX-APIKEY: ' . $this->key
398
        );
399
400
        // make request
401
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers);
402
403
        // build the POST data string
404
        $postdata = $params;
0 ignored issues
show
The assignment to $postdata is dead and can be removed.
Loading history...
405
406
        // Set URL & Header
407
        curl_setopt($this->curl, CURLOPT_URL, $this->wapi_url . $url . "?{$query}&signature={$sign}");
408
409
        //Add post vars
410
        if ($method == "POST") {
411
            curl_setopt($this->curl, CURLOPT_POST, 1);
412
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, array());
413
        }
414
415
        //Get result
416
        $result = curl_exec($this->curl);
417
        if ($result === false)
418
            throw new Exception('CURL error: ' . curl_error($this->curl));
419
420
        // decode results
421
        $result = json_decode($result, true);
0 ignored issues
show
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

421
        $result = json_decode(/** @scrutinizer ignore-type */ $result, true);
Loading history...
422
        if (!is_array($result) || json_last_error())
423
            throw new Exception('JSON decode error');
424
425
        return $result;
426
427
    }
428
429
}
430