GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 14c51d...7da3cf )
by Grisha
02:49
created

TradingApi::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of Poloniex PHP SDK.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @copyright 2017-2018 Chasovskih Grisha <[email protected]>
9
 * @license https://github.com/signulls/poloniex-php-sdk/blob/master/LICENSE MIT
10
 */
11
12
namespace Poloniex\Api;
13
14
use function is_array;
15
use GuzzleHttp\RequestOptions;
16
use Poloniex\{ApiKey, Exception\TotalDeficiencyException, Response\SampleResponse};
17
use Poloniex\Request\{CreateLoanOfferRequest, MoveOrderRequest, TradeRequest};
18
use Poloniex\Response\TradingApi\{
19
    AvailableAccountBalances,
20
    Balance,
21
    MoveOrder,
22
    TradeResult,
23
    CompleteBalance,
24
    DepositAddresses,
25
    DepositsWithdrawals,
26
    FeeInfo,
27
    ActiveLoans,
28
    CreateLoanOffer,
29
    LandingHistory,
30
    Loan,
31
    CloseMarginPosition,
32
    MarginPosition,
33
    MarginAccountSummary,
34
    MarginTrade,
35
    NewAddress,
36
    OpenOrder,
37
    OrderTrade,
38
    ResultingTrade,
39
    TradeHistory
40
};
41
42
/**
43
 * All calls to the trading API are sent via HTTP POST to https://poloniex.com/tradingApi and
44
 * must contain the following headers:
45
 *
46
 *  Key - Your API key.
47
 *  Sign - The query's POST data signed by your key's "secret" according to the HMAC-SHA512 method.
48
 *
49
 * Additionally, all queries must include a "nonce" POST parameter. The nonce parameter is an integer
50
 * which must always be greater than the previous nonce used.
51
 *
52
 * There are several methods accepted by the trading API, each of which is specified by the "command" POST parameter.
53
 *
54
 * @author Grisha Chasovskih <[email protected]>
55
 */
