Issues (11)

src/BinanceAPI.php (4 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()
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)
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);
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);
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;
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);
422
        if (!is_array($result) || json_last_error())
423
            throw new Exception('JSON decode error');
424
425
        return $result;
426
427
    }
428
429
}
430