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
![]() |
|||||
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
![]() |
|||||
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
|
|||||
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
![]() |
|||||
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 |