56
class TradingApi extends AbstractApi
57
{
58
    /**
59
     * @var ApiKey
60
     */
61
    private $apiKey;
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function request(string $command, array $params = []): array
67
    {
68
        $this->throwExceptionIf($this->apiKey === null, 'You need to set ApiKey to make trade request');
69
        $params = array_merge($params, ['nonce' => $this->getNonce(), 'command' => $command]);
70
        $data = http_build_query($params, '', '&');
71
72
        $this->options = [
73
            RequestOptions::FORM_PARAMS => $params,
74
            RequestOptions::HEADERS     => [
75
                'Key'          => $this->apiKey->getApiKey(),
76
                'Sign'         => hash_hmac('sha512', $data, $this->apiKey->getSecret()),
77
                'Content-Type' => 'application/x-www-form-urlencoded',
78
            ],
79
        ];
80
81
        $response = parent::request($command, $params);
82
        $this->apiKey = null;
83
84
        return $response;
85
    }
86
87
    /**
88
     * Set Api key
89
     *
90
     * @param ApiKey $apiKey
91
     *
92
     * @return TradingApi
93
     */
94
    public function setApiKey(ApiKey $apiKey): self
95
    {
96
        $this->apiKey = $apiKey;
97
98
        return $this;
99
    }
100
101
    /**
102
     * Returns all of your available balances.
103
     *
104
     * @return Balance
105
     */
106
    public function returnBalances(): Balance
107
    {
108
        $balance = new Balance();
109
        foreach ($this->request('returnBalances') as $currency => $value) {
110
            $balance->currencies[$currency] = $value;
111
        }
112
113
        return $balance;
114
    }
115
116
    /**
117
     * Returns all of your balances, including available balance, balance on orders, and the
118
     * estimated BTC value of your balance. By default, this call is limited to your exchange
119
     * account; set the "account" POST parameter to "all" to include your margin and lending accounts.
120
     *
121
     * Array keys are 3-digit coin codes
122
     *
123
     * @param  string $account
124
     * @return CompleteBalance[]
125
     */
126
    public function returnCompleteBalances(string $account = null): array
127
    {
128
        $balances = [];
129
        foreach ($this->request('returnCompleteBalances', compact('account')) as $coin => $balance) {
130
            $balances[$coin] = $this->factory(CompleteBalance::class, $balance);
131
        }
132
133
        return $balances;
134
    }
135
136
    /**
137
     * Returns all of your deposit addresses.
138
     *
139
     * @return DepositAddresses
140
     */
141
    public function returnDepositAddresses(): DepositAddresses
142
    {
143
        $depositAddresses = new DepositAddresses();
144
        foreach ($this->request('returnDepositAddresses') as $coin => $address) {
145
            $depositAddresses->addresses[$coin] = $address;
146
        }
147
148
        return $depositAddresses;
149
    }
150
151
    /**
152
     * Generates a new deposit address for the currency specified by the "currency" POST parameter.
153
     * Only one address per currency per day may be generated, and a new address may not be generated
154
     * before the previously-generated one has been used.
155
     *
156
     * @param string $currency 3-digit currency code
157
     *
158
     * @return NewAddress
159
     */
160
    public function generateNewAddress(string $currency): NewAddress
161
    {
162
        /* @var $newAddress NewAddress */
163
        $newAddress = $this->factory(
164
            NewAddress::class,
165
            $this->request('generateNewAddress', compact('currency'))
166
        );
167
168
        return $newAddress;
169
    }
170
171
    /**
172
     * Returns your deposit and withdrawal history within a range, specified by the "start" and "end" POST parameters,
173
     * both of which should be given as UNIX timestamps.
174
     *
175
     * @param int $start UNIX timestamps
176
     * @param int $end UNIX timestamps
177
     *
178
     * @return DepositsWithdrawals
179
     */
180
    public function returnDepositsWithdrawals(int $start, int $end): DepositsWithdrawals
181
    {
182
        /** @var $depositsWithdrawals DepositsWithdrawals*/
183
        $depositsWithdrawals = $this->factory(
184
            DepositsWithdrawals::class,
185
            $this->request('returnDepositsWithdrawals', compact('start', 'end'))
186
        );
187
188
        return $depositsWithdrawals;
189
    }
190
191
    /**
192
     * Returns your open orders for a given market.
193
     *
194
     * @param string $currencyPair
195
     * @return OpenOrder[]
196
     */
197
    public function returnOpenOrders(string $currencyPair): array
198
    {
199
        $this->throwExceptionIf($currencyPair === 'all', 'Please use TradingApi::returnAllOpenOrders() method');
200
201
        $openOrders = [];
202
        foreach ($this->request('returnOpenOrders', compact('currencyPair')) as $openOrder) {
203
            $openOrders[] = $this->factory(OpenOrder::class, $openOrder);
204
        }
205
206
        return $openOrders ?? [];
207
    }
208
209
    /**
210
     * Return open orders for all markets.
211
     *
212
     * OpenOrder[][]
213
     */
214
    public function returnAllOpenOrders(): array
215
    {
216
        foreach ($this->request('returnOpenOrders', ['currencyPair' => 'all']) as $pair => $orders) {
217
            if (is_array($orders)) {
218
                foreach ($orders as $openOrder) {
219
                    $openOrders[$pair][] = $this->factory(OpenOrder::class, $openOrder);
220
                }
221
            }
222
        }
223
224
        return $openOrders ?? [];
225
    }
226
227
    /**
228
     * Returns your trade history for a given market, specified by the "currencyPair" POST parameter.
229
     *
230
     * You may optionally specify a range via "start" and/or "end" POST parameters, given in UNIX timestamp format;
231
     * if you do not specify a range, it will be limited to one day. You may optionally limit the number of entries
232
     * returned using the "limit" parameter, up to a maximum of 10,000. If the "limit" parameter is not specified,
233
     * no more than 500 entries will be returned.
234
     *
235
     * @param string $currencyPair
236
     * @param int|null $start UNIX timestamp format
237
     * @param int|null $end UNIX timestamp format
238
     * @param int|null $limit
239
     *
240
     * @return TradeHistory[]
241
     */
242
    public function returnTradeHistory(
243
        string $currencyPair,
244
        int $start = null,
245
        int $end = null,
246
        int $limit = null
247
    ): array {
248
249
        $this->throwExceptionIf($currencyPair === 'all', 'Please use TradingApi::returnAllTradeHistory() method');
250
251
        foreach ($this->request('returnTradeHistory', compact('currencyPair', 'start', 'end', 'limit')) as $history) {
252
            $tradeHistory[] = $this->factory(TradeHistory::class, $history);
253
        }
254
255
        return $tradeHistory ?? [];
256
    }
257
258
    /**
259
     * Receive your trade history for all markets.
260
     * NOTE: Keys of response is currency pair codes like 'BTC_MAID'
261
     *
262
     * @param int|null $start
263
     * @param int|null $end
264
     * @param int|null $limit
265
     *
266
     * @return TradeHistory[][]
267
     */
268
    public function returnAllTradeHistory(
269
        int $start = null,
270
        int $end = null,
271
        int $limit = null
272
    ): array {
273
274
        $tradeHistory = [];
275
        $currencyPair = 'all';
276
        $response = $this->request('returnTradeHistory', compact('currencyPair', 'start', 'end', 'limit'));
277
278
        foreach ($response as $pair => $histories) {
279
            if (is_array($histories) && !empty($histories)) {
280
                foreach ($histories as $history) {
281
                    $tradeHistory[$pair][] = $this->factory(TradeHistory::class, $history);
282
                }
283
            }
284
        }
285
286
        return $tradeHistory;
287
    }
288
289
    /**
290
     * Returns all trades involving a given order, specified by the "orderNumber" POST parameter.
291
     * If no trades for the order have occurred or you specify an order that does
292
     * not belong to you, you will receive an error.
293
     *
294
     * @param int $orderNumber
295
     * @return OrderTrade[]
296
     */
297
    public function returnOrderTrades(int $orderNumber): array
298
    {
299
        $orderTrades = [];
300
        foreach ($this->request('returnOrderTrades', compact('orderNumber')) as $response) {
301
            $orderTrades[] = $this->factory(OrderTrade::class, $response);
302
        }
303
304
        return $orderTrades;
305
    }
306
307
    /**
308
     * Places a buy order in a given market.
309
     *
310
     * @param TradeRequest $tradeRequest
311
     * @return TradeResult
312
     */
313
    public function buy(TradeRequest $tradeRequest): TradeResult
314
    {
315
        return $this->tradeRequest('buy', $tradeRequest);
316
    }
317
318
    /**
319
     * Places a sell order in a given market.
320
     *
321
     * @param TradeRequest $tradeRequest
322
     * @return TradeResult
323
     */
324
    public function sell(TradeRequest $tradeRequest): TradeResult
325
    {
326
        return $this->tradeRequest('sell', $tradeRequest);
327
    }
328
329
    /**
330
     * Cancels an order you have placed in a given market.
331
     * Required POST parameter is "orderNumber".
332
     * If successful, the method will return: {"success":1}
333
     *
334
     * @param int $orderNumber
335
     * @return bool
336
     */
337
    public function cancelOrder(int $orderNumber): bool
338
    {
339
        $response = $this->request('cancelOrder', compact('orderNumber'));
340
341
        return isset($response['success']) ? (bool) $response['success'] : false;
342
    }
343
344
    /**
345
     * Cancels an order and places a new one of the same type in a single atomic
346
     * transaction, meaning either both operations will succeed or both will fail.
347
     * Required POST parameters are "orderNumber" and "rate"; you may optionally
348
     * specify "amount" if you wish to change the amount of the new order.
349
     *
350
     * "postOnly" or "immediateOrCancel" may be specified for exchange orders,
351
     * but will have no effect on margin orders.
352
     *
353
     * @param MoveOrderRequest $moveOrderRequest
354
     * @return MoveOrder
355
     */
356
    public function moveOrder(MoveOrderRequest $moveOrderRequest): MoveOrder
357
    {
358
        foreach (['orderNumber', 'rate'] as $requiredField) {
359
            $this->throwExceptionIf(
360
                $moveOrderRequest->{$requiredField} === null,
361
                sprintf('Unable to send "moveOrder" request. Field "%s" should be set.', $requiredField)
362
            );
363
        }
364
365
        /** @var $moveOrder MoveOrder */
366
        $moveOrder = $this->factory(
367
            MoveOrder::class,
368
            $this->request('moveOrder', get_object_vars($moveOrderRequest))
369
        );
370
371
        return $moveOrder;
372
    }
373
374
    /**
375
     * Immediately places a withdrawal for a given currency, with no email confirmation.
376
     * In order to use this method, the withdrawal privilege must be enabled for your API key.
377
     * Required POST parameters are "currency", "amount", and "address".
378
     * For XMR withdrawals, you may optionally specify "paymentId".
379
     *
380
     * @param string $currency
381
     * @param string $amount
382
     * @param string $address
383
     * @param int|null $paymentId
384
     *
385
     * @return string
386
     */
387
    public function withdraw(string $currency, string $amount, string $address, int $paymentId = null): string
388
    {
389
        $response = $this->request('withdraw', compact('currency', 'amount', 'address', 'paymentId'));
390
391
        return $response['response'] ?? 'Failed withdraw request.';
392
    }
393
394
    /**
395
     * If you are enrolled in the maker-taker fee schedule, returns your current trading fees
396
     * and trailing 30-day volume in BTC. This information is updated once every 24 hours.
397
     *
398
     * @return FeeInfo
399
     */
400
    public function returnFeeInfo(): FeeInfo
401
    {
402
        /** @var $feeInfo FeeInfo */
403
        $feeInfo = $this->factory(
404
            FeeInfo::class,
405
            $this->request('returnFeeInfo')
406
        );
407
408
        return $feeInfo;
409
    }
410
411
    /**
412
     * Returns your balances sorted by account. You may optionally specify the "account" POST parameter
413
     * if you wish to fetch only the balances of one account. Please note that balances in your margin
414
     * account may not be accessible if you have any open margin positions or orders.
415
     *
416
     * @param string|null $account
417
     * @return AvailableAccountBalances
418
     */
419
    public function returnAvailableAccountBalances(string $account = null): AvailableAccountBalances
420
    {
421
        $this->throwExceptionIf(
422
            $account !== null && !property_exists(AvailableAccountBalances::class, $account),
423
            sprintf('Invalid account type "%s" given', $account)
424
        );
425
426
        /* @var $availableAccountBalances AvailableAccountBalances */
427
        $availableAccountBalances = $this->factory(
428
            AvailableAccountBalances::class,
429
            $this->request('returnAvailableAccountBalances', compact('account'))
430
        );
431
432
        return $availableAccountBalances;
433
    }
434
435
    /**
436
     * Returns your current tradable balances for each currency in each market for which margin trading is enabled.
437
     * Please note that these balances may vary continually with market conditions. Sample output:
438
     *
439
     * "BTC_DASH" => [
440
     *      "BTC" => "8.50274777",
441
     *      "DASH":"654.05752077",
442
     * ], "BTC_LTC" => [
443
     *      "BTC" => "8.50274777",
444
     *      "LTC":"1214.67825290"
445
     * ],"BTC_XMR" => [
446
     *      "BTC" => "8.50274777",
447
     *      "XMR" => "3696.84685650"
448
     * ]
449
     *
450
     * @return array
451
     */
452
    public function returnTradableBalances(): array
453
    {
454
        return $this->request('returnTradableBalances');
455
    }
456
457
    /**
458
     * Transfers funds from one account to another (e.g. from your exchange account to your margin account).
459
     *
460
     * @param string $currency
461
     * @param float $amount
462
     * @param string $fromAccount
463
     * @param string $toAccount
464
     *
465
     * @return SampleResponse
466
     */
467
    public function transferBalance(
468
        string $currency,
469
        float $amount,
470
        string $fromAccount,
471
        string $toAccount
472
    ): SampleResponse {
473
        /* @var $response SampleResponse */
474
        $response = $this->factory(
475
            SampleResponse::class,
476
            $this->request('transferBalance', compact('currency', 'amount', 'fromAccount', 'toAccount'))
477
        );
478
479
        return $response;
480
    }
481
482
    /**
483
     * Returns a summary of your entire margin account. This is the same information you will find in the
484
     * Margin Account section of the Margin Trading page, under the Markets list.
485
     *
486
     * @return MarginAccountSummary
487
     */
488
    public function returnMarginAccountSummary(): MarginAccountSummary
489
    {
490
        /* @var $marginAccountSummary MarginAccountSummary */
491
        $marginAccountSummary = $this->factory(
492
            MarginAccountSummary::class,
493
            $this->request('returnMarginAccountSummary')
494
        );
495
496
        return $marginAccountSummary;
497
    }
498
499
    /**
500
     * Places a margin buy order in a given market.
501
     * You may optionally specify a maximum lending rate using the "lendingRate" parameter.
502
     * If successful, the method will return the order number and any trades immediately resulting from your order.
503
     *
504
     * @param string $currencyPair
505
     * @param float  $rate
506
     * @param float  $amount
507
     * @param float  $lendingRate
508
     *
509
     * @return MarginTrade
510
     */
511
    public function marginBuy(string $currencyPair, float $rate, float $amount, float $lendingRate = null): MarginTrade
512
    {
513
        return $this->marginTrade('marginBuy', compact('currencyPair', 'rate', 'amount', 'lendingRate'));
514
    }
515
516
    /**
517
     * Places a margin sell order in a given market.
518
     * Parameters and output are the same as for the marginBuy method.
519
     *
520
     * @param string     $currencyPair
521
     * @param float      $rate
522
     * @param float      $amount
523
     * @param float|null $lendingRate
524
     *
525
     * @return MarginTrade
526
     */
527
    public function marginSell(string $currencyPair, float $rate, float $amount, float $lendingRate = null): MarginTrade
528
    {
529
        return $this->marginTrade('marginSell', compact('currencyPair', 'rate', 'amount', 'lendingRate'));
530
531
    }
532
533
    /**
534
     * Returns information about your margin position in a given market.
535
     *
536
     * You may set "currencyPair" to "all" if you wish to fetch all of your margin positions at once.
537
     * If you have no margin position in the specified market, "type" will be set to "none".
538
     * "liquidationPrice" is an estimate, and does not necessarily represent the price at which an
539
     * actual forced liquidation will occur. If you have no liquidation price, the value will be -1.
540
     *
541
     * @param string $currencyPair
542
     * @return MarginPosition
543
     */
544
    public function getMarginPosition(string $currencyPair = 'all'): MarginPosition
545
    {
546
        /* @var $marginPosition MarginPosition */
547
        $marginPosition = $this->factory(
548
            MarginPosition::class,
549
            $this->request('getMarginPosition', compact('currencyPair'))
550
        );
551
552
        return $marginPosition;
553
    }
554
555
    /**
556
     * Closes your margin position in a given market using a market order.
557
     * This call will also return success if you do not have an open position in the specified market.
558
     *
559
     * @param string $currencyPair
560
     * @return CloseMarginPosition
561
     */
562
    public function closeMarginPosition(string $currencyPair): CloseMarginPosition
563
    {
564
        $response = $this->request('closeMarginPosition', compact('currencyPair'));
565
566
        $closeMarginPosition = new CloseMarginPosition();
567
        $closeMarginPosition->success = (bool) $response['success'];
568
        $closeMarginPosition->message = $response['message'];
569
570
        $responseResultingTrades = $response['resultingTrades'] ?? [];
571
572
        /* @var $resultingTrades array */
573
        foreach ($responseResultingTrades as $pair => $resultingTrades) {
574
            foreach ($resultingTrades as $resultingTrade) {
575
                $closeMarginPosition->resultingTrades[$pair][] = $this->factory(ResultingTrade::class, $resultingTrade);
576
            }
577
        }
578
579
        return $closeMarginPosition;
580
    }
581
582
    /**
583
     * Creates a loan offer for a given currency.
584
     *
585
     * @param CreateLoanOfferRequest $request
586
     * @return CreateLoanOffer
587
     */
588
    public function createLoanOffer(CreateLoanOfferRequest $request): CreateLoanOffer
589
    {
590
        foreach (get_object_vars($request) as $property => $value) {
591
            $this->throwExceptionIf(
592
                $value === null,
593
                sprintf('Unable to send "moveOrder" request. Field "%s" should be set.', $property)
594
            );
595
        }
596
597
        /* @var $createLoanOffer CreateLoanOffer */
598
        $createLoanOffer = $this->factory(
599
            CreateLoanOffer::class,
600
            $this->request('createLoanOffer', get_object_vars($request))
601
        );
602
603
        return $createLoanOffer;
604
    }
605
606
    /**
607
     * Cancels a loan offer specified by the "orderNumber" POST parameter.
608
     *
609
     * @param int $orderNumber
610
     * @return SampleResponse
611
     */
612
    public function cancelLoanOffer(int $orderNumber): SampleResponse
613
    {
614
        /* @var $response SampleResponse */
615
        $response = $this->factory(
616
            SampleResponse::class,
617
            $this->request('cancelLoanOffer', compact('orderNumber'))
618
        );
619
620
        return $response;
621
    }
622
623
    /**
624
     * Returns your open loan offers for each currency.
625
     * NOTE: Keys of result array is currency codes
626
     *
627
     * @return Loan[][]
628
     */
629
    public function returnOpenLoanOffers(): array
630
    {
631
        $openLoanOffers = [];
632
633
        /* @var $offers array */
634
        foreach ($this->request('returnOpenLoanOffers') as $currency => $offers) {
635
            foreach ($offers as $offer) {
636
                $openLoanOffers[$currency][] = $this->factory(Loan::class, $offer);
637
            }
638
        }
639
640
        return $openLoanOffers;
641
    }
642
643
    /**
644
     * Returns your active loans for each currency
645
     */
646
    public function returnActiveLoans(): ActiveLoans
647
    {
648
        /* @var $activeLoans ActiveLoans */
649
        $activeLoans = $this->factory(
650
            ActiveLoans::class,
651
            $this->request('returnActiveLoans')
652
        );
653
654
        return $activeLoans;
655
    }
656
657
    /**
658
     * Returns your lending history within a time range specified by the "start" and "end" POST parameters
659
     * as UNIX timestamps. "limit" may also be specified to limit the number of rows returned.
660
     *
661
     * @param int      $start
662
     * @param int      $end
663
     * @param int|null $limit
664
     *
665
     * @return LandingHistory[]
666
     */
667
    public function returnLendingHistory(int $start, int $end, int $limit = null): array
668
    {
669
        $history = [];
670
671
        foreach ($this->request('returnLendingHistory', compact('start', 'end', 'limit')) as $data) {
672
            $history[] = $this->factory(LandingHistory::class, $data);
673
        }
674
675
        return $history;
676
    }
677
678
    /**
679
     * Toggles the autoRenew setting on an active loan, specified by the "orderNumber" POST parameter.
680
     * If successful, "message" will indicate the new autoRenew setting.
681
     *
682
     * @param int $orderNumber
683
     *
684
     * @return SampleResponse
685
     */
686
    public function toggleAutoRenew(int $orderNumber): SampleResponse
687
    {
688
        /* @var $autoRenew SampleResponse */
689
        $autoRenew = $this->factory(
690
            SampleResponse::class,
691
            $this->request('toggleAutoRenew', compact('orderNumber'))
692
        );
693
694
        return $autoRenew;
695
    }
696
697
    /**
698
     * Places a limit buy order in a given market. Required POST parameters are "currencyPair", "rate", and "amount".
699
     * If successful, the method will return the order number.
700
     *
701
     * You may optionally set "fillOrKill", "immediateOrCancel", "postOnly" to 1. A fill-or-kill order will either
702
     * fill in its entirety or be completely aborted. An immediate-or-cancel order can be partially or completely
703
     * filled, but any portion of the order that cannot be filled immediately will be canceled rather than left on
704
     * the order book. A post-only order will only be placed if no portion of it fills immediately; this guarantees
705
     * you will never pay the taker fee on any part of the order that fills.
706
     *
707
     * @param string $command
708
     * @param TradeRequest $tradeRequest
709
     *
710
     * @return TradeResult
711
     */
712
    protected function tradeRequest(string $command, TradeRequest $tradeRequest): TradeResult
713
    {
714
        foreach (['currencyPair', 'rate', 'amount'] as $requiredField) {
715
            $this->throwExceptionIf(
716
                $tradeRequest->{$requiredField} === null,
717
                sprintf('Unable to send "%s" request. Field "%s" should be set.', $command, $requiredField)
718
            );
719
        }
720
721
        $coin = strtoupper(explode('_', $tradeRequest->currencyPair)[0]);
722
        $total = $tradeRequest->amount * $tradeRequest->rate;
723
724
        if (isset(TradeRequest::MIN_TOTAL[$coin]) && TradeRequest::MIN_TOTAL[$coin] > $total) {
725
            throw new TotalDeficiencyException(TradeRequest::MIN_TOTAL[$coin], $coin);
726
        }
727
728
        $response = $this->request($command, get_object_vars($tradeRequest));
729
        $this->throwExceptionIf(!isset($response['orderNumber'], $response['resultingTrades']), 'Poloniex buy error.');
730
731
        $buySell = new TradeResult();
732
        $buySell->orderNumber = (int) $response['orderNumber'];
733
        $resultingTrades = $response['resultingTrades'] ?? [];
734
735
        foreach ($resultingTrades as $trade) {
736
            $buySell->resultingTrades[] = $this->factory(ResultingTrade::class, $trade);
737
        }
738
739
        return $buySell;
740
    }
741
742
    /**
743
     * @param string $command
744
     * @param array  $params
745
     *
746
     * @return MarginTrade
747
     */
748
    protected function marginTrade(string $command, array $params): MarginTrade
749
    {
750
        $response = $this->request($command, $params);
751
752
        $marginTrade = new MarginTrade();
753
        $marginTrade->success = $response['success'] ?? null;
754
        $marginTrade->message = $response['message'] ?? null;
755
        $marginTrade->orderNumber = (int) $response['orderNumber'];
756
757
        $resultingTrades = $response['resultingTrades'] ?? [];
758
759
        /*  @var $trades array */
760
        foreach ($resultingTrades as $currencyPair => $trades) {
761
            foreach ($trades as $trade) {
762
                $marginTrade->resultingTrades[$currencyPair][] = $this->factory(ResultingTrade::class, $trade);
763
            }
764
        }
765
766
        return $marginTrade;
767
    }
768
769
    /**
770
     * {@inheritdoc}
771
     */
772
    protected function getRequestMethod(): string
773
    {
774
        return 'POST';
775
    }
776
777
    /**
778
     * {@inheritdoc}
779
     */
780
    protected function getRequestUri(): string
781
    {
782
        return 'tradingApi';
783
    }
784
785
    /**
786
     * The nonce parameter is an integer which must always be greater than the previous nonce used.
787
     * Generate a nonce to avoid problems with 32bit systems
788
     */
789
    public function getNonce(): int
790
    {
791
        $time = explode(' ', microtime());
792
793
        return $time[1] . substr($time[0], 2, 6);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $time[1] . substr($time[0], 2, 6) returns the type string which is incompatible with the type-hinted return integer.
Loading history...
794
    }
795
}