File Coverage

blib/lib/Binance/API.pm
Criterion Covered Total %
statement 92 154 59.7
branch 29 50 58.0
condition 1 3 33.3
subroutine 22 34 64.7
pod 26 26 100.0
total 170 267 63.6


line stmt bran cond sub pod time code
1             package Binance::API;
2              
3             # MIT License
4             #
5             # Copyright (c) 2018
6             # Lari Taskula
7             # Filip La Gre
8             #
9             # Permission is hereby granted, free of charge, to any person obtaining a copy
10             # of this software and associated documentation files (the "Software"), to deal
11             # in the Software without restriction, including without limitation the rights
12             # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13             # copies of the Software, and to permit persons to whom the Software is
14             # furnished to do so, subject to the following conditions:
15             #
16             # The above copyright notice and this permission notice shall be included in all
17             # copies or substantial portions of the Software.
18             #
19             # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20             # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21             # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22             # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23             # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24             # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25             # SOFTWARE.
26              
27 2     2   90441 use strict;
  2         18  
  2         79  
28 2     2   13 use warnings;
  2         4  
  2         86  
29              
30 2     2   15 use Carp;
  2         4  
  2         135  
31 2     2   13 use Scalar::Util qw( blessed );
  2         5  
  2         117  
32              
33 2     2   1152 use Binance::API::Logger;
  2         7  
  2         77  
34 2     2   1174 use Binance::API::Request;
  2         11  
  2         97  
35              
36 2     2   966 use Binance::Exception::Parameter::BadValue;
  2         7  
  2         67  
37 2     2   14 use Binance::Exception::Parameter::Required;
  2         4  
  2         5224  
38              
39             our $VERSION = '1.08';
40              
41             =head1 NAME
42              
43             Binance::API -- Perl implementation for Binance API
44              
45             =head1 DESCRIPTION
46              
47             This module provides a Perl implementation for Binance API
48              
49             Binance API documentation: C.
50              
51             ENUM definitions:
52             https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#enum-definitions
53              
54             =head1 SYNOPSIS
55              
56             use Binance::API;
57              
58             my $api = Binance::API->new(
59             apiKey => 'my_api_key',
60             secretKey => 'my_secret_key',
61             );
62              
63             my $ticker = $api->ticker( symbol => 'ETHBTC' );
64              
65             =head1 METHODS
66              
67             =cut
68              
69             =head2 new
70              
71             my $api = Binance::API->new(
72             apiKey => 'my_api_key',
73             secretKey => 'my_secret_key',
74             );
75              
76             Instantiates a new C object
77              
78             B
79              
80             =over
81              
82             =item apiKey
83              
84             [OPTIONAL] Your Binance API key.
85              
86             =item secretKey
87              
88             [OPTIONAL] Your Binance API secret key.
89              
90             =item recvWindow
91              
92             [OPTIONAL] Number of milliseconds the request is valid for. Applies only in
93             signed requests.
94              
95             =item logger
96              
97             [OPTIONAL] See L
98              
99             =back
100              
101             B
102              
103             A C object.
104              
105             =cut
106              
107             sub new {
108 3     3 1 3214 my ($class, %params) = @_;
109              
110 3         21 my $logger = Binance::API::Logger->new($params{logger});
111              
112             my $ua = Binance::API::Request->new(
113             apiKey => $params{apiKey},
114             secretKey => $params{secretKey},
115             recvWindow => $params{recvWindow},
116 3         23 logger => $logger,
117             );
118              
119 3         12 my $self = {
120             ua => $ua,
121             logger => $logger,
122             };
123              
124 3         31 bless $self, $class;
125             }
126              
127             =head2 ping
128              
129             $api->ping();
130              
131             Test connectivity to the Rest API
132              
133             B
134              
135             =over
136              
137             =item Takes no parameters.
138              
139             =back
140              
141              
142             B
143             1 if successful, otherwise 0
144              
145             =cut
146              
147             sub ping {
148 1 50   1 1 6938 return keys %{$_[0]->ua->get('/api/v3/ping')} == 0 ? 1 : 0;
  1         6  
149             }
150              
151             =head2 time
152              
153             $api->time();
154              
155             Test connectivity to the Rest API and get the current server time.
156              
157             B
158              
159             =over
160              
161             =item Takes no parameters.
162              
163             =back
164              
165             B
166             Server (epoch) time in milliseconds
167              
168             =cut
169              
170             sub time {
171 1     1 1 3326 my $self = shift;
172              
173 1         5 my $time = $self->ua->get('/api/v3/time');
174 1 50       10 return exists $time->{serverTime} ? $time->{serverTime} : 0;
175             }
176              
177             =head2 exchange_info
178              
179             $api->exchange_info();
180              
181             Current exchange trading rules and symbol information.
182              
183             B
184              
185             =over
186              
187             =item Takes no parameters.
188              
189             =back
190              
191             B
192             A HASHref
193              
194             {
195             "timezone": "UTC",
196             "serverTime": 1508631584636,
197             "rateLimits": [{
198             "rateLimitType": "REQUESTS",
199             "interval": "MINUTE",
200             "limit": 1200
201             },
202             {
203             "rateLimitType": "ORDERS",
204             "interval": "SECOND",
205             "limit": 10
206             },
207             {
208             "rateLimitType": "ORDERS",
209             "interval": "DAY",
210             "limit": 100000
211             }
212             ],
213             "exchangeFilters": [],
214             "symbols": [{
215             "symbol": "ETHBTC",
216             "status": "TRADING",
217             "baseAsset": "ETH",
218             "baseAssetPrecision": 8,
219             "quoteAsset": "BTC",
220             "quotePrecision": 8,
221             "orderTypes": ["LIMIT", "MARKET"],
222             "icebergAllowed": false,
223             "filters": [{
224             "filterType": "PRICE_FILTER",
225             "minPrice": "0.00000100",
226             "maxPrice": "100000.00000000",
227             "tickSize": "0.00000100"
228             }, {
229             "filterType": "LOT_SIZE",
230             "minQty": "0.00100000",
231             "maxQty": "100000.00000000",
232             "stepSize": "0.00100000"
233             }, {
234             "filterType": "MIN_NOTIONAL",
235             "minNotional": "0.00100000"
236             }]
237             }]
238             }
239              
240             =cut
241              
242             sub exchange_info {
243 0     0 1 0 return $_[0]->ua->get('/api/v3/exchangeInfo');
244             }
245              
246             =head2 depth
247              
248             $api->depth( symbol => 'ETHBTC' );
249              
250             B
251              
252             =over
253              
254             =item symbol
255              
256             [REQUIRED] Symbol, for example C.
257              
258             =item limit
259              
260             [OPTIONAL] Default 100; max 5000. Valid limits: 5, 10, 20, 50, 100, 500, 1000, 5000.
261              
262             =back
263              
264             B
265             A HASHref
266              
267             {
268             "lastUpdateId": 1027024,
269             "bids": [
270             [
271             "4.00000000", // PRICE
272             "431.00000000", // QTY
273             [] // Can be ignored
274             ]
275             ],
276             "asks": [
277             [
278             "4.00000200",
279             "12.00000000",
280             []
281             ]
282             ]
283             }
284              
285             =cut
286              
287             sub depth {
288 2     2 1 5806 my ($self, %params) = @_;
289              
290 2 100       10 unless ($params{'symbol'}) {
291 1         5 $self->log->error('Parameter "symbol" required');
292 1         12 Binance::Exception::Parameter::Required->throw(
293             error => 'Parameter "symbol" required',
294             parameters => ['symbol']
295             );
296             }
297              
298             my $query = {
299             symbol => $params{'symbol'},
300 1         5 limit => $params{'limit'},
301             };
302              
303 1         4 return $self->ua->get('/api/v3/depth', { query => $query } );
304             }
305              
306             =head2 trades
307              
308             $api->trades();
309              
310             Get recent trades (up to last 1000).
311              
312             B
313              
314             =over
315              
316             =item symbol
317              
318             [REQUIRED] Symbol, for example C.
319              
320             =item limit
321              
322             [OPTIONAL] Default 500; max 1000.
323              
324             =back
325              
326             B
327             An ARRAYref of HASHrefs
328              
329             [
330             {
331             "id": 28457,
332             "price": "4.00000100",
333             "qty": "12.00000000",
334             "time": 1499865549590,
335             "isBuyerMaker": true,
336             "isBestMatch": true
337             }
338             ]
339              
340             =cut
341              
342             sub trades {
343 0     0 1 0 my ($self, %params) = @_;
344              
345 0 0       0 unless ($params{'symbol'}) {
346 0         0 $self->log->error('Parameter "symbol" required');
347 0         0 Binance::Exception::Parameter::Required->throw(
348             error => 'Parameter "symbol" required',
349             parameters => ['symbol']
350             );
351             }
352              
353             my $query = {
354             symbol => $params{'symbol'},
355 0         0 limit => $params{'limit'},
356             };
357              
358 0         0 return $self->ua->get('/api/v3/trades', { query => $query } );
359             }
360              
361             =head2 historical_trades
362              
363             $api->historical_trades();
364              
365             Get older trades.
366              
367             B
368              
369             =over
370              
371             =item symbol
372              
373             [REQUIRED] Symbol, for example C.
374              
375             =item limit
376              
377             [OPTIONAL] Default 500; max 1000.
378              
379             =item fromId
380              
381             [OPTIONAL] TradeId to fetch from. Default gets most recent trades.
382              
383             =back
384              
385             B
386             An ARRAYref of HASHrefs
387              
388             [
389             {
390             "id": 28457,
391             "price": "4.00000100",
392             "qty": "12.00000000",
393             "time": 1499865549590,
394             "isBuyerMaker": true,
395             "isBestMatch": true
396             }
397             ]
398              
399             =cut
400              
401             sub historical_trades {
402 0     0 1 0 my ($self, %params) = @_;
403              
404 0 0       0 unless ($params{'symbol'}) {
405 0         0 $self->log->error('Parameter "symbol" required');
406 0         0 Binance::Exception::Parameter::Required->throw(
407             error => 'Parameter "symbol" required',
408             parameters => ['symbol']
409             );
410             }
411              
412             my $query = {
413             symbol => $params{'symbol'},
414             limit => $params{'limit'},
415 0         0 fromId => $params{'fromId'},
416             };
417              
418 0         0 return $self->ua->get('/api/v3/historicalTrades', { query => $query } );
419             }
420              
421             =head2 aggregate_trades
422              
423             $api->aggregate_trades( symbol => 'ETHBTC' );
424              
425             Gets compressed, aggregate trades. Trades that fill at the time, from the same
426             order, with the same price will have the quantity aggregated.
427              
428             B
429              
430             =over
431              
432             =item symbol
433              
434             [REQUIRED] Symbol, for example C.
435              
436             =item fromId
437              
438             [OPTIONAL] ID to get aggregate trades from INCLUSIVE.
439              
440             =item startTime
441              
442             [OPTIONAL] timestamp in ms to get aggregate trades from INCLUSIVE.
443              
444             =item endTime
445              
446             [OPTIONAL] timestamp in ms to get aggregate trades until INCLUSIVE.
447              
448             =item limit
449              
450             [OPTIONAL] Default 500; max 1000.
451              
452             =back
453              
454             B
455             An ARRAYref of HASHrefs
456              
457             [
458             {
459             "a": 26129, // Aggregate tradeId
460             "p": "0.01633102", // Price
461             "q": "4.70443515", // Quantity
462             "f": 27781, // First tradeId
463             "l": 27781, // Last tradeId
464             "T": 1498793709153, // Timestamp
465             "m": true, // Was the buyer the maker?
466             "M": true // Was the trade the best price match?
467             }
468             ]
469              
470             =cut
471              
472             sub aggregate_trades {
473 2     2 1 5255 my ($self, %params) = @_;
474              
475 2 100       11 unless ($params{'symbol'}) {
476 1         5 $self->log->error('Parameter "symbol" required');
477 1         24 Binance::Exception::Parameter::Required->throw(
478             error => 'Parameter "symbol" required',
479             parameters => ['symbol']
480             );
481             }
482              
483             my $query = {
484             symbol => $params{'symbol'},
485             fromId => $params{'fromId'},
486             startTime => $params{'startTime'},
487             endTime => $params{'endTime'},
488 1         7 limit => $params{'limit'},
489             };
490              
491 1         5 return $self->ua->get('/api/v3/aggTrades', { query => $query } );
492             }
493              
494             =head2 klines
495              
496             $api->klines( symbol => 'ETHBTC', interval => '1M' );
497              
498             Kline/candlestick bars for a symbol. Klines are uniquely identified by their
499             open time.
500              
501             B
502              
503             =over
504              
505             =item symbol
506              
507             [REQUIRED] Symbol, for example C.
508              
509             =item interval
510              
511             [REQUIRED] ENUM (kline intervals), for example 1m, 1h, 1d or 1M.
512              
513             =item limit
514              
515             [OPTIONAL] Default 500; max 1000.
516              
517             =item startTime
518              
519             [OPTIONAL] timestamp in ms
520              
521             =item endTime
522              
523             [OPTIONAL] timestamp in ms
524              
525             =back
526              
527             B
528             An array of ARRAYrefs
529              
530             [
531             [
532             1499040000000, // Open time
533             "0.01634790", // Open
534             "0.80000000", // High
535             "0.01575800", // Low
536             "0.01577100", // Close
537             "148976.11427815", // Volume
538             1499644799999, // Close time
539             "2434.19055334", // Quote asset volume
540             308, // Number of trades
541             "1756.87402397", // Taker buy base asset volume
542             "28.46694368", // Taker buy quote asset volume
543             "17928899.62484339" // Can be ignored
544             ]
545             ]
546              
547             =cut
548              
549             sub klines {
550 4     4 1 11011 my ($self, %params) = @_;
551              
552 4 100       14 unless ($params{'symbol'}) {
553 2         6 $self->log->error('Parameter "symbol" required');
554 2         16 Binance::Exception::Parameter::Required->throw(
555             error => 'Parameter "symbol" required',
556             parameters => ['symbol']
557             );
558             }
559              
560 2 100       8 unless ($params{'interval'}) {
561 1         3 $self->log->error('Parameter "interval" required');
562 1         7 Binance::Exception::Parameter::Required->throw(
563             error => 'Parameter "interval" required',
564             parameters => ['interval']
565             );
566             }
567              
568             my $query = {
569             symbol => $params{'symbol'},
570             interval => $params{'interval'},
571             startTime => $params{'startTime'},
572             endTime => $params{'endTime'},
573 1         6 limit => $params{'limit'},
574             };
575              
576 1         4 return $self->ua->get('/api/v3/klines', { query => $query } );
577             }
578              
579             =head2 ticker
580              
581             $api->ticker( symbol => 'ETHBTC', interval => '1M' );
582              
583             24 hour price change statistics.
584              
585             B
586              
587             =over
588              
589             =item symbol
590              
591             [OPTIONAL] Symbol, for example C.
592             Warning: Careful when accessing this with no symbol.
593              
594             =back
595              
596             B
597             A HASHref or an Array of HASHrefs if no symbol given
598              
599             {
600             "priceChange": "-94.99999800",
601             "priceChangePercent": "-95.960",
602             "weightedAvgPrice": "0.29628482",
603             "prevClosePrice": "0.10002000",
604             "lastPrice": "4.00000200",
605             "bidPrice": "4.00000000",
606             "askPrice": "4.00000200",
607             "openPrice": "99.00000000",
608             "highPrice": "100.00000000",
609             "lowPrice": "0.10000000",
610             "volume": "8913.30000000",
611             "openTime": 1499783499040,
612             "closeTime": 1499869899040,
613             "fristId": 28385, // First tradeId
614             "lastId": 28460, // Last tradeId
615             "count": 76 // Trade count
616             }
617              
618             =cut
619              
620             sub ticker {
621 1     1 1 2169 my ($self, %params) = @_;
622              
623             my $query = {
624 1         5 symbol => $params{'symbol'},
625             };
626              
627 1         3 return $self->ua->get('/api/v3/ticker/24hr', { query => $query } );
628             }
629              
630             =head2 ticker_price
631              
632             $api->ticker_price();
633              
634             Latest price for a symbol or symbols.
635              
636             B
637              
638             =over
639              
640             =item symbol
641              
642             [OPTIONAL] Symbol, for example C. If not given, returns prices of all
643             symbols.
644              
645             =back
646              
647             B
648             A HASHref
649              
650             {
651             "symbol": "LTCBTC",
652             "price": "4.00000200"
653             }
654              
655             OR an ARRAY of HASHrefs
656              
657             [
658             {
659             "symbol": "LTCBTC",
660             "price": "4.00000200"
661             },
662             {
663             "symbol": "ETHBTC",
664             "price": "0.07946600"
665             }
666             ]
667              
668             =cut
669              
670             sub ticker_price {
671 2     2 1 4773 my ($self, %params) = @_;
672              
673             my $query = {
674 2         7 symbol => $params{'symbol'},
675             };
676              
677 2         5 return $self->ua->get('/api/v3/ticker/price', { query => $query } );
678             }
679              
680             =head2 book_ticker
681              
682             $api->book_ticker();
683              
684             Best price/qty on the order book for all symbols.
685              
686             B
687              
688             =over
689              
690             =item symbol
691              
692             [OPTIONAL] Symbol, for example C. If not given, returns best price/qty of all
693             symbols.
694              
695             =back
696              
697             B
698              
699             A HASHref
700             {
701             "symbol": "LTCBTC",
702             "bidPrice": "4.00000000",
703             "bidQty": "431.00000000",
704             "askPrice": "4.00000200",
705             "askQty": "9.00000000"
706             }
707              
708             OR an ARRAY of HASHrefs
709              
710             [
711             {
712             "symbol": "LTCBTC",
713             "bidPrice": "4.00000000",
714             "bidQty": "431.00000000",
715             "askPrice": "4.00000200",
716             "askQty": "9.00000000"
717             },
718             {
719             "symbol": "ETHBTC",
720             "bidPrice": "0.07946700",
721             "bidQty": "9.00000000",
722             "askPrice": "100000.00000000",
723             "askQty": "1000.00000000"
724             }
725             ]
726              
727             =cut
728              
729             sub book_ticker {
730 1     1 1 3 my ($self, %params) = @_;
731              
732             my $query = {
733 1         3 symbol => $params{'symbol'},
734             };
735              
736 1         5 return $_[0]->ua->get('/api/v3/ticker/bookTicker', { query => $query } );
737             }
738              
739             =head2 all_book_tickers
740              
741             $api->all_book_tickers();
742              
743             DEPRECATED: use book_ticker instead.
744              
745             =cut
746              
747             sub all_book_tickers {
748 1     1 1 3702 my $self = shift;
749              
750 1         6 return $self->book_ticker(@_);
751             }
752              
753             =head2 order
754              
755             $api->order(
756             symbol => 'ETHBTC',
757             side => 'BUY',
758             type => 'LIMIT',
759             timeInForce => 'GTC',
760             quantity => 1
761             price => 0.1
762             );
763              
764             Send in a new order.
765              
766             B
767              
768             =over
769              
770             =item symbol
771              
772             [REQUIRED] Symbol, for example C.
773              
774             =item side
775              
776             [REQUIRED] BUY or SELL.
777              
778             =item type
779              
780             [REQUIRED] LIMIT|STOP_LOSS|STOP_LOSS_LIMIT|TAKE_PROFIT|TAKE_PROFIT_LIMIT|LIMIT_MAKER|MARKET.
781              
782             =item timeInForce
783              
784             [OPTIONAL] GTC or IOC.
785              
786             =item quantity
787              
788             [OPTIONAL] Quantity (of symbols) in order.
789              
790             =item quoteOrderQty
791              
792             [OPTIONAL] MARKET orders using quoteOrderQty specifies the amount the user wants
793             to spend (when buying) or receive (when selling) the quote asset; the correct
794             quantity will be determined based on the market liquidity and quoteOrderQty.
795              
796             E.g. Using the symbol BTCUSDT:
797             BUY side, the order will buy as many BTC as quoteOrderQty USDT can.
798             SELL side, the order will sell as much BTC needed to receive quoteOrderQty USDT.
799              
800             =item price
801              
802             [OPTIONAL] Price (of symbol) in order.
803              
804             =item newClientOrderId
805              
806             [OPTIONAL] A unique id for the order. Automatically generated
807             if not sent.
808              
809             =item stopPrice
810              
811             [OPTIONAL] Used with stop orders.
812              
813             =item icebergQty
814              
815             [OPTIONAL] Used with iceberg orders.
816              
817             =item newOrderRespType
818              
819             [OPTIONAL] Set the response JSON. ACK, RESULT, or FULL; MARKET and LIMIT order
820             types default to FULL, all other orders default to ACK.
821              
822             =item test
823              
824             [OPTIONAL] Test new order creation and signature/recvWindow long. Creates and
825             validates a new order but does not send it into the matching engine.
826              
827             =back
828              
829             B
830             A HASHref
831              
832             {
833             "symbol":"LTCBTC",
834             "orderId": 1,
835             "clientOrderId": "myOrder1" // Will be newClientOrderId
836             "transactTime": 1499827319559
837             }
838              
839             =cut
840              
841             sub order {
842 32     32 1 88 my ($self, %params) = @_;
843              
844 32 100       88 unless (defined $params{'type'}) {
845 1         4 $self->log->error('Parameter "type" required');
846 1         7 Binance::Exception::Parameter::Required->throw(
847             error => 'Parameter "type" required',
848             parameters => ['type']
849             );
850             }
851              
852 31         63 my @required = (
853             'symbol', 'side',
854             );
855              
856 31 100       145 if ($params{'type'} eq 'LIMIT') {
    100          
    100          
    100          
    100          
    100          
    100          
857 5         11 push @required, ('timeInForce', 'quantity', 'price');
858             }
859             elsif ($params{'type'} eq 'STOP_LOSS') {
860 4         9 push @required, ('quantity', 'stopPrice');
861             }
862             elsif ($params{'type'} eq 'STOP_LOSS_LIMIT') {
863 6         14 push @required, ('timeInForce', 'quantity', 'price', 'stopPrice');
864             }
865             elsif ($params{'type'} eq 'TAKE_PROFIT') {
866 4         7 push @required, ('quantity', 'stopPrice');
867             }
868             elsif ($params{'type'} eq 'TAKE_PROFIT_LIMIT') {
869 6         16 push @required, ('timeInForce', 'quantity', 'price', 'stopPrice');
870             }
871             elsif ($params{'type'} eq 'LIMIT_MAKER') {
872 4         10 push @required, ('quantity', 'price');
873             }
874             elsif ($params{'type'} eq 'MARKET') {
875 1 50 33     8 if (!defined $params{'quantity'} && !defined $params{'quoteOrderQty'}) {
876 1         4 $self->log->error('One of parameters "quantity" or "quoteOrderQty" is required');
877 1         9 Binance::Exception::Parameter::Required->throw(
878             error => 'One of parameters "quantity" or "quoteOrderQty" is required',
879             parameters => ["quantity", "quoteOrderQty"]
880             );
881             }
882             } else {
883 1         4 $self->log->error('Invalid value for parameter "type"');
884 1         17 Binance::Exception::Parameter::BadValue->throw(
885             error => 'Invalid value for parameter "type"',
886             parameters => ["type"],
887             format => '(LIMIT|STOP_LOSS|STOP_LOSS_LIMIT|TAKE_PROFIT|TAKE_PROFIT_LIMIT|LIMIT_MAKER|MARKET)'
888             );
889             }
890              
891 29         50 foreach my $param (@required) {
892 87 100       174 unless (defined ($params{$param})) {
893 29         58 $self->log->error('Parameter "'.$param.'" required');
894 29         232 Binance::Exception::Parameter::Required->throw(
895             error => 'Parameter "'.$param.'" required',
896             parameters => [$param]
897             );
898             }
899             }
900              
901             my $body = {
902             symbol => $params{'symbol'},
903             side => $params{'side'},
904             type => $params{'type'},
905             timeInForce => $params{'timeInForce'},
906             quantity => $params{'quantity'},
907             quoteOrderQty => $params{'quoteOrderQty'},
908             price => $params{'price'},
909             newClientOrderId => $params{'newClientOrderId'},
910             stopPrice => $params{'stopPrice'},
911             icebergQty => $params{'icebergQty'},
912 0         0 newOrderRespType => $params{'newOrderRespType'},
913             };
914              
915             # Enable dry mode
916 0         0 my $url = '/api/v3/order';
917              
918 0 0       0 if ($params{'test'}) {
919 0         0 $self->{logger}->debug('Test flag enabled - using order_test() instead of order()');
920 0         0 $url .= '/test'
921             }
922              
923 0         0 return $self->ua->post($url, { signed => 1, body => $body } );
924             }
925              
926             =head2 order_test
927              
928             $api->order_test();
929              
930             Test new order creation and signature/recvWindow long. Creates and validates
931             a new order but does not send it into the matching engine.
932              
933             B
934              
935             Same as C.
936              
937             B
938             An empty HASHref
939              
940             {}
941              
942             =cut
943              
944             sub order_test {
945 32     32 1 97105 my ($self, %params) = @_;
946              
947 32         73 $params{'test'} = 1;
948              
949 32         101 return $self->order(%params);
950             }
951              
952             =head2 cancel_order
953              
954             $api->cancel_order();
955              
956             Cancel an active order.
957              
958             B
959              
960             =over
961              
962             =item symbol
963              
964             [REQUIRED] Symbol, for example C.
965              
966             =item orderId
967              
968             [OPTIONAL]
969              
970             =item origClientOrderId
971              
972             [OPTIONAL]
973              
974             =item newClientOrderId
975              
976             [OPTIONAL] Used to uniquely identify this cancel.
977             Automatically generated by default.
978              
979             =item recvWindow
980              
981             [OPTIONAL]
982              
983             =back
984              
985             B
986             A HASHref
987              
988             {
989             "symbol": "LTCBTC",
990             "origClientOrderId": "myOrder1",
991             "orderId": 1,
992             "clientOrderId": "cancelMyOrder1"
993             }
994              
995             =cut
996              
997             sub cancel_order {
998 0     0 1 0 my ($self, %params) = @_;
999              
1000 0 0       0 unless ($params{'symbol'}) {
1001 0         0 $self->log->error('Parameter "symbol" required');
1002 0         0 Binance::Exception::Parameter::Required->throw(
1003             error => 'Parameter "symbol" required',
1004             parameters => ['symbol']
1005             );
1006             }
1007              
1008             my $body = {
1009             symbol => $params{'symbol'},
1010             orderId => $params{'orderId'},
1011             origClientOrderId => $params{'origClientOrderId'},
1012             newClientOrderId => $params{'newClientOrderId'},
1013 0         0 recvWindow => $params{'recvWindow'},
1014             };
1015              
1016 0         0 return $self->ua->delete('/api/v3/order', { signed => 1, body => $body } );
1017             }
1018              
1019             =head2 cancel_open_orders
1020              
1021             $api->cancel_open_orders( symbol => 'ETHBTC' );
1022              
1023             Cancel all active orders for a given symbol.
1024              
1025             B
1026              
1027             =over
1028              
1029             =item symbol
1030              
1031             [REQUIRED] Symbol, for example C.
1032              
1033             =item recvWindow
1034              
1035             [OPTIONAL]
1036              
1037             =back
1038              
1039             B
1040             An ARRAYref of HASHrefs
1041              
1042             [
1043             {
1044             "symbol": "ETHBTC",
1045             "origClientOrderId": "myOrder1",
1046             "orderId": 1,
1047             "clientOrderId": "cancelMyOrder1"
1048             }
1049             ]
1050              
1051             =cut
1052              
1053             sub cancel_open_orders {
1054 0     0 1 0 my ($self, %params) = @_;
1055              
1056 0 0       0 unless ($params{'symbol'}) {
1057 0         0 $self->log->error('Parameter "symbol" required');
1058 0         0 Binance::Exception::Parameter::Required->throw(
1059             error => 'Parameter "symbol" required',
1060             parameters => ['symbol']
1061             );
1062             }
1063              
1064             my $body = {
1065             symbol => $params{'symbol'},
1066 0         0 recvWindow => $params{'recvWindow'},
1067             };
1068              
1069 0         0 return $self->ua->delete('/api/v3/openOrders', { signed => 1, body => $body } );
1070             }
1071              
1072             =head2 open_orders
1073              
1074             $api->open_orders();
1075              
1076             Get all open orders on a symbol. Careful when accessing this with no symbol.
1077              
1078             B
1079              
1080             =over
1081              
1082             =item symbol
1083              
1084             OPTIONAL] Symbol, for example C.
1085              
1086             =item recvWindow
1087              
1088             [OPTIONAL]
1089              
1090             =back
1091              
1092             B
1093             An ARRAYref of HASHrefs
1094              
1095             [
1096             {
1097             "symbol": "LTCBTC",
1098             "orderId": 1,
1099             "clientOrderId": "myOrder1",
1100             "price": "0.1",
1101             "origQty": "1.0",
1102             "executedQty": "0.0",
1103             "status": "NEW",
1104             "timeInForce": "GTC",
1105             "type": "LIMIT",
1106             "side": "BUY",
1107             "stopPrice": "0.0",
1108             "icebergQty": "0.0",
1109             "time": 1499827319559,
1110             "isWorking": trueO
1111             }
1112             ]
1113              
1114             =cut
1115              
1116             sub open_orders {
1117 0     0 1 0 my ($self, %params) = @_;
1118              
1119             my $query = {
1120             symbol => $params{'symbol'},
1121 0         0 recvWindow => $params{'recvWindow'},
1122             };
1123 0         0 return $self->ua->get(
1124             '/api/v3/openOrders', { signed => 1, query => $query }
1125             );
1126             }
1127              
1128             =head2 all_orders
1129              
1130             $api->all_orders();
1131              
1132             Get all account orders; active, canceled, or filled.
1133              
1134             B
1135              
1136             =over
1137              
1138             =item symbol
1139              
1140             [REQUIRED] Symbol, for example C.
1141              
1142             =item orderId
1143              
1144             [OPTIONAL]
1145              
1146             =item startTime
1147              
1148             [OPTIONAL] Start time
1149              
1150             =item endTime
1151              
1152             [OPTIONAL] End time
1153              
1154             =item limit
1155              
1156             [OPTIONAL] Default 500; max 1000.
1157              
1158             =item recvWindow
1159              
1160             [OPTIONAL] The value cannot be greater than 60000.
1161              
1162             =back
1163              
1164             B
1165             An ARRAYref of HASHrefs
1166              
1167             [
1168             {
1169             "symbol": "LTCBTC",
1170             "orderId": 1,
1171             "clientOrderId": "myOrder1",
1172             "price": "0.1",
1173             "origQty": "1.0",
1174             "executedQty": "0.0",
1175             "status": "NEW",
1176             "timeInForce": "GTC",
1177             "type": "LIMIT",
1178             "side": "BUY",
1179             "stopPrice": "0.0",
1180             "icebergQty": "0.0",
1181             "time": 1499827319559,
1182             "isWorking": true
1183             }
1184             ]
1185              
1186             =cut
1187              
1188             sub all_orders {
1189 0     0 1 0 my ($self, %params) = @_;
1190 0 0       0 unless ($params{'symbol'}) {
1191 0         0 $self->log->error('Parameter "symbol" required');
1192 0         0 Binance::Exception::Parameter::Required->throw(
1193             error => 'Parameter "symbol" required',
1194             parameters => ['symbol']
1195             );
1196             }
1197             my $query = {
1198             symbol => $params{'symbol'},
1199             orderId => $params{'orderId'},
1200             startTime => $params{'startTime'},
1201             endTime => $params{'endTime'},
1202             limit => $params{'limit'},
1203 0         0 recvWindow => $params{'recvWindow'},
1204             };
1205 0         0 return $self->ua->get('/api/v3/allOrders',
1206             { signed => 1, query => $query }
1207             );
1208             }
1209              
1210             =head2 account
1211              
1212             $api->account();
1213              
1214             Get current account information.
1215              
1216             B
1217              
1218             =over
1219              
1220             =item recvWindow
1221              
1222             [OPTIONAL]
1223              
1224             =back
1225              
1226             B
1227             A HASHref
1228              
1229             {
1230             "makerCommission": 15,
1231             "takerCommission": 15,
1232             "buyerCommission": 0,
1233             "sellerCommission": 0,
1234             "canTrade": true,
1235             "canWithdraw": true,
1236             "canDeposit": true,
1237             "updateTime": 123456789,
1238             "balances": [
1239             {
1240             "asset": "BTC",
1241             "free": "4723846.89208129",
1242             "locked": "0.00000000"
1243             },
1244             {
1245             "asset": "LTC",
1246             "free": "4763368.68006011",
1247             "locked": "0.00000000"
1248             }
1249             ]
1250             }
1251              
1252             =cut
1253              
1254             sub account {
1255 0     0 1 0 my ($self, %params) = @_;
1256              
1257             my $query = {
1258 0         0 recvWindow => $params{'recvWindow'},
1259             };
1260 0         0 return $self->ua->get('/api/v3/account', { signed => 1, query => $query } );
1261             }
1262              
1263             =head2 my_trades
1264              
1265             $api->my_trades();
1266              
1267             Get trades for a specific account and symbol.
1268              
1269             B
1270              
1271             =over
1272              
1273             =item symbol
1274              
1275             [REQUIRED] Symbol, for example C.
1276              
1277             =item limit
1278              
1279             [OPTIONAL] Default 500; max 500.
1280              
1281             =item fromId
1282              
1283             [OPTIONAL] TradeId to fetch from. Default gets most recent
1284             trades.
1285              
1286             =item recvWindow
1287              
1288             [OPTIONAL]
1289              
1290             =back
1291              
1292             B
1293             An ARRAYref of HASHrefs
1294              
1295             [
1296             {
1297             "id": 28457,
1298             "orderId": 100234,
1299             "price": "4.00000100",
1300             "qty": "12.00000000",
1301             "commission": "10.10000000",
1302             "commissionAsset": "BNB",
1303             "time": 1499865549590,
1304             "isBuyer": true,
1305             "isMaker": false,
1306             "isBestMatch": true
1307             }
1308             ]
1309              
1310             =cut
1311              
1312             sub my_trades {
1313 0     0 1 0 my ($self, %params) = @_;
1314 0 0       0 unless ($params{'symbol'}) {
1315 0         0 $self->log->error('Parameter "symbol" required');
1316 0         0 Binance::Exception::Parameter::Required->throw(
1317             error => 'Parameter "symbol" required',
1318             parameters => ['symbol']
1319             );
1320             }
1321             my $query = {
1322             symbol => $params{'symbol'},
1323             limit => $params{'limit'},
1324             fromId => $params{'fromId'},
1325 0         0 recvWindow => $params{'recvWindow'},
1326             };
1327 0         0 return $self->ua->get(
1328             '/api/v3/myTrades', { signed => 1, query => $query }
1329             );
1330             }
1331              
1332             =head2 start_user_data_stream
1333              
1334             $api->start_user_data_stream();
1335              
1336             Start a new user data stream. The stream will close after 60 minutes unless
1337             a keepalive is sent.
1338              
1339             B
1340              
1341             =over
1342              
1343             =item Takes no parameters.
1344              
1345             =back
1346              
1347             B
1348             A HASHref
1349              
1350             {
1351             "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1"
1352             }
1353              
1354             =cut
1355              
1356             sub start_user_data_stream {
1357 0     0 1 0 return $_[0]->ua->post('/api/v3/userDataStream');
1358             }
1359              
1360             =head2 keep_alive_user_data_stream
1361              
1362             $api->keep_alive_user_data_stream();
1363              
1364             Keepalive a user data stream to prevent a time out. User data streams will close
1365             after 60 minutes. It's recommended to send a ping about every 30 minutes.
1366              
1367             B
1368              
1369             =over
1370              
1371             =item listenKey
1372              
1373             [REQUIRED]
1374              
1375             =back
1376              
1377             B
1378             An empty HASHref
1379              
1380             {}
1381              
1382             =cut
1383              
1384             sub keep_alive_user_data_stream {
1385 0     0 1 0 my ($self, %params) = @_;
1386 0 0       0 unless ($params{'listenKey'}) {
1387 0         0 $self->log->error('Parameter "listenKey" required');
1388 0         0 Binance::Exception::Parameter::Required->throw(
1389             error => 'Parameter "listenKey" required',
1390             parameters => ['listenKey']
1391             );
1392             }
1393             my $query = {
1394 0         0 listenKey => $params{'listenKey'},
1395             };
1396 0         0 return $self->ua->put('/api/v3/userDataStream', { query => $query } );
1397             }
1398              
1399             =head2 delete_user_data_stream
1400              
1401             $api->delete_user_data_stream();
1402              
1403             Close out a user data stream.
1404              
1405             B
1406              
1407             =over
1408              
1409             =item listenKey
1410              
1411             [REQUIRED]
1412              
1413             =back
1414              
1415             B
1416             An empty HASHref
1417              
1418             {}
1419              
1420             =cut
1421              
1422             sub delete_user_data_stream {
1423 0     0 1 0 my ($self, %params) = @_;
1424 0 0       0 unless ($params{'listenKey'}) {
1425 0         0 $self->log->error('Parameter "listenKey" required');
1426 0         0 Binance::Exception::Parameter::Required->throw(
1427             error => 'Parameter "listenKey" required',
1428             parameters => ['listenKey']
1429             );
1430             }
1431             my $query = {
1432 0         0 listenKey => $params{'listenKey'},
1433             };
1434 0         0 return $self->ua->delete('/api/v3/userDataStream', { query => $query } );
1435             }
1436              
1437             =head2 log
1438              
1439             $api->log->warn("This is a warning");
1440              
1441             B
1442              
1443             =over
1444              
1445             =item Takes no parameters.
1446              
1447             =back
1448              
1449             B
1450              
1451             An instance of L.
1452              
1453             =cut
1454              
1455 37     37 1 322 sub log { return $_[0]->{logger}; }
1456              
1457             =head2 ua
1458              
1459             $api->ua->get('/binance/endpoint');
1460              
1461             B
1462              
1463             =over
1464              
1465             =item Takes no parameters.
1466              
1467             =back
1468              
1469             B
1470              
1471             An instance of L.
1472              
1473             =cut
1474              
1475 9     9 1 49 sub ua { return $_[0]->{ua}; }
1476              
1477             1;