├── .gitignore
├── src
├── Enum
│ └── MarginMode.php
├── ApiCode.php
├── Exceptions
│ ├── NoAvailableWebSocketServerException.php
│ ├── BusinessException.php
│ ├── InvalidApiUriException.php
│ └── HttpException.php
├── IAuth.php
├── Http
│ ├── BaseHttp.php
│ ├── IHttp.php
│ ├── Response.php
│ ├── ApiResponse.php
│ ├── GuzzleHttp.php
│ ├── SwooleHttp.php
│ └── Request.php
├── KuCoinFuturesApi.php
├── PublicApi
│ ├── Time.php
│ ├── Status.php
│ ├── Contract.php
│ ├── Index.php
│ └── Symbol.php
├── PrivateApi
│ ├── Fee.php
│ ├── Deposit.php
│ ├── RiskLimitLevel.php
│ ├── Fill.php
│ ├── Withdrawal.php
│ ├── Account.php
│ ├── Position.php
│ ├── Order.php
│ └── WebSocketFeed.php
├── Auth.php
└── Api.php
├── .travis.yml
├── examples
├── Status.php
├── Time.php
├── GoTime.php
├── Account.php
├── BenchmarkCoroutine.php
├── GoOrder.php
└── WebSocketFeed.php
├── tests
├── TimeTest.php
├── StatusTest.php
├── FeeTest.php
├── RiskLimitLevelTest.php
├── TestCase.php
├── DepositTest.php
├── FillTest.php
├── WithdrawalTest.php
├── IndexTest.php
├── SymbolTest.php
├── ContractTest.php
├── PositionTest.php
├── AccountTest.php
├── WebSocketFeedTest.php
└── OrderTest.php
├── LICENSE
├── phpunit.xml
├── composer.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | .idea
3 | *.swap
4 | composer.lock
--------------------------------------------------------------------------------
/src/Enum/MarginMode.php:
--------------------------------------------------------------------------------
1 | config = $config;
12 | }
13 | }
--------------------------------------------------------------------------------
/examples/Status.php:
--------------------------------------------------------------------------------
1 | status();
12 | var_dump($status);
13 |
--------------------------------------------------------------------------------
/examples/Time.php:
--------------------------------------------------------------------------------
1 | timestamp();
12 | var_dump($timestamp);
13 |
--------------------------------------------------------------------------------
/src/Http/IHttp.php:
--------------------------------------------------------------------------------
1 | timestamp();
16 | var_dump($timestamp);
17 | });
--------------------------------------------------------------------------------
/src/Exceptions/BusinessException.php:
--------------------------------------------------------------------------------
1 | response;
20 | }
21 |
22 | /**
23 | * @param ApiResponse $response
24 | */
25 | public function setResponse($response)
26 | {
27 | $this->response = $response;
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/tests/TimeTest.php:
--------------------------------------------------------------------------------
1 | timestamp();
22 | $this->assertInternalType('int', $timestamp);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/KuCoinFuturesApi.php:
--------------------------------------------------------------------------------
1 | getOverview();
18 | var_dump($result);
19 | } catch (HttpException $e) {
20 | var_dump($e->getMessage());
21 | } catch (BusinessException $e) {
22 | var_dump($e->getMessage());
23 | }
24 |
--------------------------------------------------------------------------------
/src/PublicApi/Time.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/timestamp');
25 | return $response->getApiData();
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/StatusTest.php:
--------------------------------------------------------------------------------
1 | status();
22 | $this->assertInternalType('array', $status);
23 | $this->assertArrayHasKey('msg', $status);
24 | $this->assertArrayHasKey('status', $status);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/PublicApi/Status.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/status');
25 | return $response->getApiData();
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Exceptions/InvalidApiUriException.php:
--------------------------------------------------------------------------------
1 | baseUri;
23 | }
24 |
25 | /**
26 | * @param string $baseUri
27 | */
28 | public function setBaseUri($baseUri)
29 | {
30 | $this->baseUri = $baseUri;
31 | }
32 |
33 | /**
34 | * @return string
35 | */
36 | public function getUri()
37 | {
38 | return $this->uri;
39 | }
40 |
41 | /**
42 | * @param string $uri
43 | */
44 | public function setUri($uri)
45 | {
46 | $this->uri = $uri;
47 | }
48 | }
--------------------------------------------------------------------------------
/tests/FeeTest.php:
--------------------------------------------------------------------------------
1 | getTradeFees($symbol);
24 | $this->assertInternalType('array', $data);
25 | $this->assertArrayHasKey('symbol', $data);
26 | $this->assertArrayHasKey('takerFeeRate', $data);
27 | $this->assertArrayHasKey('makerFeeRate', $data);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/examples/BenchmarkCoroutine.php:
--------------------------------------------------------------------------------
1 | timestamp();
25 | var_dump($timestamp);
26 | }
27 | }
28 |
29 | function asyncIO()
30 | {
31 | global $maxCount;
32 | $api = new Time(null, new SwooleHttp);
33 | for ($i = 0; $i < $maxCount; $i++) {
34 | go(function () use ($api) {
35 | $timestamp = $api->timestamp();
36 | var_dump($timestamp);
37 | });
38 | }
39 | Event::wait();
40 | }
--------------------------------------------------------------------------------
/src/Exceptions/HttpException.php:
--------------------------------------------------------------------------------
1 | request;
26 | }
27 |
28 | /**
29 | * @param Request $request
30 | */
31 | public function setRequest($request)
32 | {
33 | $this->request = $request;
34 | }
35 |
36 | /**
37 | * @return Response
38 | */
39 | public function getResponse()
40 | {
41 | return $this->response;
42 | }
43 |
44 | /**
45 | * @param Response $response
46 | */
47 | public function setResponse($response)
48 | {
49 | $this->response = $response;
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/src/PrivateApi/Fee.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/trade-fees', compact('symbol'));
27 | return $response->getApiData();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 KuCoin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/GoOrder.php:
--------------------------------------------------------------------------------
1 | uniqid(),
23 | 'price' => '1',
24 | 'size' => '1',
25 | 'symbol' => 'BTC-USDT',
26 | 'type' => 'limit',
27 | 'side' => 'buy',
28 | 'remark' => 'ORDER#' . $i,
29 | ];
30 | try {
31 | $result = $api->create($order);
32 | var_dump($result);
33 | } catch (\Throwable $e) {
34 | var_dump($e->getMessage());
35 | }
36 | });
37 | }
38 | });
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | tests
12 | tests/TestCase.php
13 |
14 |
15 |
16 |
17 | ./src
18 |
19 | ./vendor
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kucoin/kucoin-futures-php-sdk",
3 | "type": "library",
4 | "license": "MIT",
5 | "description": "PHP SDK for KuCoin Futures API",
6 | "keywords": [
7 | "kucoin",
8 | "futures",
9 | "kumex",
10 | "api",
11 | "sdk"
12 | ],
13 | "homepage": "https://github.com/Kucoin/kucoin-futures-php-sdk",
14 | "support": {
15 | "source": "https://github.com/Kucoin/kucoin-futures-php-sdk",
16 | "issues": "https://github.com/Kucoin/kucoin-futures-php-sdk/issues"
17 | },
18 | "authors": [
19 | {
20 | "name": "KuCoin API",
21 | "email": "api@kucoin.com"
22 | }
23 | ],
24 | "require": {
25 | "php": ">=5.5.0",
26 | "ext-json": "*",
27 | "guzzlehttp/guzzle": "^6.0|^7.0",
28 | "ratchet/pawl": "^0.4.1",
29 | "monolog/monolog": "~1.0|~2.0|~3.0"
30 | },
31 | "require-dev": {
32 | "phpunit/phpunit": ">=5.7"
33 | },
34 | "autoload": {
35 | "psr-4": {
36 | "KuCoin\\Futures\\SDK\\": "src/"
37 | }
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "KuCoin\\Futures\\SDK\\Tests\\": "tests/"
42 | }
43 | },
44 | "minimum-stability": "dev",
45 | "prefer-stable": true,
46 | "config": {
47 | "optimize-autoloader": true,
48 | "secure-http": false
49 | },
50 | "scripts": {
51 | "test": "./vendor/bin/phpunit -c phpunit.xml --filter '/::testGet\\w+/' --coverage-text --verbose"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/PrivateApi/Deposit.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/deposit-address', compact('currency'));
27 | return $response->getApiData();
28 | }
29 |
30 | /**
31 | * Get deposit list.
32 | *
33 | * @param array $params
34 | * @param array $pagination
35 | * @return array
36 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
38 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
39 | */
40 | public function getDeposits(array $params, array $pagination = [])
41 | {
42 | $response = $this->call(Request::METHOD_GET, '/api/v1/deposit-list', $params + $pagination);
43 | return $response->getApiData();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/PrivateApi/RiskLimitLevel.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/contracts/risk-limit/' . $symbol);
27 | return $response->getApiData();
28 | }
29 |
30 | /**
31 | * Adjust risk Limit Level
32 | *
33 | * @param $symbol
34 | * @param $level
35 | * @return mixed|null
36 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
38 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
39 | */
40 | public function changeRiskLimitLevel($symbol, $level)
41 | {
42 | $response = $this->call(Request::METHOD_POST, '/api/v1/position/risk-limit-level/change', ['symbol' => $symbol, 'level' => $level]);
43 | return $response->getApiData();
44 | }
45 | }
--------------------------------------------------------------------------------
/src/Http/Response.php:
--------------------------------------------------------------------------------
1 | body = $body;
30 | $this->statusCode = $statusCode;
31 | $this->headers = $headers;
32 | }
33 |
34 | public function setRequest(Request $request)
35 | {
36 | $this->request = $request;
37 | }
38 |
39 | public function getRequest()
40 | {
41 | return $this->request;
42 | }
43 |
44 | public function getHeaders()
45 | {
46 | return $this->headers;
47 | }
48 |
49 | public function getBody($decodeJson = false)
50 | {
51 | return $decodeJson ? json_decode($this->body, true) : $this->body;
52 | }
53 |
54 | public function getStatusCode()
55 | {
56 | return $this->statusCode;
57 | }
58 |
59 | public function isSuccessful()
60 | {
61 | return $this->statusCode == 200;
62 | }
63 |
64 | public function __toString()
65 | {
66 | $str = 'respond ' . $this->getStatusCode();
67 | $str .= ' with headers=' . json_encode($this->getHeaders(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
68 | $str .= ' with body=' . $this->getBody(false);
69 | return $str;
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/examples/WebSocketFeed.php:
--------------------------------------------------------------------------------
1 | subscribePrivateChannel()).
16 | // $auth = new Auth('key', 'secret', 'passphrase');
17 | $api = new WebSocketFeed($auth);
18 |
19 | // Use a custom event loop instance if you like
20 | //$loop = Factory::create();
21 | //$loop->addPeriodicTimer(1, function () {
22 | // var_dump(date('Y-m-d H:i:s'));
23 | //});
24 | //$api->setLoop($loop);
25 |
26 | $query = ['connectId' => uniqid('', true)];
27 | $channels = [
28 | ['topic' => '/contractMarket/ticker:XBTUSDM'], // Subscribe multiple channels
29 | ['topic' => '/contractMarket/ticker:XBTUSDTM'],
30 | ];
31 |
32 | $api->subscribePublicChannels($query, $channels, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
33 | var_dump($message);
34 |
35 | // Subscribe another channel
36 | // $ws->send(json_encode($api->createSubscribeMessage('/contractMarket/ticker:ETHUSDTM')));
37 |
38 | // Unsubscribe the channel
39 | // $ws->send(json_encode($api->createUnsubscribeMessage('/contractMarket/ticker:XBTUSDM')));
40 |
41 | // Stop loop
42 | // $loop->stop();
43 | }, function ($code, $reason) {
44 | echo "OnClose: {$code} {$reason}\n";
45 | });
--------------------------------------------------------------------------------
/tests/RiskLimitLevelTest.php:
--------------------------------------------------------------------------------
1 | getRiskLimitLevel('ADAUSDTM');
22 | $this->assertInternalType('array', $data);
23 | foreach ($data as $datum) {
24 | $this->assertArrayHasKey('symbol', $datum);
25 | $this->assertArrayHasKey('level', $datum);
26 | $this->assertArrayHasKey('maxRiskLimit', $datum);
27 | $this->assertArrayHasKey('minRiskLimit', $datum);
28 | $this->assertArrayHasKey('maxLeverage', $datum);
29 | $this->assertArrayHasKey('initialMargin', $datum);
30 | $this->assertArrayHasKey('maintainMargin', $datum);
31 | }
32 | }
33 |
34 | /**
35 | * @dataProvider apiProvider
36 | *
37 | * @param RiskLimitLevel $api
38 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
39 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
40 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
41 | */
42 | public function testChangeRiskLimitLevel(RiskLimitLevel $api)
43 | {
44 | $data = $api->changeRiskLimitLevel('ADAUSDTM', 2);
45 | $this->assertInternalType('bool', $data);
46 | }
47 | }
--------------------------------------------------------------------------------
/src/PublicApi/Contract.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/contracts/active');
26 | return $response->getApiData();
27 | }
28 |
29 | /**
30 | * Get the details of a contract.
31 | *
32 | * @param string $symbol
33 | * @return array
34 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
35 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
36 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
37 | */
38 | public function getDetail($symbol)
39 | {
40 | $response = $this->call(Request::METHOD_GET, '/api/v1/contracts/' . $symbol);
41 | return $response->getApiData();
42 | }
43 |
44 | /**
45 | * Get Latest Ticker for All Contracts.
46 | *
47 | * @return mixed|null
48 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
49 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
50 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
51 | */
52 | public function getAllTickers()
53 | {
54 | $response = $this->call(Request::METHOD_GET, '/api/v1/allTickers');
55 | return $response->getApiData();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | apiClass($this->apiWithAuth ? $auth : null)],
37 | [new $this->apiClass($this->apiWithAuth ? $auth : null, new GuzzleHttp(['skipVerifyTls' => $apiSkipVerifyTls]))],
38 | //[new $this->apiClass($this->apiWithAuth ? $auth : null, new SwooleHttp(['skipVerifyTls' => $apiSkipVerifyTls]))],
39 | ];
40 | }
41 |
42 | protected function assertPagination($data)
43 | {
44 | $this->assertInternalType('array', $data);
45 | $this->assertArrayHasKey('totalNum', $data);
46 | $this->assertArrayHasKey('totalPage', $data);
47 | $this->assertArrayHasKey('pageSize', $data);
48 | $this->assertArrayHasKey('currentPage', $data);
49 | $this->assertArrayHasKey('items', $data);
50 | $this->assertInternalType('array', $data['items']);
51 | }
52 | }
--------------------------------------------------------------------------------
/src/PrivateApi/Fill.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/fills', $params + $pagination);
28 | return $response->getApiData();
29 | }
30 |
31 | /**
32 | * Get the recent orders of the latest transactions within 24 hours.
33 | *
34 | * @return array
35 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
36 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
38 | */
39 | public function getRecentList()
40 | {
41 | $response = $this->call(Request::METHOD_GET, '/api/v1/recentFills');
42 | return $response->getApiData();
43 | }
44 | /**
45 | * Get a funding-history list.
46 | *
47 | * @param array $params
48 | * @param array $pagination
49 | * @return array
50 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
51 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
52 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
53 | */
54 | public function getFundingHistory(array $params, array $pagination = [])
55 | {
56 | $response = $this->call(Request::METHOD_GET, '/api/v1/funding-history', $params + $pagination);
57 | return $response->getApiData();
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/tests/DepositTest.php:
--------------------------------------------------------------------------------
1 | getAddress('XBT');
25 | // if ($address !== null) {
26 | // $this->assertInternalType('array', $address);
27 | // $this->assertArrayHasKey('address', $address);
28 | // $this->assertArrayHasKey('memo', $address);
29 | // }
30 | // } catch (BusinessException $e) {
31 | // // deposit.disabled
32 | // if ($e->getResponse()->getApiCode() == '260200') {
33 | // return;
34 | // }
35 | // throw $e;
36 | // }
37 | $this->assertTrue(true);
38 | }
39 |
40 | /**
41 | * @dataProvider apiProvider
42 | * @param Deposit $api
43 | * @return array|string
44 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
45 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
46 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
47 | */
48 | public function testGetDeposits(Deposit $api)
49 | {
50 | $data = $api->getDeposits(['currency' => 'XBT'], ['currentPage' => 1, 'pageSize' => 10]);
51 | $this->assertPagination($data);
52 | foreach ($data['items'] as $item) {
53 | $this->assertArrayHasKey('currency', $item);
54 | $this->assertArrayHasKey('status', $item);
55 | $this->assertArrayHasKey('address', $item);
56 | $this->assertArrayHasKey('isInner', $item);
57 | $this->assertArrayHasKey('amount', $item);
58 | $this->assertArrayHasKey('fee', $item);
59 | $this->assertArrayHasKey('walletTxId', $item);
60 | $this->assertArrayHasKey('createdAt', $item);
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/PrivateApi/Withdrawal.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/withdrawals/quotas', compact('currency'));
26 | return $response->getApiData();
27 | }
28 |
29 | /**
30 | * Get a list of withdrawal
31 | * @param array $params
32 | * @param array $pagination
33 | * @return array
34 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
35 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
36 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
37 | */
38 | public function getList(array $params, array $pagination = [])
39 | {
40 | $response = $this->call(Request::METHOD_GET, '/api/v1/withdrawal-list', $params + $pagination);
41 | return $response->getApiData();
42 | }
43 |
44 | /**
45 | * Apply a withdrawal
46 | * @param array $params
47 | * @return array
48 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
49 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
50 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
51 | */
52 | public function apply(array $params)
53 | {
54 | $response = $this->call(Request::METHOD_POST, '/api/v1/withdrawals', $params);
55 | return $response->getApiData();
56 | }
57 |
58 | /**
59 | * Cancel a withdrawal
60 | * @param string $withdrawId
61 | * @return array
62 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
63 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
64 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
65 | */
66 | public function cancel($withdrawId)
67 | {
68 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/withdrawals/' . $withdrawId);
69 | return $response->getApiData();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Auth.php:
--------------------------------------------------------------------------------
1 | key = $key;
22 | $this->secret = $secret;
23 | $this->passphrase = $passphrase;
24 | $this->apiKeyVersion = $apiKeyVersion;
25 | }
26 |
27 | public function signature($requestUri, $body, $timestamp, $method)
28 | {
29 | // Decode $requestUri
30 | $parts = parse_url($requestUri);
31 | if (isset($parts['query'])) {
32 | parse_str($parts['query'], $queries);
33 | $queryString = '';
34 | foreach ($queries as $key => $value) {
35 | $queryString .= sprintf('%s=%s&', $key, $value);
36 | }
37 | $queryString = rtrim($queryString, '&');
38 | $requestUri = $parts['path'] . '?' . $queryString;
39 | if (isset($parts['fragment'])) {
40 | $requestUri .= '#' . $parts['fragment'];
41 | }
42 | }
43 |
44 | if (is_array($body)) {
45 | $body = empty($body) ? '' : json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
46 | } else {
47 | $body = (string)$body;
48 | }
49 | $method = strtoupper($method);
50 | $plain = $timestamp . $method . $requestUri . $body;
51 | return base64_encode(hash_hmac('sha256', $plain, $this->secret, true));
52 | }
53 |
54 | public function getHeaders($method, $requestUri, $body)
55 | {
56 | $timestamp = floor(microtime(true) * 1000);
57 | $isApiKeyVersionV1 = $this->apiKeyVersion === self::API_KEY_VERSION_V1;
58 | $headers = [
59 | 'KC-API-KEY' => $this->key,
60 | 'KC-API-TIMESTAMP' => $timestamp,
61 | 'KC-API-PASSPHRASE' => $isApiKeyVersionV1 ? $this->passphrase : $this->signaturePassphrase(),
62 | 'KC-API-SIGN' => $this->signature($requestUri, $body, $timestamp, $method),
63 | ];
64 |
65 | !$isApiKeyVersionV1 && $headers['KC-API-KEY-VERSION'] = $this->apiKeyVersion;
66 | return $headers;
67 | }
68 |
69 | private function signaturePassphrase()
70 | {
71 | return base64_encode(hash_hmac('sha256', $this->passphrase, $this->secret, true));
72 | }
73 | }
--------------------------------------------------------------------------------
/src/PublicApi/Index.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/index/query', $params + $pagination);
28 | return $response->getApiData();
29 | }
30 |
31 | /**
32 | * Get mark price.
33 | *
34 | * @param string $symbol
35 | * @return array
36 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
38 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
39 | */
40 | public function getMarkPrice($symbol)
41 | {
42 | $response = $this->call(Request::METHOD_GET, sprintf('/api/v1/mark-price/%s/current', $symbol));
43 | return $response->getApiData();
44 | }
45 |
46 | /**
47 | * Get a interest list of index.
48 | *
49 | * @param array $pagination
50 | * @return array
51 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
52 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
53 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
54 | */
55 | public function getInterests(array $pagination = [])
56 | {
57 | $response = $this->call(Request::METHOD_GET, '/api/v1/interest/query', $pagination);
58 | return $response->getApiData();
59 | }
60 |
61 | /**
62 | * Get a premium of index list.
63 | *
64 | * @param array $params
65 | * @param array $pagination
66 | * @return array
67 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
68 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
69 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
70 | */
71 | public function getPremium(array $params, array $pagination = [])
72 | {
73 | $response = $this->call(Request::METHOD_GET, '/api/v1/premium/query', $params + $pagination);
74 | return $response->getApiData();
75 | }
76 |
77 | /**
78 | * Get current funding rate.
79 | *
80 | * @param string $symbol
81 | * @return array
82 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
83 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
84 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
85 | */
86 | public function getCurrentFundingRate($symbol)
87 | {
88 | $response = $this->call(Request::METHOD_GET, sprintf('/api/v1/funding-rate/%s/current', $symbol));
89 | return $response->getApiData();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Http/ApiResponse.php:
--------------------------------------------------------------------------------
1 | httpResponse = $response;
21 | }
22 |
23 | public function getBody()
24 | {
25 | if (is_null($this->body)) {
26 | $this->body = $this->httpResponse->getBody(true);
27 | }
28 | return $this->body;
29 | }
30 |
31 | public function getApiCode()
32 | {
33 | $body = $this->getBody();
34 | return isset($body['code']) ? $body['code'] : '';
35 | }
36 |
37 | public function getApiMessage()
38 | {
39 | $body = $this->getBody();
40 | return isset($body['msg']) ? $body['msg'] : '';
41 | }
42 |
43 | public function getHttpResponse()
44 | {
45 | return $this->httpResponse;
46 | }
47 |
48 | public function isSuccessful()
49 | {
50 | if ($this->httpResponse->isSuccessful()) {
51 | if ($this->getApiCode() == ApiCode::SUCCESS) {
52 | return true;
53 | }
54 | }
55 | return false;
56 | }
57 |
58 | public function mustSuccessful()
59 | {
60 | if (!$this->httpResponse->isSuccessful()) {
61 | $msg = sprintf(
62 | '[HTTP]Failure: status code is NOT 200, %s %s with body=%s, respond code=%d body=%s',
63 | $this->httpResponse->getRequest()->getMethod(),
64 | $this->httpResponse->getRequest()->getRequestUri(),
65 | $this->httpResponse->getRequest()->getBodyParams(),
66 | $this->httpResponse->getStatusCode(),
67 | $this->httpResponse->getBody()
68 | );
69 | $exception = new HttpException($msg, $this->httpResponse->getStatusCode());
70 | $exception->setRequest($this->httpResponse->getRequest());
71 | $exception->setResponse($this->httpResponse);
72 | throw $exception;
73 | }
74 |
75 | if (!$this->isSuccessful()) {
76 | $msg = sprintf(
77 | '[API]Failure: api code is NOT %s, %s %s with body=%s, respond code=%s message="%s" body=%s',
78 | ApiCode::SUCCESS,
79 | $this->httpResponse->getRequest()->getMethod(),
80 | $this->httpResponse->getRequest()->getRequestUri(),
81 | $this->httpResponse->getRequest()->getBodyParams(),
82 | $this->getApiCode(),
83 | $this->getApiMessage(),
84 | $this->httpResponse->getBody()
85 | );
86 | $exception = new BusinessException($msg, is_numeric($this->getApiCode()) ? $this->getApiCode() : 110);
87 | $exception->setResponse($this);
88 | throw $exception;
89 | }
90 | }
91 |
92 | /**
93 | * @return mixed
94 | * @throws BusinessException
95 | * @throws HttpException
96 | */
97 | public function getApiData()
98 | {
99 | $this->mustSuccessful();
100 | $body = $this->getBody();
101 | if (!isset($body['data'])) {
102 | return null;
103 | }
104 | return $body['data'];
105 | }
106 |
107 | }
--------------------------------------------------------------------------------
/src/Http/GuzzleHttp.php:
--------------------------------------------------------------------------------
1 | getBaseUri() && strpos($request->getUri(), '://') === false) {
38 | $exception = new InvalidApiUriException('Invalid base_uri or uri, must set base_uri or set uri to a full url');
39 | $exception->setBaseUri($request->getBaseUri());
40 | $exception->setUri($request->getUri());
41 | throw $exception;
42 | }
43 |
44 | $config = [
45 | 'base_uri' => $request->getBaseUri(),
46 | 'timeout' => $timeout,
47 | 'connect_timeout' => 30,
48 | 'http_errors' => false,
49 | 'verify' => isset($this->config['verify']) ? $this->config['verify'] : empty($this->config['skipVerifyTls']),
50 | ] + $this->config;
51 | $client = static::getClient($config);
52 | $options = [
53 | 'headers' => $request->getHeaders(),
54 | ];
55 | $method = $request->getMethod();
56 | $params = $request->getParams();
57 | $hasParam = !empty($params);
58 | switch ($method) {
59 | case Request::METHOD_GET:
60 | case Request::METHOD_DELETE:
61 | $hasParam AND $options['query'] = $params;
62 | break;
63 | case Request::METHOD_PUT:
64 | case Request::METHOD_POST:
65 | if ($hasParam) {
66 | $options['headers']['Content-Type'] = 'application/json';
67 | $options['body'] = $request->getBodyParams();
68 | }
69 | break;
70 | default:
71 | $exception = new HttpException('Unsupported method ' . $method, 0);
72 | $exception->setRequest($request);
73 | throw $exception;
74 | }
75 | try {
76 | $guzzleResponse = $client->request($request->getMethod(), $request->getUri(), $options);
77 | $response = new Response($guzzleResponse->getBody()->__toString(), $guzzleResponse->getStatusCode(), $guzzleResponse->getHeaders());
78 | $response->setRequest($request);
79 | return $response;
80 | } catch (\GuzzleHttp\Exception\GuzzleException $e) {
81 | $exception = new HttpException($e->getMessage(), $e->getCode(), $e);
82 | $exception->setRequest($request);
83 | throw $exception;
84 | } catch (\Exception $e) {
85 | $exception = new HttpException($e->getMessage(), $e->getCode(), $e);
86 | $exception->setRequest($request);
87 | throw $exception;
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/src/Http/SwooleHttp.php:
--------------------------------------------------------------------------------
1 | getBaseUri() && strpos($request->getUri(), '://') === false) {
47 | $exception = new InvalidApiUriException('Invalid base_uri or uri, must set base_uri or set uri to a full url');
48 | $exception->setBaseUri($request->getBaseUri());
49 | $exception->setUri($request->getUri());
50 | throw $exception;
51 | }
52 |
53 | $config = [
54 | 'base_uri' => $request->getBaseUri(),
55 | 'timeout' => $timeout,
56 | 'use_pool' => true,
57 | 'ssl_verify_peer' => isset($this->config['ssl_verify_peer']) ? $this->config['ssl_verify_peer'] : empty($this->config['skipVerifyTls']),
58 | ] + $this->config;
59 | $client = static::getClient($config);
60 | $options['headers'] = $request->getHeaders();
61 |
62 | $method = $request->getMethod();
63 | $requestUri = $request->getRequestUri();
64 | try {
65 | switch ($method) {
66 | case Request::METHOD_GET:
67 | case Request::METHOD_DELETE:
68 | /**@var \Swlib\Saber\Response $saberResponse */
69 | $saberResponse = $client->{strtolower($method)}($requestUri, $options);
70 | break;
71 | case Request::METHOD_PUT:
72 | case Request::METHOD_POST:
73 | $data = $request->getBodyParams();
74 | $options['headers']['Content-Type'] = ContentType::JSON;
75 | /**@var \Swlib\Saber\Response $saberResponse */
76 | $saberResponse = $client->{strtolower($method)}($requestUri, $data, $options);
77 | break;
78 | default:
79 | $exception = new HttpException('Unsupported method ' . $method, 0);
80 | $exception->setRequest($request);
81 | throw $exception;
82 | }
83 | $response = new Response($saberResponse->getBody()->__toString(), $saberResponse->getStatusCode(), $saberResponse->getHeaders());
84 | $response->setRequest($request);
85 | return $response;
86 | } catch (\Exception $e) {
87 | if ($e instanceof RequestException && $e->hasResponse()) {
88 | $saberResponse = $e->getResponse();
89 | $response = new Response($saberResponse->getBody()->__toString(), $saberResponse->getStatusCode(), $saberResponse->getHeaders());
90 | $response->setRequest($request);
91 | return $response;
92 | }
93 | $exception = new HttpException($e->getMessage(), $e->getCode(), $e);
94 | $exception->setRequest($request);
95 | throw $exception;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/tests/FillTest.php:
--------------------------------------------------------------------------------
1 | getFills([], ['currentPage' => 1, 'pageSize' => 10]);
22 | var_dump($data);
23 | $this->assertPagination($data);
24 | foreach ($data['items'] as $item) {
25 | $this->assertArrayHasKey('symbol', $item);
26 | $this->assertArrayHasKey('side', $item);
27 | $this->assertArrayHasKey('forceTaker', $item);
28 | $this->assertArrayHasKey('orderId', $item);
29 | $this->assertArrayHasKey('fee', $item);
30 | $this->assertArrayHasKey('liquidity', $item);
31 | $this->assertArrayHasKey('feeRate', $item);
32 | $this->assertArrayHasKey('createdAt', $item);
33 | $this->assertArrayHasKey('size', $item);
34 | $this->assertArrayHasKey('stop', $item);
35 | $this->assertArrayHasKey('price', $item);
36 | $this->assertArrayHasKey('tradeId', $item);
37 | $this->assertArrayHasKey('settleCurrency', $item);
38 | $this->assertArrayHasKey('tradeTime', $item);
39 | }
40 | }
41 |
42 | /**
43 | * @dataProvider apiProvider
44 | * @param Fill $api
45 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
46 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
47 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
48 | */
49 | public function testGetRecentList(Fill $api)
50 | {
51 | $items = $api->getRecentList();
52 | $this->assertInternalType('array', $items);
53 | foreach ($items as $item) {
54 | $this->assertArrayHasKey('symbol', $item);
55 | $this->assertArrayHasKey('side', $item);
56 | $this->assertArrayHasKey('forceTaker', $item);
57 | $this->assertArrayHasKey('orderId', $item);
58 | $this->assertArrayHasKey('fee', $item);
59 | $this->assertArrayHasKey('liquidity', $item);
60 | $this->assertArrayHasKey('feeRate', $item);
61 | $this->assertArrayHasKey('createdAt', $item);
62 | $this->assertArrayHasKey('size', $item);
63 | $this->assertArrayHasKey('stop', $item);
64 | $this->assertArrayHasKey('price', $item);
65 | $this->assertArrayHasKey('tradeId', $item);
66 | $this->assertArrayHasKey('settleCurrency', $item);
67 | $this->assertArrayHasKey('tradeTime', $item);
68 | }
69 | }
70 |
71 |
72 | /**
73 | *
74 | * @dataProvider apiProvider
75 | * @param Fill $api
76 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
77 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
78 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
79 | */
80 | public function testGetFundingHistory(Fill $api)
81 | {
82 | $params = [
83 | 'symbol' => 'XBTUSDM'
84 | ];
85 | $data = $api->getFundingHistory($params);
86 | $this->assertInternalType('array', $data);
87 | foreach ($data['dataList'] as $item) {
88 | $this->assertArrayHasKey('symbol', $item);
89 | $this->assertArrayHasKey('fundingRate', $item);
90 | $this->assertArrayHasKey('timePoint', $item);
91 | $this->assertArrayHasKey('markPrice', $item);
92 | $this->assertArrayHasKey('positionQty', $item);
93 | $this->assertArrayHasKey('positionCost', $item);
94 | $this->assertArrayHasKey('funding', $item);
95 | $this->assertArrayHasKey('settleCurrency', $item);
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/tests/WithdrawalTest.php:
--------------------------------------------------------------------------------
1 | getQuotas('XBT');
22 | $this->assertInternalType('array', $data);
23 | $this->assertArrayHasKey('limitAmount', $data);
24 | $this->assertArrayHasKey('withdrawMinFee', $data);
25 | $this->assertArrayHasKey('innerWithdrawMinFee', $data);
26 | $this->assertArrayHasKey('usedAmount', $data);
27 | $this->assertArrayHasKey('availableAmount', $data);
28 | $this->assertArrayHasKey('remainAmount', $data);
29 | $this->assertArrayHasKey('precision', $data);
30 | $this->assertArrayHasKey('currency', $data);
31 | $this->assertArrayHasKey('isWithdrawEnabled', $data);
32 | $this->assertArrayHasKey('withdrawMinSize', $data);
33 | }
34 |
35 | /**
36 | * @dataProvider apiProvider
37 | * @param Withdrawal $api
38 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
39 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
40 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
41 | */
42 | public function testApply(Withdrawal $api)
43 | {
44 | $params = [
45 | 'currency' => 'USDT',
46 | 'address' => '1BcTdvq6Qdh7GnviHTYHq4tBvU32FfUbGz',
47 | 'amount' => 0.3,
48 | 'remark' => 'test apply withdrawal',
49 | 'chain' => 'OMNI'
50 | ];
51 | $data = $api->apply($params);
52 | $this->assertInternalType('array', $data);
53 | $this->assertArrayHasKey('withdrawId', $data);
54 | }
55 |
56 |
57 | /**
58 | * @dataProvider apiProvider
59 | * @param Withdrawal $api
60 | * @return array
61 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
62 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
63 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
64 | */
65 | public function testGetList(Withdrawal $api)
66 | {
67 | $params = [
68 | 'currency' => 'BTC',
69 | ];
70 | $pagination = [
71 | 'currentPage' => 1,
72 | 'pageSize' => 10,
73 | ];
74 | $data = $api->getList($params, $pagination);
75 | $this->assertPagination($data);
76 | foreach ($data['items'] as $item) {
77 | $this->assertInternalType('array', $item);
78 | $this->assertArrayHasKey('withdrawalId', $item);
79 | $this->assertArrayHasKey('walletTxId', $item);
80 | $this->assertArrayHasKey('address', $item);
81 | $this->assertArrayHasKey('memo', $item);
82 | $this->assertArrayHasKey('currency', $item);
83 | $this->assertArrayHasKey('amount', $item);
84 | $this->assertArrayHasKey('fee', $item);
85 | $this->assertArrayHasKey('isInner', $item);
86 | $this->assertArrayHasKey('status', $item);
87 | $this->assertArrayHasKey('createdAt', $item);
88 | }
89 | }
90 |
91 | /**
92 | * @dataProvider apiProvider
93 | * @param Withdrawal $api
94 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
95 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
96 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
97 | */
98 | public function testCancel(Withdrawal $api)
99 | {
100 | $data = $api->cancel('5c1cb7bb03aa6774239b772c');
101 | $this->assertInternalType('array', $data);
102 | $this->assertArrayHasKey('cancelledWithdrawIds', $data);
103 | }
104 | }
--------------------------------------------------------------------------------
/src/Http/Request.php:
--------------------------------------------------------------------------------
1 | method;
53 | }
54 |
55 | /**
56 | * @param string $method Request::METHOD_XXX
57 | */
58 | public function setMethod($method)
59 | {
60 | $this->method = strtoupper($method);
61 | }
62 |
63 | /**
64 | * @return string
65 | */
66 | public function getBaseUri()
67 | {
68 | return $this->baseUri;
69 | }
70 |
71 | /**
72 | * @param string $baseUri
73 | */
74 | public function setBaseUri($baseUri)
75 | {
76 | $this->baseUri = $baseUri ? rtrim($baseUri, '/') : null;
77 | }
78 |
79 | /**
80 | * @return string
81 | */
82 | public function getUri()
83 | {
84 | return $this->uri;
85 | }
86 |
87 | /**
88 | * @param string $uri
89 | */
90 | public function setUri($uri)
91 | {
92 | $this->uri = rtrim($uri, '/');
93 | }
94 |
95 | /**
96 | * @return string
97 | */
98 | public function getRequestUri()
99 | {
100 | if ($this->requestUri) {
101 | return $this->requestUri;
102 | }
103 |
104 | // GET/DELETE: move parameters into query
105 | if ($this->isGetOrDeleteMethod() && !empty($this->params)) {
106 | $query = http_build_query($this->params);
107 | if ($query !== '') {
108 | $this->uri .= strpos($this->uri, '?') === false ? '?' : '&';
109 | $this->uri .= $query;
110 | }
111 | }
112 |
113 | $url = $this->baseUri . $this->uri;
114 | $this->requestUri = substr($url, strpos($url, '/', 8));
115 | return $this->requestUri;
116 | }
117 |
118 | /**
119 | * @return array
120 | */
121 | public function getHeaders()
122 | {
123 | return $this->headers;
124 | }
125 |
126 | /**
127 | * @param array $headers
128 | */
129 | public function setHeaders($headers)
130 | {
131 | $this->headers = $headers;
132 | }
133 |
134 | /**
135 | * @return array
136 | */
137 | public function getParams()
138 | {
139 | return $this->params;
140 | }
141 |
142 | /**
143 | * @param array $params
144 | */
145 | public function setParams(array $params)
146 | {
147 | $this->params = $params;
148 | }
149 |
150 | /**
151 | * @return string
152 | */
153 | public function getBodyParams()
154 | {
155 | if ($this->bodyParams === null) {
156 | if ($this->isGetOrDeleteMethod()) {
157 | $this->bodyParams = '';
158 | } else {
159 | $this->bodyParams = empty($this->params) ? '' : json_encode($this->params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
160 | }
161 | }
162 | return $this->bodyParams;
163 | }
164 |
165 | protected function isGetOrDeleteMethod()
166 | {
167 | return in_array($this->getMethod(), [self::METHOD_GET, self::METHOD_DELETE], true);
168 | }
169 |
170 | public function __toString()
171 | {
172 | $str = $this->getMethod() . ' ' . $this->getRequestUri();
173 | $str .= ' with headers=' . json_encode($this->getHeaders(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
174 | $str .= ' with body=' . $this->getBodyParams();
175 | return $str;
176 | }
177 | }
--------------------------------------------------------------------------------
/tests/IndexTest.php:
--------------------------------------------------------------------------------
1 | easy@kucoin.com
4 | * Date: 2019/6/17 下午3:08
5 | */
6 |
7 | namespace KuCoin\Futures\SDK\Tests;
8 |
9 | use \KuCoin\Futures\SDK\PublicApi\Index;
10 |
11 |
12 | class IndexTest extends TestCase
13 | {
14 |
15 | protected $apiClass = Index::class;
16 | protected $apiWithAuth = false;
17 |
18 | /**
19 | *
20 | * @dataProvider apiProvider
21 | * @param Index $api
22 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
23 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
24 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
25 | */
26 | public function testGetList(Index $api)
27 | {
28 | $params = [
29 | 'symbol' => '.BXBT'
30 | ];
31 | $data = $api->getList($params);
32 | $this->assertInternalType('array', $data);
33 | foreach ($data['dataList'] as $item) {
34 | $this->assertArrayHasKey('symbol', $item);
35 | $this->assertArrayHasKey('granularity', $item);
36 | $this->assertArrayHasKey('timePoint', $item);
37 | $this->assertArrayHasKey('value', $item);
38 | $this->assertArrayHasKey('decomposionList', $item);
39 | }
40 | }
41 |
42 | /**
43 | *
44 | * @dataProvider apiProvider
45 | * @param Index $api
46 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
47 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
48 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
49 | */
50 | public function testGetInterests(Index $api)
51 | {
52 | $params = [
53 | 'symbol' => '.XBTINT'
54 | ];
55 | $data = $api->getInterests($params);
56 | $this->assertInternalType('array', $data);
57 | foreach ($data['dataList'] as $item) {
58 | $this->assertArrayHasKey('symbol', $item);
59 | $this->assertArrayHasKey('granularity', $item);
60 | $this->assertArrayHasKey('timePoint', $item);
61 | $this->assertArrayHasKey('value', $item);
62 | }
63 | }
64 |
65 | /**
66 | *
67 | * @dataProvider apiProvider
68 | * @param Index $api
69 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
70 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
71 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
72 | */
73 | public function testGetMarkPrice(Index $api)
74 | {
75 | $data = $api->getMarkPrice('XBTUSDM');
76 | $this->assertInternalType('array', $data);
77 | $this->assertArrayHasKey('symbol', $data);
78 | $this->assertArrayHasKey('granularity', $data);
79 | $this->assertArrayHasKey('timePoint', $data);
80 | $this->assertArrayHasKey('value', $data);
81 | $this->assertArrayHasKey('indexPrice', $data);
82 | }
83 |
84 | /**
85 | *
86 | * @dataProvider apiProvider
87 | * @param Index $api
88 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
89 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
90 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
91 | */
92 | public function testGetPremium(Index $api)
93 | {
94 | $params = [
95 | 'symbol' => '.BXBT'
96 | ];
97 | $data = $api->getPremium($params);
98 | $this->assertInternalType('array', $data);
99 | foreach ($data['dataList'] as $item) {
100 | $this->assertArrayHasKey('symbol', $item);
101 | $this->assertArrayHasKey('granularity', $item);
102 | $this->assertArrayHasKey('timePoint', $item);
103 | $this->assertArrayHasKey('value', $item);
104 | }
105 | }
106 |
107 | /**
108 | *
109 | * @dataProvider apiProvider
110 | * @param Index $api
111 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
112 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
113 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
114 | */
115 | public function testGetCurrentFundingRate(Index $api)
116 | {
117 | $data = $api->getCurrentFundingRate('.XBTUSDMFPI8H');
118 | $this->assertInternalType('array', $data);
119 | $this->assertArrayHasKey('symbol', $data);
120 | $this->assertArrayHasKey('granularity', $data);
121 | $this->assertArrayHasKey('timePoint', $data);
122 | $this->assertArrayHasKey('value', $data);
123 | $this->assertArrayHasKey('predictedValue', $data);
124 | }
125 |
126 | }
--------------------------------------------------------------------------------
/src/Api.php:
--------------------------------------------------------------------------------
1 | &self::$skipVerifyTls]);
75 | }
76 | $this->auth = $auth;
77 | $this->http = $http;
78 | }
79 |
80 | /**
81 | * @return string
82 | */
83 | public static function getBaseUri()
84 | {
85 | return static::$baseUri;
86 | }
87 |
88 | /**
89 | * @param string $baseUri
90 | */
91 | public static function setBaseUri($baseUri)
92 | {
93 | static::$baseUri = $baseUri;
94 | }
95 |
96 | /**
97 | * @return bool
98 | */
99 | public static function isSkipVerifyTls()
100 | {
101 | return static::$skipVerifyTls;
102 | }
103 |
104 | /**
105 | * @param bool $skipVerifyTls
106 | */
107 | public static function setSkipVerifyTls($skipVerifyTls)
108 | {
109 | static::$skipVerifyTls = $skipVerifyTls;
110 | }
111 |
112 | /**
113 | * @return bool
114 | */
115 | public static function isDebugMode()
116 | {
117 | return self::$debugMode;
118 | }
119 |
120 | /**
121 | * @param bool $debugMode
122 | */
123 | public static function setDebugMode($debugMode)
124 | {
125 | self::$debugMode = $debugMode;
126 | }
127 |
128 | /**
129 | * @param LoggerInterface $logger
130 | */
131 | public static function setLogger(LoggerInterface $logger)
132 | {
133 | self::$logger = $logger;
134 | }
135 |
136 | /**
137 | * @return Logger|LoggerInterface
138 | * @throws \Exception
139 | */
140 | public static function getLogger()
141 | {
142 | if (self::$logger === null) {
143 | self::$logger = new Logger('kucoin-futures-sdk');
144 | $handler = new RotatingFileHandler(static::getLogPath() . '/kucoin-futures.log', 0, static::$logLevel);
145 | $formatter = new LineFormatter(null, null, false, true);
146 | $handler->setFormatter($formatter);
147 | self::$logger->pushHandler($handler);
148 | }
149 | return self::$logger;
150 | }
151 |
152 | /**
153 | * @return string
154 | */
155 | public static function getLogPath()
156 | {
157 | return self::$logPath;
158 | }
159 |
160 | /**
161 | * @param string $logPath
162 | */
163 | public static function setLogPath($logPath)
164 | {
165 | self::$logPath = $logPath;
166 | }
167 |
168 | /**
169 | * @return int
170 | */
171 | public static function getLogLevel()
172 | {
173 | return self::$logLevel;
174 | }
175 |
176 | /**
177 | * @param int $logLevel
178 | */
179 | public static function setLogLevel($logLevel)
180 | {
181 | self::$logLevel = $logLevel;
182 | }
183 |
184 | /**
185 | * @param array $headers
186 | */
187 | public static function setCustomHeaders(array $headers)
188 | {
189 | self::$customHeaders = $headers;
190 | }
191 |
192 | /**
193 | * @return array
194 | */
195 | public static function getCustomHeaders()
196 | {
197 | return self::$customHeaders;
198 | }
199 |
200 | /**
201 | * @param string $method
202 | * @param string $uri
203 | * @param array $params
204 | * @param array $headers
205 | * @param int $timeout
206 | * @return Response
207 | * @throws Exceptions\HttpException
208 | * @throws Exceptions\InvalidApiUriException
209 | */
210 | public function call($method, $uri, array $params = [], array $headers = [], $timeout = 30)
211 | {
212 | $request = new Request();
213 | $request->setMethod($method);
214 | $request->setBaseUri(static::getBaseUri());
215 | $request->setUri($uri);
216 | $request->setParams($params);
217 |
218 | if ($this->auth) {
219 | $authHeaders = $this->auth->getHeaders(
220 | $request->getMethod(),
221 | $request->getRequestUri(),
222 | $request->getBodyParams()
223 | );
224 | $headers = array_merge($headers, $authHeaders);
225 | }
226 | $headers['User-Agent'] = 'KuCoin-Futures-PHP-SDK/' . static::VERSION;
227 |
228 | if (self::$customHeaders) {
229 | $headers = array_merge($headers, self::$customHeaders);
230 | }
231 |
232 | $request->setHeaders($headers);
233 |
234 | $requestId = uniqid();
235 |
236 | if (self::isDebugMode()) {
237 | static::getLogger()->debug(sprintf('Sent a HTTP request#%s: %s', $requestId, $request));
238 | }
239 | $requestStart = microtime(true);
240 | $response = $this->http->request($request, $timeout);
241 | if (self::isDebugMode()) {
242 | $cost = (microtime(true) - $requestStart) * 1000;
243 | static::getLogger()->debug(sprintf('Received a HTTP response#%s: cost %.2fms, %s', $requestId, $cost, $response));
244 | }
245 |
246 | return $response;
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/src/PublicApi/Symbol.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/ticker', compact('symbol'));
27 | return $response->getApiData();
28 | }
29 |
30 | /**
31 | * Get the snapshot details of a symbol.
32 | *
33 | * @param string $symbol
34 | * @return array
35 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
36 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
38 | */
39 | public function getLevel2Snapshot($symbol)
40 | {
41 | $response = $this->call(Request::METHOD_GET, '/api/v1/level2/snapshot', compact('symbol'));
42 | return $response->getApiData();
43 | }
44 |
45 | /**
46 | * Get the snapshot details of a symbol.
47 | *
48 | * @param string $symbol
49 | * @return array
50 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
51 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
52 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
53 | */
54 | public function getLevel3Snapshot($symbol)
55 | {
56 | $response = $this->call(Request::METHOD_GET, '/api/v1/level3/snapshot', compact('symbol'));
57 | return $response->getApiData();
58 | }
59 |
60 | /**
61 | * Get the snapshot details of a symbol.
62 | *
63 | * @param string $symbol
64 | * @return array
65 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
66 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
67 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
68 | */
69 | public function getV2Level3Snapshot($symbol)
70 | {
71 | $response = $this->call(Request::METHOD_GET, '/api/v2/level3/snapshot', compact('symbol'));
72 | return $response->getApiData();
73 | }
74 |
75 | /**
76 | * Get the level2 message of a symbol.
77 | *
78 | * @param string $symbol
79 | * @param int $start
80 | * @param int $end
81 | * @return array
82 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
83 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
84 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
85 | * @deprecated
86 | */
87 | public function getLevel2Message($symbol, $start, $end)
88 | {
89 | $response = $this->call(Request::METHOD_GET, '/api/v1/level2/message/query',
90 | compact('symbol', 'start', 'end')
91 | );
92 | return $response->getApiData();
93 | }
94 |
95 | /**
96 | * Get the level3 message of a symbol.
97 | * @param string $symbol
98 | * @param int $start
99 | * @param int $end
100 | * @return array
101 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
102 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
103 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
104 | * @deprecated
105 | */
106 | public function getLevel3Message($symbol, $start, $end)
107 | {
108 | $response = $this->call(Request::METHOD_GET, '/api/v1/level3/message/query',
109 | compact('symbol', 'start', 'end')
110 | );
111 | return $response->getApiData();
112 | }
113 |
114 | /**
115 | * Get the trade history details of a symbol.
116 | *
117 | * @param string $symbol
118 | * @return array
119 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
120 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
121 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
122 | */
123 | public function getTradeHistory($symbol)
124 | {
125 | $response = $this->call(Request::METHOD_GET, '/api/v1/trade/history', compact('symbol'));
126 | return $response->getApiData();
127 | }
128 |
129 | /**
130 | * Get KLines for a symbol. Data are returned in grouped buckets based on granularity.
131 | *
132 | * The granularity (granularity parameter of K-line) represents the number of minutes,
133 | * the available granularity scope is: 1,5,15,30,60,120,240,480,720,1440,10080.
134 | *
135 | * @param string $symbol
136 | * @param int $from
137 | * @param int $to
138 | * @param int $granularity
139 | * @return array
140 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
141 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
142 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
143 | */
144 | public function getKLines($symbol, $from, $to, $granularity)
145 | {
146 | $response = $this->call(
147 | Request::METHOD_GET,
148 | '/api/v1/kline/query',
149 | compact('symbol', 'from', 'to', 'granularity')
150 | );
151 | return $response->getApiData();
152 | }
153 |
154 | /**
155 | * Get the depth20 of level2.
156 | * @param string $symbol
157 | * @return mixed
158 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
159 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
160 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
161 | */
162 | public function getLevel2Depth20($symbol)
163 | {
164 | $response = $this->call(Request::METHOD_GET, '/api/v1/level2/depth20', ['symbol' => $symbol]);
165 | return $response->getApiData();
166 | }
167 |
168 | /**
169 | * Get the depth100 of level2.
170 | * @param string $symbol
171 | * @return mixed
172 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
173 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
174 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
175 | */
176 | public function getLevel2Depth100($symbol)
177 | {
178 | $response = $this->call(Request::METHOD_GET, '/api/v1/level2/depth100', ['symbol' => $symbol]);
179 | return $response->getApiData();
180 | }
181 |
182 | /**
183 | * Get Public Funding History.
184 | *
185 | * @param $symbol
186 | * @param $from
187 | * @param $to
188 | * @return mixed|null
189 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
190 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
191 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
192 | */
193 | public function getFundingRates($symbol, $from, $to)
194 | {
195 | $params = compact('symbol', 'from', 'to');
196 | $response = $this->call(Request::METHOD_GET, '/api/v1/contract/funding-rates', $params);
197 | return $response->getApiData();
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/tests/SymbolTest.php:
--------------------------------------------------------------------------------
1 | getTicker('XBTUSDM');
23 | $this->assertInternalType('array', $data);
24 | $this->assertArrayHasKey('sequence', $data);
25 | $this->assertArrayHasKey('symbol', $data);
26 | $this->assertArrayHasKey('size', $data);
27 | $this->assertArrayHasKey('price', $data);
28 | $this->assertArrayHasKey('bestBidSize', $data);
29 | $this->assertArrayHasKey('bestAskSize', $data);
30 | $this->assertArrayHasKey('ts', $data);
31 | }
32 |
33 | /**
34 | * @dataProvider apiProvider
35 | * @param Symbol $api
36 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
38 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
39 | */
40 | public function testGetLevel2Snapshot(Symbol $api)
41 | {
42 | $data = $api->getLevel2Snapshot('XBTUSDM');
43 | $this->assertInternalType('array', $data);
44 | $this->assertArrayHasKey('sequence', $data);
45 | $this->assertArrayHasKey('symbol', $data);
46 | $this->assertArrayHasKey('asks', $data);
47 | $this->assertArrayHasKey('bids', $data);
48 | }
49 |
50 | /**
51 | * @dataProvider apiProvider
52 | * @param Symbol $api
53 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
54 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
55 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
56 | */
57 | public function testGetLevel3Snapshot(Symbol $api)
58 | {
59 | $data = $api->getLevel3Snapshot('XBTUSDM');
60 | $this->assertInternalType('array', $data);
61 | $this->assertArrayHasKey('sequence', $data);
62 | $this->assertArrayHasKey('symbol', $data);
63 | $this->assertArrayHasKey('asks', $data);
64 | $this->assertArrayHasKey('bids', $data);
65 | }
66 |
67 | /**
68 | * @dataProvider apiProvider
69 | * @param Symbol $api
70 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
71 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
72 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
73 | */
74 | public function testGetV2Level3Snapshot(Symbol $api)
75 | {
76 | $data = $api->getV2Level3Snapshot('XBTUSDM');
77 | $this->assertInternalType('array', $data);
78 | $this->assertArrayHasKey('sequence', $data);
79 | $this->assertArrayHasKey('symbol', $data);
80 | $this->assertArrayHasKey('asks', $data);
81 | $this->assertArrayHasKey('bids', $data);
82 | $this->assertArrayHasKey('ts', $data);
83 | }
84 |
85 | /**
86 | * @dataProvider apiProvider
87 | * @param Symbol $api
88 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
89 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
90 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
91 | */
92 | public function testGetLevel2Message(Symbol $api)
93 | {
94 | $data = $api->getLevel2Message('XBTUSDM', 1, 100);
95 | $this->assertInternalType('array', $data);
96 | foreach ($data as $item) {
97 | $this->assertArrayHasKey('symbol', $item);
98 | $this->assertArrayHasKey('sequence', $item);
99 | $this->assertArrayHasKey('change', $item);
100 | }
101 | }
102 |
103 | /**
104 | * @dataProvider apiProvider
105 | * @param Symbol $api
106 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
107 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
108 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
109 | */
110 | public function testGetLevel3Message(Symbol $api)
111 | {
112 | // $data = $api->getLevel3Message('XBTUSDM', 1, 100);
113 | // $this->assertInternalType('array', $data);
114 | // foreach ($data as $item) {
115 | // $this->assertArrayHasKey('symbol', $item);
116 | // $this->assertArrayHasKey('sequence', $item);
117 | // $this->assertArrayHasKey('orderId', $item);
118 | // $this->assertArrayHasKey('type', $item);
119 | // }
120 | }
121 |
122 | /**
123 | * @dataProvider apiProvider
124 | * @param Symbol $api
125 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
126 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
127 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
128 | */
129 | public function testGetTradeHistory(Symbol $api)
130 | {
131 | $data = $api->getTradeHistory('XBTUSDM');
132 | $this->assertInternalType('array', $data);
133 | foreach ($data as $item) {
134 | $this->assertArrayHasKey('sequence', $item);
135 | $this->assertArrayHasKey('tradeId', $item);
136 | $this->assertArrayHasKey('takerOrderId', $item);
137 | $this->assertArrayHasKey('makerOrderId', $item);
138 | $this->assertArrayHasKey('price', $item);
139 | }
140 | }
141 |
142 | /**
143 | * @dataProvider apiProvider
144 | * @param Symbol $api
145 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
146 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
147 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
148 | */
149 | public function testGetLevel2Depth20(Symbol $api)
150 | {
151 | $data = $api->getLevel2Depth20('XBTUSDM');
152 |
153 | $this->assertInternalType('array', $data);
154 | $this->assertArrayHasKey('symbol', $data);
155 | $this->assertArrayHasKey('sequence', $data);
156 | $this->assertArrayHasKey('asks', $data);
157 | $this->assertInternalType('array', $data['asks']);
158 | $this->assertInternalType('array', $data['bids']);
159 | }
160 |
161 | /**
162 | * @dataProvider apiProvider
163 | * @param Symbol $api
164 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
165 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
166 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
167 | */
168 | public function testGetLevel2Depth100(Symbol $api)
169 | {
170 | $data = $api->getLevel2Depth100('XBTUSDM');
171 |
172 | $this->assertInternalType('array', $data);
173 | $this->assertArrayHasKey('symbol', $data);
174 | $this->assertArrayHasKey('sequence', $data);
175 | $this->assertArrayHasKey('asks', $data);
176 | $this->assertInternalType('array', $data['asks']);
177 | $this->assertInternalType('array', $data['bids']);
178 | }
179 |
180 | /**
181 | * @dataProvider apiProvider
182 | * @param Symbol $api
183 | * @return void
184 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
185 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
186 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
187 | */
188 | public function testGetFundingRates(Symbol $api)
189 | {
190 | $from = strtotime(date('Y-m-d', time() - 86400));
191 | $to = $from + 86400;
192 | $data = $api->getFundingRates('ETHUSDTM', $from * 1000, $to * 1000);
193 | $this->assertInternalType('array', $data);
194 | foreach ($data as $item) {
195 | $this->assertInternalType('array', $item);
196 | $this->assertArrayHasKey('symbol', $item);
197 | $this->assertArrayHasKey('fundingRate', $item);
198 | $this->assertArrayHasKey('timepoint', $item);
199 | }
200 | }
201 | }
--------------------------------------------------------------------------------
/src/PrivateApi/Account.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/account-overview', $params);
26 | return $response->getApiData();
27 | }
28 |
29 | /**
30 | * Get a transaction history of accounts.
31 | *
32 | * @param array $params
33 | * @param array $pagination
34 | * @return array
35 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
36 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
37 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
38 | */
39 | public function getTransactionHistory(array $params = [], array $pagination = [])
40 | {
41 | $response = $this->call(Request::METHOD_GET, '/api/v1/transaction-history', $params + $pagination);
42 | return $response->getApiData();
43 | }
44 |
45 | /**
46 | * KuCoin transfer to kuCoin futures account.
47 | * @param string amount
48 | * @return array
49 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
50 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
51 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
52 | */
53 | public function transferIn($amount)
54 | {
55 | $response = $this->call(Request::METHOD_POST, '/api/v1/transfer-in', compact('amount'));
56 | return $response->getApiData();
57 | }
58 |
59 | /**
60 | * kuCoin futures transfer to KuCoin account.
61 | *
62 | * @param string bizNo
63 | * @param string amount
64 | * @return array
65 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
66 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
67 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
68 | */
69 | public function transferOut($bizNo, $amount)
70 | {
71 | $response = $this->call(Request::METHOD_POST, '/api/v1/transfer-out', compact('bizNo', 'amount'));
72 | return $response->getApiData();
73 | }
74 |
75 | /**
76 | * Cancel an transfer out.
77 | * @param string $applyId
78 | * @return array
79 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
80 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
81 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
82 | * @deprecated
83 | */
84 | public function cancelTransferOut($applyId)
85 | {
86 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/cancel/transfer-out?applyId=' . $applyId);
87 | return $response->getApiData();
88 | }
89 |
90 | /**
91 | * Get a transfer list.
92 | *
93 | * @param array $params
94 | * @param array $pagination
95 | * @return array
96 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
97 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
98 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
99 | */
100 | public function getTransferList(array $params = [], array $pagination = [])
101 | {
102 | $response = $this->call(Request::METHOD_GET, '/api/v1/transfer-list', $params + $pagination);
103 | return $response->getApiData();
104 | }
105 |
106 | /**
107 | * kuCoin futures transfer to KuCoin account.
108 | * [It is recommended to call transferOutV3() instead]
109 | * @param string bizNo
110 | * @param string amount
111 | * @param string currency
112 | * @return array
113 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
114 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
115 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
116 | */
117 | public function transferOutV2($bizNo, $amount, $currency)
118 | {
119 | $response = $this->call(Request::METHOD_POST, '/api/v2/transfer-out', compact('bizNo', 'amount', 'currency'));
120 | return $response->getApiData();
121 | }
122 |
123 | /**
124 | * Get list of Futures APIs pertaining to a sub-accounts.
125 | *
126 | * @param array $params
127 | * @return array
128 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
129 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
130 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
131 | */
132 | public function getSubApikey(array $params)
133 | {
134 | $response = $this->call(Request::METHOD_GET, '/api/v1/sub/api-key', $params);
135 | return $response->getApiData();
136 | }
137 |
138 | /**
139 | * Create futures APIs for sub-accounts.
140 | *
141 | * @param array $params
142 | * @return array
143 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
144 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
145 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
146 | */
147 | public function createSubApikey(array $params)
148 | {
149 | $response = $this->call(Request::METHOD_POST, '/api/v1/sub/api-key', $params);
150 | return $response->getApiData();
151 | }
152 |
153 | /**
154 | * Modify futures APIs for sub-accounts.
155 | *
156 | * @param array $params
157 | * @return array
158 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
159 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
160 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
161 | */
162 | public function modifySubApikey(array $params)
163 | {
164 | $response = $this->call(Request::METHOD_POST, '/api/v1/sub/api-key/update', $params);
165 | return $response->getApiData();
166 | }
167 |
168 | /**
169 | * Delete futures APIs for sub-accounts.
170 | *
171 | * @param array $params
172 | * @return array
173 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
174 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
175 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
176 | */
177 | public function deleteSubApikey(array $params)
178 | {
179 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/sub/api-key', $params);
180 | return $response->getApiData();
181 | }
182 |
183 | /**
184 | * kuCoin futures transfer to KuCoin account.
185 | *
186 | * @param string recAccountType
187 | * @param string amount
188 | * @param string currency
189 | * @return array
190 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
191 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
192 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
193 | */
194 | public function transferOutV3($recAccountType, $amount, $currency)
195 | {
196 | $response = $this->call(Request::METHOD_POST, '/api/v3/transfer-out', compact('recAccountType', 'amount', 'currency'));
197 | return $response->getApiData();
198 | }
199 |
200 | /**
201 | * Get all account asset information.
202 | * @param string $currency
203 | * @return array
204 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
205 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
206 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
207 | */
208 | public function getAccountOverviewAll($currency)
209 | {
210 | $response = $this->call(Request::METHOD_GET, '/api/v1/account-overview-all', compact('currency'));
211 | return $response->getApiData();
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/src/PrivateApi/Position.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_GET, '/api/v1/positions');
26 | return $response->getApiData();
27 | }
28 |
29 | /**
30 | * Get the position details of a symbol.
31 | *
32 | * @param string $symbol
33 | * @return array
34 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
35 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
36 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
37 | */
38 | public function getDetail($symbol)
39 | {
40 | $response = $this->call(Request::METHOD_GET, '/api/v1/position', compact('symbol'));
41 | return $response->getApiData();
42 | }
43 |
44 | /**
45 | * Change auto append status.
46 | *
47 | * @param string $symbol
48 | * @param boolean $status
49 | * @return array
50 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
51 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
52 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
53 | */
54 | public function changeAutoAppendStatus($symbol, $status)
55 | {
56 | $response = $this->call(Request::METHOD_POST, '/api/v1/position/margin/auto-deposit-status',
57 | compact('symbol', 'status')
58 | );
59 | return $response->getApiData();
60 | }
61 |
62 | /**
63 | * Get whether to automatically add margin status.
64 | *
65 | * @deprecated
66 | *
67 | * @param string $symbol
68 | * @return array
69 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
70 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
71 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
72 | */
73 | public function getMarginAppend($symbol, $status)
74 | {
75 | $response = $this->call(Request::METHOD_GET, '/api/v1/position/margin/append',
76 | compact('symbol', 'status')
77 | );
78 | return $response->getApiData();
79 | }
80 |
81 | /**
82 | * Margin Append.
83 | *
84 | * @param array $params
85 | * @return array
86 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
87 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
88 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
89 | */
90 | public function marginAppend(array $params)
91 | {
92 | $response = $this->call(Request::METHOD_POST,
93 | '/api/v1/position/margin/deposit-margin', $params
94 | );
95 | return $response->getApiData();
96 | }
97 |
98 |
99 | /**
100 | * Get Max Withdraw Margin.
101 | *
102 | * @param $symbol
103 | * @return mixed|null
104 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
105 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
106 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
107 | */
108 | public function getMaxWithdrawMargin($symbol)
109 | {
110 | $response = $this->call(Request::METHOD_GET, '/api/v1/margin/maxWithdrawMargin', compact('symbol'));
111 | return $response->getApiData();
112 | }
113 |
114 | /**
115 | * Remove Margin Manually.
116 | *
117 | * @param $symbol
118 | * @param $withdrawAmount
119 | * @return mixed|null
120 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
121 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
122 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
123 | */
124 | public function withdrawMargin($symbol, $withdrawAmount)
125 | {
126 | $response = $this->call(Request::METHOD_POST, '/api/v1/margin/withdrawMargin', compact('symbol', 'withdrawAmount'));
127 | return $response->getApiData();
128 | }
129 |
130 | /**
131 | * Get Positions History.
132 | *
133 | * @param array $params
134 | * @return \KuCoin\Futures\SDK\Http\Response
135 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
136 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
137 | */
138 | public function getHistoryPositions(array $params)
139 | {
140 | $response = $this->call(Request::METHOD_GET, '/api/v1/history-positions', $params);
141 | return $response->getApiData();
142 | }
143 |
144 | /**
145 | * Get Maximum Open Position Size.
146 | *
147 | * @param $symbol
148 | * @param $price
149 | * @param $leverage
150 | * @return mixed|null
151 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
152 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
153 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
154 | */
155 | public function getMaxOpenSize($symbol, $price, $leverage)
156 | {
157 | $response = $this->call(Request::METHOD_GET, '/api/v2/getMaxOpenSize', compact('symbol', 'price', 'leverage'));
158 | return $response->getApiData();
159 | }
160 |
161 | /**
162 | * This interface can modify the current symbol’s cross-margin leverage multiple.
163 | *
164 | * @param $symbol
165 | * @param $leverage
166 | * @return mixed|null
167 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
168 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
169 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
170 | */
171 | public function modifyCrossUserLeverage($symbol, $leverage)
172 | {
173 | $response = $this->call(Request::METHOD_POST, '/api/v2/changeCrossUserLeverage', compact('symbol', 'leverage'));
174 | return $response->getApiData();
175 | }
176 |
177 | /**
178 | * This interface can query the current symbol’s cross-margin leverage multiple.
179 | *
180 | * @param $symbol
181 | * @return mixed|null
182 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
183 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
184 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
185 | */
186 | public function getCrossUserLeverage($symbol)
187 | {
188 | $response = $this->call(Request::METHOD_GET, '/api/v2/getCrossUserLeverage', compact('symbol'));
189 | return $response->getApiData();
190 | }
191 |
192 | /**
193 | * This interface can modify the margin mode of the current symbol
194 | *
195 | * @param $symbol
196 | * @param $marginMode
197 | * @return mixed|null
198 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
199 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
200 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
201 | */
202 | public function modifyMarginMode($symbol, $marginMode)
203 | {
204 | $response = $this->call(Request::METHOD_POST, '/api/v2/position/changeMarginMode', compact('symbol', 'marginMode'));
205 | return $response->getApiData();
206 | }
207 |
208 | /**
209 | * This interface can query the margin mode of the current symbol.
210 | *
211 | * @param $symbol
212 | * @return mixed|null
213 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
214 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
215 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
216 | */
217 | public function getMarginMode($symbol)
218 | {
219 | $response = $this->call(Request::METHOD_GET, '/api/v2/position/getMarginMode', compact('symbol'));
220 | return $response->getApiData();
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/tests/ContractTest.php:
--------------------------------------------------------------------------------
1 | easy@kucoin.com
4 | * Date: 2019/6/17 下午3:08
5 | */
6 |
7 | namespace KuCoin\Futures\SDK\Tests;
8 |
9 | use KuCoin\Futures\SDK\PublicApi\Contract;
10 |
11 |
12 | class ContractTest extends TestCase
13 | {
14 |
15 | protected $apiClass = Contract::class;
16 | protected $apiWithAuth = false;
17 |
18 | /**
19 | * @dataProvider apiProvider
20 | * @param Contract $api
21 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
22 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
23 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
24 | */
25 | public function testGetList(Contract $api)
26 | {
27 | $data = $api->getList();
28 | $this->assertInternalType('array', $data);
29 |
30 | foreach ($data as $item) {
31 | $this->assertInternalType('array', $item);
32 |
33 | $this->assertArrayHasKey('symbol', $item);
34 | $this->assertArrayHasKey('rootSymbol', $item);
35 | $this->assertArrayHasKey('type', $item);
36 | $this->assertArrayHasKey('firstOpenDate', $item);
37 | $this->assertArrayHasKey('expireDate', $item);
38 | $this->assertArrayHasKey('settleDate', $item);
39 | $this->assertArrayHasKey('baseCurrency', $item);
40 | $this->assertArrayHasKey('quoteCurrency', $item);
41 | $this->assertArrayHasKey('settleCurrency', $item);
42 | $this->assertArrayHasKey('maxOrderQty', $item);
43 | $this->assertArrayHasKey('maxPrice', $item);
44 | $this->assertArrayHasKey('lotSize', $item);
45 | $this->assertArrayHasKey('tickSize', $item);
46 | $this->assertArrayHasKey('indexPriceTickSize', $item);
47 | $this->assertArrayHasKey('multiplier', $item);
48 | $this->assertArrayHasKey('initialMargin', $item);
49 | $this->assertArrayHasKey('maintainMargin', $item);
50 | $this->assertArrayHasKey('maxRiskLimit', $item);
51 | $this->assertArrayHasKey('minRiskLimit', $item);
52 | $this->assertArrayHasKey('riskStep', $item);
53 | $this->assertArrayHasKey('makerFeeRate', $item);
54 | $this->assertArrayHasKey('takerFeeRate', $item);
55 | $this->assertArrayHasKey('takerFixFee', $item);
56 | $this->assertArrayHasKey('makerFixFee', $item);
57 | $this->assertArrayHasKey('settlementFee', $item);
58 | $this->assertArrayHasKey('isDeleverage', $item);
59 | $this->assertArrayHasKey('isQuanto', $item);
60 | $this->assertArrayHasKey('isInverse', $item);
61 | $this->assertArrayHasKey('markMethod', $item);
62 | $this->assertArrayHasKey('fairMethod', $item);
63 | $this->assertArrayHasKey('fundingBaseSymbol', $item);
64 | $this->assertArrayHasKey('fundingQuoteSymbol', $item);
65 | $this->assertArrayHasKey('fundingRateSymbol', $item);
66 | $this->assertArrayHasKey('indexSymbol', $item);
67 | $this->assertArrayHasKey('settlementSymbol', $item);
68 | $this->assertArrayHasKey('status', $item);
69 | $this->assertArrayHasKey('fundingFeeRate', $item);
70 | $this->assertArrayHasKey('predictedFundingFeeRate', $item);
71 | $this->assertArrayHasKey('openInterest', $item);
72 | $this->assertArrayHasKey('turnoverOf24h', $item);
73 | $this->assertArrayHasKey('volumeOf24h', $item);
74 | $this->assertArrayHasKey('markPrice', $item);
75 | $this->assertArrayHasKey('indexPrice', $item);
76 | $this->assertArrayHasKey('lastTradePrice', $item);
77 | $this->assertArrayHasKey('nextFundingRateTime', $item);
78 | $this->assertArrayHasKey('maxLeverage', $item);
79 | $this->assertArrayHasKey('lowPrice', $item);
80 | $this->assertArrayHasKey('highPrice', $item);
81 | $this->assertArrayHasKey('priceChgPct', $item);
82 | $this->assertArrayHasKey('priceChg', $item);
83 | }
84 | }
85 |
86 | /**
87 | * @dataProvider apiProvider
88 | * @param Contract $api
89 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
90 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
91 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
92 | */
93 | public function testGetDetail(Contract $api)
94 | {
95 | $data = $api->getDetail('XBTUSDM');
96 | $this->assertInternalType('array', $data);
97 |
98 | $this->assertArrayHasKey('symbol', $data);
99 | $this->assertArrayHasKey('rootSymbol', $data);
100 | $this->assertArrayHasKey('type', $data);
101 | $this->assertArrayHasKey('firstOpenDate', $data);
102 | $this->assertArrayHasKey('expireDate', $data);
103 | $this->assertArrayHasKey('settleDate', $data);
104 | $this->assertArrayHasKey('baseCurrency', $data);
105 | $this->assertArrayHasKey('quoteCurrency', $data);
106 | $this->assertArrayHasKey('settleCurrency', $data);
107 | $this->assertArrayHasKey('maxOrderQty', $data);
108 | $this->assertArrayHasKey('maxPrice', $data);
109 | $this->assertArrayHasKey('lotSize', $data);
110 | $this->assertArrayHasKey('tickSize', $data);
111 | $this->assertArrayHasKey('indexPriceTickSize', $data);
112 | $this->assertArrayHasKey('multiplier', $data);
113 | $this->assertArrayHasKey('initialMargin', $data);
114 | $this->assertArrayHasKey('maintainMargin', $data);
115 | $this->assertArrayHasKey('maxRiskLimit', $data);
116 | $this->assertArrayHasKey('minRiskLimit', $data);
117 | $this->assertArrayHasKey('riskStep', $data);
118 | $this->assertArrayHasKey('makerFeeRate', $data);
119 | $this->assertArrayHasKey('takerFeeRate', $data);
120 | $this->assertArrayHasKey('takerFixFee', $data);
121 | $this->assertArrayHasKey('makerFixFee', $data);
122 | $this->assertArrayHasKey('settlementFee', $data);
123 | $this->assertArrayHasKey('isDeleverage', $data);
124 | $this->assertArrayHasKey('isQuanto', $data);
125 | $this->assertArrayHasKey('isInverse', $data);
126 | $this->assertArrayHasKey('markMethod', $data);
127 | $this->assertArrayHasKey('fairMethod', $data);
128 | $this->assertArrayHasKey('fundingBaseSymbol', $data);
129 | $this->assertArrayHasKey('fundingQuoteSymbol', $data);
130 | $this->assertArrayHasKey('fundingRateSymbol', $data);
131 | $this->assertArrayHasKey('indexSymbol', $data);
132 | $this->assertArrayHasKey('settlementSymbol', $data);
133 | $this->assertArrayHasKey('status', $data);
134 | $this->assertArrayHasKey('fundingFeeRate', $data);
135 | $this->assertArrayHasKey('predictedFundingFeeRate', $data);
136 | $this->assertArrayHasKey('openInterest', $data);
137 | $this->assertArrayHasKey('turnoverOf24h', $data);
138 | $this->assertArrayHasKey('volumeOf24h', $data);
139 | $this->assertArrayHasKey('markPrice', $data);
140 | $this->assertArrayHasKey('indexPrice', $data);
141 | $this->assertArrayHasKey('lastTradePrice', $data);
142 | $this->assertArrayHasKey('nextFundingRateTime', $data);
143 | $this->assertArrayHasKey('maxLeverage', $data);
144 | $this->assertArrayHasKey('lowPrice', $data);
145 | $this->assertArrayHasKey('highPrice', $data);
146 | $this->assertArrayHasKey('priceChgPct', $data);
147 | $this->assertArrayHasKey('priceChg', $data);
148 | }
149 |
150 | /**
151 | * @dataProvider apiProvider
152 | *
153 | * @param Contract $api
154 | * @return void
155 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
156 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
157 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
158 | */
159 | public function testGetAllTickers(Contract $api)
160 | {
161 | $data = $api->getAllTickers();
162 | $this->assertInternalType('array', $data);
163 | foreach ($data as $item) {
164 | $this->assertArrayHasKey('symbol', $item);
165 | $this->assertArrayHasKey('sequence', $item);
166 | $this->assertArrayHasKey('side', $item);
167 | $this->assertArrayHasKey('size', $item);
168 | $this->assertArrayHasKey('tradeId', $item);
169 | $this->assertArrayHasKey('price', $item);
170 | $this->assertArrayHasKey('bestBidPrice', $item);
171 | $this->assertArrayHasKey('bestBidSize', $item);
172 | $this->assertArrayHasKey('bestAskPrice', $item);
173 | $this->assertArrayHasKey('bestAskSize', $item);
174 | $this->assertArrayHasKey('ts', $item);
175 | }
176 | }
177 | }
--------------------------------------------------------------------------------
/src/PrivateApi/Order.php:
--------------------------------------------------------------------------------
1 | call(Request::METHOD_POST, '/api/v1/orders', $order);
30 | return $response->getApiData();
31 | }
32 |
33 | /**
34 | * Cancel an order.
35 | *
36 | * @param string $orderId
37 | * @return array
38 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
39 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
40 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
41 | */
42 | public function cancel($orderId)
43 | {
44 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/orders/' . $orderId);
45 | return $response->getApiData();
46 | }
47 |
48 | /**
49 | * Batch cancel orders.
50 | *
51 | * @param string|null $symbol
52 | * @return array
53 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
54 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
55 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
56 | */
57 | public function batchCancel($symbol = null)
58 | {
59 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/orders', compact('symbol'));
60 | return $response->getApiData();
61 | }
62 |
63 | /**
64 | * Batch cancel stop orders.
65 | *
66 | * @param string|null $symbol
67 | * @return array
68 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
69 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
70 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
71 | */
72 | public function stopOrders($symbol = null)
73 | {
74 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/stopOrders', compact('symbol'));
75 | return $response->getApiData();
76 | }
77 |
78 | /**
79 | * List orders.
80 | *
81 | * @param array $params
82 | * @param array $pagination
83 | * @return array
84 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
85 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
86 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
87 | */
88 | public function getList(array $params = [], array $pagination = [])
89 | {
90 | $response = $this->call(Request::METHOD_GET, '/api/v1/orders', $params + $pagination);
91 | return $response->getApiData();
92 | }
93 |
94 | /**
95 | * Stop orders list.
96 | *
97 | * @param array $params
98 | * @param array $pagination
99 | * @return array
100 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
101 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
102 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
103 | */
104 | public function getStopOrders(array $params = [], array $pagination = [])
105 | {
106 | $response = $this->call(Request::METHOD_GET, '/api/v1/stopOrders', $params + $pagination);
107 | return $response->getApiData();
108 | }
109 |
110 | /**
111 | * 24 hour done of orders.
112 | *
113 | * @param array $params
114 | * @param array $pagination
115 | * @return array
116 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
117 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
118 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
119 | */
120 | public function getRecentDoneOrders(array $params = [], array $pagination = [])
121 | {
122 | $response = $this->call(Request::METHOD_GET, '/api/v1/recentDoneOrders', $params + $pagination);
123 | return $response->getApiData();
124 | }
125 |
126 | /**
127 | * Get an order.
128 | *
129 | * @param string $orderId
130 | * @return array
131 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
132 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
133 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
134 | */
135 | public function getDetail($orderId)
136 | {
137 | $response = $this->call(Request::METHOD_GET, '/api/v1/orders/' . $orderId, []);
138 | return $response->getApiData();
139 | }
140 |
141 | /**
142 | * Get open order statistics.
143 | *
144 | * @param string|null $symbol
145 | * @return array
146 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
147 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
148 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
149 | */
150 | public function getOpenOrderStatistics($symbol = null)
151 | {
152 | $response = $this->call(Request::METHOD_GET, '/api/v1/openOrderStatistics', compact('symbol'));
153 | return $response->getApiData();
154 | }
155 |
156 | /**
157 | * Get an order By ClientOid.
158 | *
159 | * @param $clientOid
160 | * @return array
161 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
162 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
163 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
164 | */
165 | public function getDetailByClientOid($clientOid)
166 | {
167 | $response = $this->call(Request::METHOD_GET, '/api/v1/orders/byClientOid', ['clientOid' => $clientOid]);
168 | return $response->getApiData();
169 | }
170 |
171 | /**
172 | * Cancel Order by clientOid.
173 | *
174 | * @param $clientOid
175 | * @param $symbol
176 | * @return array
177 | * @throws BusinessException
178 | * @throws HttpException
179 | * @throws InvalidApiUriException
180 | */
181 | public function cancelByClientOid($clientOid, $symbol)
182 | {
183 | $response = $this->call(Request::METHOD_DELETE, '/api/v1/orders/client-order/' . $clientOid, ['symbol' => $symbol]);
184 | return $response->getApiData();
185 | }
186 |
187 | /**
188 | * Order test endpoint, the request parameters and return parameters of this endpoint are exactly the same as the order endpoint, and can be used to verify whether the signature is correct and other operations. After placing an order, the order will not enter the matching system, and the order cannot be queried.
189 | *
190 | * @param array $order
191 | * @return mixed|null
192 | * @throws BusinessException
193 | * @throws HttpException
194 | * @throws InvalidApiUriException
195 | */
196 | public function createTest(array $order)
197 | {
198 | $response = $this->call(Request::METHOD_POST, '/api/v1/orders/test', $order);
199 | return $response->getApiData();
200 | }
201 |
202 | /**
203 | * You can place up to 20 orders at one time, including limit orders, market orders, and stop orders.
204 | *
205 | * @param array $orders
206 | * @return mixed|null
207 | * @throws BusinessException
208 | * @throws HttpException
209 | * @throws InvalidApiUriException
210 | */
211 | public function createMultiOrders(array $orders)
212 | {
213 | $response = $this->call(Request::METHOD_POST, '/api/v1/orders/multi', $orders);
214 | return $response->getApiData();
215 | }
216 |
217 | /**
218 | * This interface supports both take-profit and stop-loss functions, and other functions are exactly the same as the place order interface.
219 | *
220 | * You can place two types of orders: limit and market. Orders can only be placed if your account has sufficient funds. Once an order is placed, your funds will be put on hold for the duration of the order. The amount of funds on hold depends on the order type and parameters specified.
221 | *
222 | * Please be noted that the system would hold the fees from the orders entered the orderbook in advance. Read Get Fills to learn more.
223 | *
224 | * @param array $order
225 | * @return mixed|null
226 | * @throws BusinessException
227 | * @throws HttpException
228 | * @throws InvalidApiUriException
229 | */
230 | public function createStOrder(array $order)
231 | {
232 | $response = $this->call(Request::METHOD_POST, '/api/v1/st-orders', $order);
233 | return $response->getApiData();
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/src/PrivateApi/WebSocketFeed.php:
--------------------------------------------------------------------------------
1 | loop === null) {
33 | $this->loop = Factory::create();
34 | }
35 | return $this->loop;
36 | }
37 |
38 | /**
39 | * Set the event loop instance
40 | * @param LoopInterface $loop
41 | */
42 | public function setLoop(LoopInterface $loop)
43 | {
44 | $this->loop = $loop;
45 | }
46 |
47 | /**
48 | * Get the server list and temporary token
49 | * @return array
50 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
51 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
52 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
53 | */
54 | public function getPublicBullet()
55 | {
56 | $response = $this->call(Request::METHOD_POST, '/api/v1/bullet-public');
57 | return $response->getApiData();
58 | }
59 |
60 | /**
61 | * Get the server list and authorized token
62 | * @return array
63 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
64 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
65 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
66 | */
67 | public function getPrivateBullet()
68 | {
69 | $response = $this->call(Request::METHOD_POST, '/api/v1/bullet-private');
70 | return $response->getApiData();
71 | }
72 |
73 | /**
74 | * Get the url of WebSocket
75 | * @param bool $private
76 | * @param array $params
77 | * @return array
78 | * @throws NoAvailableWebSocketServerException
79 | */
80 | public function getServer($private = false, array $params = [])
81 | {
82 | $bulletMethod = $private ? 'getPrivateBullet' : 'getPublicBullet';
83 | $bullet = $this->$bulletMethod();
84 | if (empty($bullet['instanceServers'])) {
85 | throw new NoAvailableWebSocketServerException();
86 | }
87 | $server = $bullet['instanceServers'][array_rand($bullet['instanceServers'])];
88 | $params['token'] = $bullet['token'];
89 | $url = sprintf('%s%s%s', $server['endpoint'], strpos($server['endpoint'], '?') === false ? '?' : '&', http_build_query($params));
90 | $server['connectUrl'] = $url;
91 | return $server;
92 | }
93 |
94 | /**
95 | * Get the url of WebSocket for public channels
96 | * @param array $params
97 | * @return array
98 | * @throws NoAvailableWebSocketServerException
99 | */
100 | public function getPublicServer(array $params = [])
101 | {
102 | return $this->getServer(false, $params);
103 | }
104 |
105 | /**
106 | * Get the url of WebSocket for private channels
107 | * @param array $params
108 | * @return array
109 | * @throws NoAvailableWebSocketServerException
110 | */
111 | public function getPrivateServer(array $params = [])
112 | {
113 | return $this->getServer(true, $params);
114 | }
115 |
116 | /**
117 | * Subscribe multiple channels by url
118 | * @param array $server
119 | * @param array $channels
120 | * @param callable $onMessage
121 | * @param callable|null $onClose
122 | * @param array $options
123 | * @throws \Exception|\Throwable
124 | */
125 | public function subscribeChannels(array $server, array $channels, callable $onMessage, callable $onClose = null, array $options = [])
126 | {
127 | if (!isset($options['tls']['verify_peer'])) {
128 | $options['tls']['verify_peer'] = !static::isSkipVerifyTls();
129 | }
130 |
131 | $loop = $this->getLoop();
132 | $reactConnector = new SocketConnector($loop, $options);
133 | $connector = new RatchetConnector($loop, $reactConnector);
134 | /**
135 | * @var \Exception|\Throwable $exception
136 | */
137 | $exception = null;
138 | $connector($server['connectUrl'])->then(function (WebSocket $ws) use ($server, $channels, $onMessage, $onClose, $loop) {
139 | // Add timer to send ping message
140 | $pingTimer = $loop->addPeriodicTimer($server['pingInterval'] / 1000 - 1, function () use ($ws) {
141 | try {
142 | $ping = $this->createPingMessage();
143 | $pingStr = json_encode($ping);
144 | if (self::isDebugMode()) {
145 | static::getLogger()->debug(sprintf('Sent a WebSocket message: %s', $pingStr));
146 | }
147 | // fputs(STDIN, print_r($ping, true));
148 | $ws->send($pingStr);
149 | } catch (\Exception $e) {
150 | // Ignore this exception
151 | }
152 | });
153 | $ws->on('message', function (MessageInterface $msg) use ($server, $ws, $channels, $onMessage, $loop, $pingTimer) {
154 | $msgStr = $msg->__toString();
155 | if (self::isDebugMode()) {
156 | static::getLogger()->debug(sprintf('Received a WebSocket message: %s', $msgStr));
157 | }
158 | $msgArray = json_decode($msgStr, true);
159 | if (!isset($msgArray['type'])) {
160 | throw new BusinessException('Invalid format of message without type: ' . $msgStr);
161 | }
162 | switch ($msgArray['type']) {
163 | case 'welcome':
164 | // Do subscribe
165 | if (!isset($msgArray['id']) || $msgArray['id'] === $server['connectId']) {
166 | foreach ($channels as $channel) {
167 | $ws->send(json_encode($channel));
168 | }
169 | }
170 | break;
171 | case 'ack':
172 | case 'ping':
173 | case 'pong':
174 | // fputs(STDIN, print_r($msgArray, true));
175 | break;
176 | case 'error':
177 | $loop->cancelTimer($pingTimer);
178 | throw new BusinessException('Error: ' . $msg);
179 | case 'message':
180 | call_user_func($onMessage, $msgArray, $ws, $loop);
181 | break;
182 | default:
183 | throw new BusinessException('Unknown type: ' . $msgArray['type']);
184 | }
185 | });
186 | $ws->on('close', function ($code = null, $reason = null) use ($onClose, $loop, $pingTimer) {
187 | if (is_callable($onClose)) {
188 | call_user_func($onClose, $code, $reason);
189 | }
190 | $loop->cancelTimer($pingTimer);
191 | });
192 | }, function ($e) use ($loop, &$exception) {
193 | $exception = $e;
194 | });
195 |
196 | $loop->run();
197 |
198 | if ($exception !== null) {
199 | throw $exception;
200 | }
201 | }
202 |
203 | /**
204 | * Subscribe multiple public channels
205 | * @param array $query The query of websocket url
206 | * @param array $channels
207 | * @param callable $onMessage
208 | * @param callable|null $onClose
209 | * @param array $options
210 | * @throws \Exception|\Throwable
211 | */
212 | public function subscribePublicChannels(array $query, array $channels, callable $onMessage, callable $onClose = null, array $options = [])
213 | {
214 | if (!isset($channels[0])) {
215 | $channels = [$channels];
216 | }
217 | array_walk($channels, function (&$channel) {
218 | if (!isset($channel['id'])) {
219 | $channel['id'] = uniqid('', true);
220 | }
221 | $channel['type'] = 'subscribe';
222 | $channel['privateChannel'] = false;
223 | });
224 | if (!isset($query['connectId'])) {
225 | $query['connectId'] = uniqid('', true);
226 | }
227 | $server = $this->getPublicServer($query);
228 | $server['connectId'] = $query['connectId'];
229 | $this->subscribeChannels($server, $channels, $onMessage, $onClose, $options);
230 | }
231 |
232 | /**
233 | * Subscribe multiple private channels
234 | * @param array $query The query of websocket url
235 | * @param array $channels
236 | * @param callable $onMessage
237 | * @param callable|null $onClose
238 | * @param array $options
239 | * @throws \Exception|\Throwable
240 | */
241 | public function subscribePrivateChannels(array $query, array $channels, callable $onMessage, callable $onClose = null, array $options = [])
242 | {
243 | if (!isset($channels[0])) {
244 | $channels = [$channels];
245 | }
246 | array_walk($channels, function (&$channel) {
247 | if (!isset($channel['id'])) {
248 | $channel['id'] = uniqid('', true);
249 | }
250 | $channel['type'] = 'subscribe';
251 | $channel['privateChannel'] = true;
252 | });
253 | if (!isset($query['connectId'])) {
254 | $query['connectId'] = uniqid('', true);
255 | }
256 | $server = $this->getPrivateServer($query);
257 | $server['connectId'] = $query['connectId'];
258 | $this->subscribeChannels($server, $channels, $onMessage, $onClose, $options);
259 | }
260 |
261 | /**
262 | * Subscribe one public channel
263 | * @param array $query The query of websocket url
264 | * @param array $channel
265 | * @param callable $onMessage
266 | * @param callable|null $onClose
267 | * @param array $options
268 | * @throws \Exception|\Throwable
269 | */
270 | public function subscribePublicChannel(array $query, array $channel, callable $onMessage, callable $onClose = null, array $options = [])
271 | {
272 | $this->subscribePublicChannels($query, [$channel], $onMessage, $onClose, $options);
273 | }
274 |
275 | /**
276 | * Subscribe one private channel
277 | * @param array $query The query of websocket url
278 | * @param array $channel
279 | * @param callable $onMessage
280 | * @param callable|null $onClose
281 | * @param array $options
282 | * @throws \Exception|\Throwable
283 | */
284 | public function subscribePrivateChannel(array $query, array $channel, callable $onMessage, callable $onClose = null, array $options = [])
285 | {
286 | $this->subscribePrivateChannels($query, [$channel], $onMessage, $onClose, $options);
287 | }
288 |
289 | /**
290 | * Create a ping message
291 | * @param string $id
292 | * @return array
293 | */
294 | public function createPingMessage($id = null)
295 | {
296 | return ['id' => $id ?: uniqid('', true), 'type' => 'ping'];
297 | }
298 |
299 | /**
300 | * Create a subscription message
301 | * @param string $topic
302 | * @param bool $privateChannel
303 | * @param bool $response
304 | * @param string $id
305 | * @return array
306 | */
307 | public function createSubscribeMessage($topic, $privateChannel = false, $response = true, $id = null)
308 | {
309 | return ['id' => $id ?: uniqid('', true), 'type' => 'subscribe', 'topic' => $topic, 'privateChannel' => $privateChannel, 'response' => $response];
310 | }
311 |
312 | /**
313 | * Create an unsubscribe message
314 | * @param string $topic
315 | * @param bool $privateChannel
316 | * @param bool $response
317 | * @param string $id
318 | * @return array
319 | */
320 | public function createUnsubscribeMessage($topic, $privateChannel = false, $response = true, $id = null)
321 | {
322 | return ['id' => $id ?: uniqid('', true), 'type' => 'unsubscribe', 'topic' => $topic, 'privateChannel' => $privateChannel, 'response' => $response];
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/tests/PositionTest.php:
--------------------------------------------------------------------------------
1 | getList();
23 | // $this->assertPagination($data);
24 | foreach ($data as $item) {
25 | $this->assertArrayHasKey('id', $item);
26 | $this->assertArrayHasKey('symbol', $item);
27 | $this->assertArrayHasKey('autoDeposit', $item);
28 | $this->assertArrayHasKey('maintMarginReq', $item);
29 | $this->assertArrayHasKey('riskLimit', $item);
30 | $this->assertArrayHasKey('realLeverage', $item);
31 | $this->assertArrayHasKey('crossMode', $item);
32 | $this->assertArrayHasKey('delevPercentage', $item);
33 | // $this->assertArrayHasKey('openingTimestamp', $item);
34 | $this->assertArrayHasKey('currentTimestamp', $item);
35 | $this->assertArrayHasKey('currentQty', $item);
36 | $this->assertArrayHasKey('currentCost', $item);
37 | $this->assertArrayHasKey('currentComm', $item);
38 | $this->assertArrayHasKey('unrealisedCost', $item);
39 | $this->assertArrayHasKey('realisedGrossCost', $item);
40 | $this->assertArrayHasKey('realisedCost', $item);
41 | $this->assertArrayHasKey('isOpen', $item);
42 | $this->assertArrayHasKey('markPrice', $item);
43 | $this->assertArrayHasKey('markValue', $item);
44 | $this->assertArrayHasKey('posCost', $item);
45 | $this->assertArrayHasKey('posCross', $item);
46 | $this->assertArrayHasKey('posInit', $item);
47 | $this->assertArrayHasKey('posComm', $item);
48 | $this->assertArrayHasKey('posLoss', $item);
49 | $this->assertArrayHasKey('posMargin', $item);
50 | $this->assertArrayHasKey('posMaint', $item);
51 | $this->assertArrayHasKey('maintMargin', $item);
52 | $this->assertArrayHasKey('realisedGrossPnl', $item);
53 | $this->assertArrayHasKey('realisedPnl', $item);
54 | $this->assertArrayHasKey('unrealisedPnl', $item);
55 | $this->assertArrayHasKey('unrealisedPnlPcnt', $item);
56 | $this->assertArrayHasKey('avgEntryPrice', $item);
57 | $this->assertArrayHasKey('liquidationPrice', $item);
58 | $this->assertArrayHasKey('bankruptPrice', $item);
59 | }
60 | }
61 |
62 | /**
63 | * @dataProvider apiProvider
64 | * @param Position $api
65 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
66 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
67 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
68 | */
69 | public function testGetDetail(Position $api)
70 | {
71 | $item = $api->getDetail("XBTUSDM");
72 | $this->assertArrayHasKey('id', $item);
73 | $this->assertArrayHasKey('symbol', $item);
74 | $this->assertArrayHasKey('autoDeposit', $item);
75 | $this->assertArrayHasKey('maintMarginReq', $item);
76 | $this->assertArrayHasKey('riskLimit', $item);
77 | $this->assertArrayHasKey('realLeverage', $item);
78 | $this->assertArrayHasKey('crossMode', $item);
79 | $this->assertArrayHasKey('delevPercentage', $item);
80 | $this->assertArrayHasKey('openingTimestamp', $item);
81 | $this->assertArrayHasKey('currentTimestamp', $item);
82 | $this->assertArrayHasKey('currentQty', $item);
83 | $this->assertArrayHasKey('currentCost', $item);
84 | $this->assertArrayHasKey('currentComm', $item);
85 | $this->assertArrayHasKey('unrealisedCost', $item);
86 | $this->assertArrayHasKey('realisedGrossCost', $item);
87 | $this->assertArrayHasKey('realisedCost', $item);
88 | $this->assertArrayHasKey('isOpen', $item);
89 | $this->assertArrayHasKey('markPrice', $item);
90 | $this->assertArrayHasKey('markValue', $item);
91 | $this->assertArrayHasKey('posCost', $item);
92 | $this->assertArrayHasKey('posCross', $item);
93 | $this->assertArrayHasKey('posInit', $item);
94 | $this->assertArrayHasKey('posComm', $item);
95 | $this->assertArrayHasKey('posLoss', $item);
96 | $this->assertArrayHasKey('posMargin', $item);
97 | $this->assertArrayHasKey('posMaint', $item);
98 | $this->assertArrayHasKey('maintMargin', $item);
99 | $this->assertArrayHasKey('realisedGrossPnl', $item);
100 | $this->assertArrayHasKey('realisedPnl', $item);
101 | $this->assertArrayHasKey('unrealisedPnl', $item);
102 | $this->assertArrayHasKey('unrealisedPnlPcnt', $item);
103 | $this->assertArrayHasKey('avgEntryPrice', $item);
104 | $this->assertArrayHasKey('liquidationPrice', $item);
105 | $this->assertArrayHasKey('bankruptPrice', $item);
106 | }
107 |
108 | /**
109 | * @dataProvider apiProvider
110 | * @param Position $api
111 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
112 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
113 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
114 | */
115 | public function testChangeAutoAppendStatus(Position $api)
116 | {
117 | $data = $api->changeAutoAppendStatus('XBTUSDM', true);
118 | // $this->assertInternalType('array', $data);
119 | $this->assertNull($data);
120 | }
121 |
122 | /**
123 | * @dataProvider apiProvider
124 | * @param Position $api
125 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
126 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
127 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
128 | */
129 | public function testMarginAppend(Position $api)
130 | {
131 | $params = [
132 | 'symbol' => 'XBTUSDM',
133 | 'margin' => 1000,
134 | 'bizNo' => '123123',
135 | ];
136 | $data = $api->marginAppend($params);
137 | // $this->assertInternalType('array', $data);
138 | $this->assertNull($data);
139 | }
140 |
141 | /**
142 | * @dataProvider apiProvider
143 | *
144 | * @param Position $api
145 | * @return void
146 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
147 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
148 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
149 | */
150 | public function testGetMaxWithdrawMargin(Position $api)
151 | {
152 | $symbol = 'XBTUSDM';
153 | $result = $api->getMaxWithdrawMargin($symbol);
154 | $this->assertGreaterThanOrEqual('0', $result);
155 | }
156 |
157 | /**
158 | * @dataProvider apiProvider
159 | *
160 | * @param Position $api
161 | * @return void
162 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
163 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
164 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
165 | */
166 | public function testWithdrawMargin(Position $api)
167 | {
168 | $symbol = 'XBTUSDTM';
169 | $result = $api->withdrawMargin($symbol, '0.1');
170 | $this->assertEquals('0.1', $result);
171 | }
172 |
173 | /**
174 | * @dataProvider apiProvider
175 | *
176 | * @param Position $api
177 | * @return void
178 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
179 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
180 | */
181 | public function testGetGetHistoryPositions(Position $api)
182 | {
183 | $params = [
184 | 'limit' => 2,
185 | 'pageId' => 1,
186 | ];
187 | $result = $api->getHistoryPositions($params);
188 | $this->assertPagination($result);
189 | foreach ($result['items'] as $item) {
190 | $this->assertArrayHasKey('closeId', $item);
191 | $this->assertArrayHasKey('userId', $item);
192 | $this->assertArrayHasKey('symbol', $item);
193 | $this->assertArrayHasKey('settleCurrency', $item);
194 | $this->assertArrayHasKey('leverage', $item);
195 | $this->assertArrayHasKey('type', $item);
196 | $this->assertArrayHasKey('pnl', $item);
197 | $this->assertArrayHasKey('realisedGrossCost', $item);
198 | $this->assertArrayHasKey('withdrawPnl', $item);
199 | $this->assertArrayHasKey('tradeFee', $item);
200 | $this->assertArrayHasKey('fundingFee', $item);
201 | $this->assertArrayHasKey('openTime', $item);
202 | $this->assertArrayHasKey('closeTime', $item);
203 | $this->assertArrayHasKey('openPrice', $item);
204 | $this->assertArrayHasKey('closePrice', $item);
205 | }
206 | }
207 |
208 | /**
209 | * @dataProvider apiProvider
210 | *
211 | * @param Position $api
212 | * @return void
213 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
214 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
215 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
216 | */
217 | public function testGetMaxOpenSize(Position $api)
218 | {
219 | $symbol = 'XBTUSDTM';
220 | $price = '60000';
221 | $leverage = 2;
222 | $result = $api->getMaxOpenSize($symbol, $price, $leverage);
223 | $this->assertInternalType('array', $result);
224 | $this->assertArrayHasKey('symbol', $result);
225 | $this->assertArrayHasKey('maxBuyOpenSize', $result);
226 | $this->assertArrayHasKey('maxSellOpenSize', $result);
227 | }
228 |
229 | /**
230 | * @dataProvider apiProvider
231 | *
232 | * @param Position $api
233 | * @return void
234 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
235 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
236 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
237 | */
238 | public function testModifyMarginMode(Position $api)
239 | {
240 | $symbol = 'XBTUSDM';
241 | $marginMode = MarginMode::ISOLATED;
242 | $result = $api->modifyMarginMode($symbol, $marginMode);
243 | $this->assertInternalType('array', $result);
244 | $this->assertArrayHasKey('symbol', $result);
245 | $this->assertArrayHasKey('marginMode', $result);
246 | }
247 |
248 | /**
249 | * @dataProvider apiProvider
250 | *
251 | * @param Position $api
252 | * @return void
253 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
254 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
255 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
256 | */
257 | public function testGetMarginMode(Position $api)
258 | {
259 | $symbol = 'XBTUSDM';
260 | $marginMode = MarginMode::ISOLATED;
261 | $api->modifyMarginMode($symbol, $marginMode);
262 | $result = $api->getMarginMode($symbol);
263 | $this->assertInternalType('array', $result);
264 | $this->assertArrayHasKey('symbol', $result);
265 | $this->assertArrayHasKey('marginMode', $result);
266 | $this->assertEquals($marginMode, $result['marginMode']);
267 | }
268 |
269 | /**
270 | * @dataProvider apiProvider
271 | *
272 | * @param Position $api
273 | * @return void
274 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
275 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
276 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
277 | */
278 | public function testModifyCrossUserLeverage(Position $api)
279 | {
280 | $symbol = 'XBTUSDM';
281 | $leverage = 2;
282 | $api->modifyMarginMode($symbol, MarginMode::CROSS);
283 | $result = $api->modifyCrossUserLeverage($symbol, $leverage);
284 | $this->assertEquals(true, $result);
285 | }
286 |
287 | /**
288 | * @dataProvider apiProvider
289 | *
290 | * @param Position $api
291 | * @return void
292 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
293 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
294 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
295 | */
296 | public function testGetCrossUserLeverage(Position $api)
297 | {
298 | $symbol = 'XBTUSDM';
299 | $leverage = 2;
300 | $api->modifyMarginMode($symbol, MarginMode::CROSS);
301 | $api->modifyCrossUserLeverage($symbol, $leverage);
302 | $result = $api->getCrossUserLeverage($symbol);
303 | $this->assertInternalType('array', $result);
304 | $this->assertArrayHasKey('symbol', $result);
305 | $this->assertArrayHasKey('leverage', $result);
306 | $this->assertEquals($leverage, $result['leverage']);
307 | }
308 | }
309 |
--------------------------------------------------------------------------------
/tests/AccountTest.php:
--------------------------------------------------------------------------------
1 | getOverview(['currency' => 'XBT']);
24 | $this->assertInternalType('array', $accounts);
25 | $this->assertArrayHasKey('accountEquity', $accounts);
26 | $this->assertArrayHasKey('unrealisedPNL', $accounts);
27 | $this->assertArrayHasKey('marginBalance', $accounts);
28 | $this->assertArrayHasKey('positionMargin', $accounts);
29 | $this->assertArrayHasKey('orderMargin', $accounts);
30 | $this->assertArrayHasKey('frozenFunds', $accounts);
31 | $this->assertArrayHasKey('availableBalance', $accounts);
32 | }
33 |
34 | /**
35 | * @dataProvider apiProvider
36 | * @param Account $api
37 | * @throws BusinessException
38 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
39 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
40 | */
41 | public function testGetTransactionHistory(Account $api)
42 | {
43 | $accounts = $api->getTransactionHistory(['currency' => 'XBT']);
44 | $this->assertInternalType('array', $accounts);
45 | foreach ($accounts['dataList'] as $item) {
46 | $this->assertArrayHasKey('time', $item);
47 | $this->assertArrayHasKey('type', $item);
48 | $this->assertArrayHasKey('amount', $item);
49 | $this->assertArrayHasKey('accountEquity', $item);
50 | $this->assertArrayHasKey('status', $item);
51 | $this->assertArrayHasKey('offset', $item);
52 | }
53 | }
54 |
55 | /**
56 | * @param Account $api
57 | * @throws BusinessException
58 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
59 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
60 | * @deprecated
61 | * @dataProvider apiProvider
62 | */
63 | // public function testTransferIn(Account $api)
64 | // {
65 | // $amount = 0.1;
66 | // $accounts = $api->transferIn($amount);
67 | // $this->assertInternalType('array', $accounts);
68 | // if (isset($accounts['applyId'])) {
69 | // $this->assertArrayHasKey('applyId', $accounts);
70 | // }
71 | // }
72 |
73 | /**
74 | * @dataProvider apiProvider
75 | * @param Account $api
76 | * @throws BusinessException
77 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
78 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
79 | */
80 | public function testTransferOut(Account $api)
81 | {
82 | $bizNo = rand(1, 9999);
83 | $amount = 0.1;
84 | $accounts = $api->transferOut($bizNo, $amount);
85 | $this->assertInternalType('array', $accounts);
86 | if (isset($accounts['applyId'])) {
87 | $this->assertArrayHasKey('applyId', $accounts);
88 | }
89 | }
90 |
91 | /**
92 | * @dataProvider apiProvider
93 | * @param Account $api
94 | * @throws BusinessException
95 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
96 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
97 | */
98 | public function testCancelTransferOut(Account $api)
99 | {
100 | $applyId = $this->getTransferId($api);
101 | $accounts = $api->cancelTransferOut($applyId);
102 | $this->assertNull($accounts);
103 | }
104 |
105 | /**
106 | * @dataProvider apiProvider
107 | * @param Account $api
108 | * @throws BusinessException
109 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
110 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
111 | */
112 | public function testGetTransferList(Account $api)
113 | {
114 | $accounts = $api->getTransactionHistory();
115 | $this->assertInternalType('array', $accounts);
116 | foreach ($accounts['dataList'] as $item) {
117 | // $this->assertArrayHasKey('applyId', $item);
118 | // $this->assertArrayHasKey('currency', $item);
119 | $this->assertArrayHasKey('status', $item);
120 | $this->assertArrayHasKey('amount', $item);
121 | $this->assertArrayHasKey('offset', $item);
122 | }
123 | }
124 |
125 | /**
126 | * @dataProvider apiProvider.
127 | *
128 | * @param Account $api
129 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
130 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
131 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
132 | */
133 | private function getTransferId($api)
134 | {
135 | $bizNo = '10000000001';
136 | $amount = 0.1;
137 | $accounts = $api->transferOut($bizNo, $amount);
138 | $this->assertInternalType('array', $accounts);
139 | return $accounts['applyId'];
140 | }
141 |
142 |
143 | /**
144 | * @dataProvider apiProvider
145 | * @param Account $api
146 | * @throws BusinessException
147 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
148 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
149 | */
150 | public function testTransferOutV2(Account $api)
151 | {
152 | $bizNo = uniqid('t_', false);
153 | $amount = 0.01;
154 | $currency = 'USDT';
155 | $data = $api->transferOutV2($bizNo, $amount, $currency);
156 |
157 | $this->assertInternalType('array', $data);
158 |
159 | $this->assertArrayHasKey('applyId', $data);
160 | $this->assertArrayHasKey('bizNo', $data);
161 | $this->assertArrayHasKey('payAccountType', $data);
162 | $this->assertArrayHasKey('payTag', $data);
163 | $this->assertArrayHasKey('remark', $data);
164 | $this->assertArrayHasKey('recAccountType', $data);
165 | $this->assertArrayHasKey('recTag', $data);
166 | $this->assertArrayHasKey('recRemark', $data);
167 | $this->assertArrayHasKey('recSystem', $data);
168 | $this->assertArrayHasKey('status', $data);
169 | $this->assertArrayHasKey('currency', $data);
170 | $this->assertArrayHasKey('amount', $data);
171 | $this->assertArrayHasKey('fee', $data);
172 | $this->assertArrayHasKey('sn', $data);
173 | }
174 |
175 | /**
176 | * @dataProvider apiProvider
177 | * @param Account $api
178 | * @throws BusinessException
179 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
180 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
181 | */
182 | public function testGetSubApikey(Account $api)
183 | {
184 | $params = ['subName' => 'phpunittest', 'apiKey' => '647da940d35150000196a56c'];
185 | $data = $api->getSubApikey($params);
186 | $this->assertInternalType('array', $data);
187 | $this->assertArrayHasKey('apiKey', $data);
188 | $this->assertArrayHasKey('createdAt', $data);
189 | $this->assertArrayHasKey('ipWhitelist', $data);
190 | $this->assertArrayHasKey('permission', $data);
191 | $this->assertArrayHasKey('remark', $data);
192 | $this->assertArrayHasKey('subName', $data);
193 | }
194 |
195 | /**
196 | * @dataProvider apiProvider
197 | * @param Account $api
198 | * @throws BusinessException
199 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
200 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
201 | */
202 | public function testCreateSubApikey(Account $api)
203 | {
204 | $params = ['subName' => 'phpunittest', 'passphrase' => 'phpunit2023', 'remark' => 'remark'];
205 | $data = $api->createSubApikey($params);
206 | $this->assertInternalType('array', $data);
207 | $this->assertArrayHasKey('apiKey', $data);
208 | $this->assertArrayHasKey('createdAt', $data);
209 | $this->assertArrayHasKey('ipWhitelist', $data);
210 | $this->assertArrayHasKey('permission', $data);
211 | $this->assertArrayHasKey('remark', $data);
212 | $this->assertArrayHasKey('subName', $data);
213 | }
214 |
215 | /**
216 | * @dataProvider apiProvider
217 | * @param Account $api
218 | * @throws BusinessException
219 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
220 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
221 | */
222 | public function testModifySubApikey(Account $api)
223 | {
224 | $params = ['subName' => 'phpunittest', 'passphrase' => 'phpunit2023', 'apiKey' => '647d8f588de0cc0001751b6e'];
225 | $data = $api->modifySubApikey($params);
226 | $this->assertInternalType('array', $data);
227 | $this->assertArrayHasKey('apiKey', $data);
228 | $this->assertArrayHasKey('ipWhitelist', $data);
229 | $this->assertArrayHasKey('permission', $data);
230 | $this->assertArrayHasKey('subName', $data);
231 | }
232 |
233 | /**
234 | * @dataProvider apiProvider
235 | * @param Account $api
236 | * @throws BusinessException
237 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
238 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
239 | */
240 | public function testDeleteSubApikey(Account $api)
241 | {
242 | $params = ['subName' => 'phpunittest', 'passphrase' => 'phpunit2023', 'apiKey' => '647d8f588de0cc0001751b6e'];
243 | $data = $api->deleteSubApikey($params);
244 | $this->assertInternalType('array', $data);
245 | $this->assertArrayHasKey('apiKey', $data);
246 | $this->assertArrayHasKey('subName', $data);
247 | }
248 |
249 | /**
250 | * @dataProvider apiProvider
251 | * @param Account $api
252 | * @throws BusinessException
253 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
254 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
255 | */
256 | public function testTransferOutV3(Account $api)
257 | {
258 | $recAccountType = 'MAIN';
259 | $amount = 0.01;
260 | $currency = 'USDT';
261 | $data = $api->transferOutV3($recAccountType, $amount, $currency);
262 |
263 | $this->assertInternalType('array', $data);
264 |
265 | $this->assertArrayHasKey('applyId', $data);
266 | $this->assertArrayHasKey('bizNo', $data);
267 | $this->assertArrayHasKey('payAccountType', $data);
268 | $this->assertArrayHasKey('payTag', $data);
269 | $this->assertArrayHasKey('remark', $data);
270 | $this->assertArrayHasKey('recAccountType', $data);
271 | $this->assertArrayHasKey('recTag', $data);
272 | $this->assertArrayHasKey('recRemark', $data);
273 | $this->assertArrayHasKey('recSystem', $data);
274 | $this->assertArrayHasKey('status', $data);
275 | $this->assertArrayHasKey('currency', $data);
276 | $this->assertArrayHasKey('amount', $data);
277 | $this->assertArrayHasKey('fee', $data);
278 | $this->assertArrayHasKey('sn', $data);
279 | $this->assertArrayHasKey('reason', $data);
280 | $this->assertArrayHasKey('createdAt', $data);
281 | $this->assertArrayHasKey('updatedAt', $data);
282 | }
283 |
284 | /**
285 | * @dataProvider apiProvider
286 | * @param Account $api
287 | * @throws BusinessException
288 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
289 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
290 | */
291 | public function testGetAccountOverviewAll(Account $api)
292 | {
293 | $currency = 'USDT';
294 | $data = $api->getAccountOverviewAll($currency);
295 | $this->assertInternalType('array', $data);
296 | $this->assertInternalType('array', $data['summary']);
297 | $this->assertArrayHasKey('accountEquityTotal', $data['summary']);
298 | $this->assertArrayHasKey('unrealisedPNLTotal', $data['summary']);
299 | $this->assertArrayHasKey('marginBalanceTotal', $data['summary']);
300 | $this->assertArrayHasKey('positionMarginTotal', $data['summary']);
301 | $this->assertArrayHasKey('orderMarginTotal', $data['summary']);
302 | $this->assertArrayHasKey('frozenFundsTotal', $data['summary']);
303 | $this->assertArrayHasKey('availableBalanceTotal', $data['summary']);
304 | $this->assertArrayHasKey('currency', $data['summary']);
305 | $this->assertEquals($currency, $data['summary']['currency']);
306 | $this->assertInternalType('array', $data['accounts']);
307 | foreach ($data['accounts'] as $item) {
308 | $this->assertArrayHasKey('accountName', $item);
309 | $this->assertArrayHasKey('accountEquity', $item);
310 | $this->assertArrayHasKey('unrealisedPNL', $item);
311 | $this->assertArrayHasKey('marginBalance', $item);
312 | $this->assertArrayHasKey('positionMargin', $item);
313 | $this->assertArrayHasKey('orderMargin', $item);
314 | $this->assertArrayHasKey('frozenFunds', $item);
315 | $this->assertArrayHasKey('availableBalance', $item);
316 | $this->assertArrayHasKey('currency', $item);
317 | $this->assertEquals($currency, $item['currency']);
318 | }
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/tests/WebSocketFeedTest.php:
--------------------------------------------------------------------------------
1 | getPublicBullet();
24 | $this->assertInternalType('array', $data);
25 | $this->assertArrayHasKey('token', $data);
26 | $this->assertArrayHasKey('instanceServers', $data);
27 | $this->assertInternalType('array', $data['instanceServers']);
28 | foreach ($data['instanceServers'] as $instanceServer) {
29 | $this->assertArrayHasKey('endpoint', $instanceServer);
30 | $this->assertArrayHasKey('protocol', $instanceServer);
31 | $this->assertArrayHasKey('encrypt', $instanceServer);
32 | $this->assertInternalType('array', $instanceServer);
33 | }
34 | }
35 |
36 | /**
37 | * @dataProvider apiProvider
38 | * @param WebSocketFeed $api
39 | * @return array
40 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
41 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
42 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
43 | */
44 | public function testGetPrivateBullet(WebSocketFeed $api)
45 | {
46 | $data = $api->getPrivateBullet();
47 | $this->assertInternalType('array', $data);
48 | $this->assertArrayHasKey('token', $data);
49 | $this->assertArrayHasKey('instanceServers', $data);
50 | $this->assertInternalType('array', $data['instanceServers']);
51 |
52 | $wsAddress = null;
53 | foreach ($data['instanceServers'] as $instanceServer) {
54 | $this->assertInternalType('array', $instanceServer);
55 | $this->assertArrayHasKey('endpoint', $instanceServer);
56 | $this->assertArrayHasKey('protocol', $instanceServer);
57 | $this->assertArrayHasKey('encrypt', $instanceServer);
58 | if ($instanceServer['protocol'] === 'websocket') {
59 | $wsAddress = $instanceServer['endpoint'];
60 | }
61 | }
62 | return ['address' => $wsAddress, 'token' => $data['token']];
63 | }
64 |
65 | /**
66 | * @dataProvider apiProvider
67 | * @param WebSocketFeed $api
68 | * @throws \Exception|\Throwable
69 | */
70 | public function testSubscribePublicChannel(WebSocketFeed $api)
71 | {
72 | $query = ['connectId' => uniqid('', true),];
73 | $channel = ['topic' => '/contractMarket/ticker:XBTUSDM'];
74 |
75 | $options = [
76 | // 'tls' => [
77 | // 'verify_peer' => false,
78 | // ],
79 | ];
80 | $api->subscribePublicChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
81 | $this->assertInternalType('array', $message);
82 | $this->assertArrayHasKey('type', $message);
83 | $this->assertArrayHasKey('channelType', $message);
84 | $this->assertEquals('message', $message['type']);
85 |
86 | // Dynamic output
87 | fputs(STDIN, print_r($message, true));
88 |
89 | // Stop for phpunit
90 | $loop->stop();
91 | }, function ($code, $reason) {
92 | echo "OnClose: {$code} {$reason}\n";
93 | }, $options);
94 | }
95 |
96 | /**
97 | * @dataProvider apiProvider
98 | * @param WebSocketFeed $api
99 | * @throws \Exception|\Throwable
100 | */
101 | public function testSubscribePublicChannels(WebSocketFeed $api)
102 | {
103 | $query = ['connectId' => uniqid('', true),];
104 | $channels = [
105 | ['topic' => '/contractMarket/ticker:XBTUSDM'],
106 | ['topic' => '/contractMarket/ticker:XBTUSDM'],
107 | ];
108 |
109 | $options = [
110 | // 'tls' => [
111 | // 'verify_peer' => false,
112 | // ],
113 | ];
114 | $api->subscribePublicChannels($query, $channels, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
115 | $this->assertInternalType('array', $message);
116 | $this->assertArrayHasKey('type', $message);
117 | $this->assertArrayHasKey('channelType', $message);
118 | $this->assertEquals('message', $message['type']);
119 |
120 | // Dynamic output
121 | fputs(STDIN, print_r($message, true));
122 |
123 | // Stop for phpunit
124 | $loop->stop();
125 | }, function ($code, $reason) {
126 | echo "OnClose: {$code} {$reason}\n";
127 | }, $options);
128 | }
129 |
130 |
131 | /**
132 | * @dataProvider apiProvider
133 | * @param WebSocketFeed $api
134 | * @throws \Exception|\Throwable
135 | */
136 | public function testUnsubscribePublicChannel(WebSocketFeed $api)
137 | {
138 | $query = ['connectId' => uniqid('', true),];
139 | $channel = ['topic' => '/contractMarket/ticker:XBTUSDM'];
140 |
141 | $options = [
142 | // 'tls' => [
143 | // 'verify_peer' => false,
144 | // ],
145 | ];
146 | $api->subscribePublicChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
147 | $this->assertInternalType('array', $message);
148 | $this->assertArrayHasKey('type', $message);
149 | $this->assertArrayHasKey('channelType', $message);
150 | $this->assertEquals('message', $message['type']);
151 |
152 | // Dynamic output
153 | fputs(STDIN, print_r($message, true));
154 |
155 | // Stop for phpunit
156 | $loop->stop();
157 | }, function ($code, $reason) {
158 | echo "OnClose: {$code} {$reason}\n";
159 | }, $options);
160 | }
161 |
162 | /**
163 | * @dataProvider apiProvider
164 | * @param WebSocketFeed $api
165 | * @throws \Exception|\Throwable
166 | */
167 | public function testSubscribePrivateChannel(WebSocketFeed $api)
168 | {
169 | $query = ['connectId' => uniqid('', true),];
170 | $channel = ['topic' => '/contract/position:XBTUSDM'];
171 |
172 | $options = [
173 | // 'tls' => [
174 | // 'verify_peer' => false,
175 | // ],
176 | ];
177 | $api->subscribePrivateChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
178 | $this->assertInternalType('array', $message);
179 | $this->assertArrayHasKey('type', $message);
180 | $this->assertArrayHasKey('channelType', $message);
181 | $this->assertEquals('message', $message['type']);
182 | // Dynamic output
183 | fputs(STDIN, print_r($message, true));
184 |
185 | // Stop for phpunit
186 | $loop->stop();
187 | }, function ($code, $reason) {
188 | echo "OnClose: {$code} {$reason}\n";
189 | }, $options);
190 | }
191 |
192 | /**
193 | * @dataProvider apiProvider
194 | * @param WebSocketFeed $api
195 | * @throws \Exception|\Throwable
196 | */
197 | public function testSubscribePrivateChannels(WebSocketFeed $api)
198 | {
199 | $query = ['connectId' => uniqid('', true),];
200 | $channels = [
201 | ['topic' => '/contract/position:XBTUSDM'],
202 | ['topic' => '/contract/position:XBTUSDM'],
203 | ];
204 |
205 | $options = [
206 | // 'tls' => [
207 | // 'verify_peer' => false,
208 | // ],
209 | ];
210 | $api->subscribePrivateChannels($query, $channels, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
211 | $this->assertInternalType('array', $message);
212 | $this->assertArrayHasKey('type', $message);
213 | $this->assertArrayHasKey('channelType', $message);
214 | $this->assertEquals('message', $message['type']);
215 | // Dynamic output
216 | fputs(STDIN, print_r($message, true));
217 |
218 | // Stop for phpunit
219 | $loop->stop();
220 | }, function ($code, $reason) {
221 | echo "OnClose: {$code} {$reason}\n";
222 | }, $options);
223 | }
224 |
225 | /**
226 | * @dataProvider apiProvider
227 | * @param WebSocketFeed $api
228 | * @throws \Throwable
229 | */
230 | public function testSubscribeLevel3v2(WebSocketFeed $api)
231 | {
232 | $query = ['connectId' => uniqid('t_', false),];
233 | $channel = ['topic' => '/contractMarket/level3v2:XBTUSDM'];
234 |
235 | $options = [];
236 | $api->subscribePublicChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
237 | // Dynamic output
238 | fwrite(STDIN, print_r($message, true));
239 |
240 | $this->assertInternalType('array', $message);
241 | $this->assertArrayHasKey('type', $message);
242 | $this->assertArrayHasKey('topic', $message);
243 | $this->assertArrayHasKey('subject', $message);
244 | $this->assertArrayHasKey('data', $message);
245 | $this->assertInternalType('array', $message['data']);
246 | $this->assertArrayHasKey('symbol', $message['data']);
247 | $this->assertArrayHasKey('sequence', $message['data']);
248 | $this->assertArrayHasKey('orderId', $message['data']);
249 |
250 | // Stop for phpunit
251 | $loop->stop();
252 | }, function ($code, $reason) {
253 | echo "OnClose: {$code} {$reason}\n";
254 | }, $options);
255 | }
256 |
257 | /**
258 | * @dataProvider apiProvider
259 | * @param WebSocketFeed $api
260 | * @throws \Throwable
261 | */
262 | public function testSubscribeTickerV2(WebSocketFeed $api)
263 | {
264 | $query = ['connectId' => uniqid('t_', false),];
265 | $channel = ['topic' => '/contractMarket/tickerV2:XBTUSDM'];
266 |
267 | $options = [];
268 | $api->subscribePublicChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
269 | // Dynamic output
270 | fwrite(STDIN, print_r($message, true));
271 |
272 | $this->assertInternalType('array', $message);
273 | $this->assertArrayHasKey('type', $message);
274 | $this->assertArrayHasKey('topic', $message);
275 | $this->assertArrayHasKey('subject', $message);
276 | $this->assertArrayHasKey('data', $message);
277 | $this->assertArrayHasKey('symbol', $message['data']);
278 | $this->assertArrayHasKey('sequence', $message['data']);
279 | $this->assertArrayHasKey('bestBidSize', $message['data']);
280 | $this->assertArrayHasKey('bestBidPrice', $message['data']);
281 | $this->assertArrayHasKey('bestAskPrice', $message['data']);
282 | $this->assertArrayHasKey('bestAskSize', $message['data']);
283 | $this->assertArrayHasKey('ts', $message['data']);
284 | // Stop for phpunit
285 | $loop->stop();
286 | }, function ($code, $reason) {
287 | echo "OnClose: {$code} {$reason}\n";
288 | }, $options);
289 | }
290 |
291 | /**
292 | * @dataProvider apiProvider
293 | * @param WebSocketFeed $api
294 | * @throws \Throwable
295 | */
296 | public function testSubscribeTradeOrders(WebSocketFeed $api)
297 | {
298 | $query = ['connectId' => uniqid('t_', false),];
299 | $channel = ['topic' => '/contractMarket/tradeOrders:XBTUSDM'];
300 |
301 | $options = [];
302 | $api->subscribePrivateChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
303 | // Dynamic output
304 | fwrite(STDIN, print_r($message, true));
305 |
306 | $this->assertInternalType('array', $message);
307 | $this->assertArrayHasKey('type', $message);
308 | $this->assertArrayHasKey('topic', $message);
309 | $this->assertArrayHasKey('subject', $message);
310 | $this->assertArrayHasKey('data', $message);
311 | // Stop for phpunit
312 | $loop->stop();
313 | }, function ($code, $reason) {
314 | echo "OnClose: {$code} {$reason}\n";
315 | }, $options);
316 | }
317 |
318 | /**
319 | * @dataProvider apiProvider
320 | * @param WebSocketFeed $api
321 | * @throws \Throwable
322 | */
323 | public function testSubscribeWalletAvailableBalanceChange(WebSocketFeed $api)
324 | {
325 | $query = ['connectId' => uniqid('t_', false),];
326 | $channel = ['topic' => '/contractAccount/wallet'];
327 |
328 | $options = [];
329 | $api->subscribePrivateChannel($query, $channel, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
330 | // Dynamic output
331 | fwrite(STDIN, print_r($message, true));
332 |
333 | $this->assertInternalType('array', $message);
334 | $this->assertArrayHasKey('type', $message);
335 | $this->assertArrayHasKey('topic', $message);
336 | $this->assertArrayHasKey('subject', $message);
337 | $this->assertArrayHasKey('data', $message);
338 |
339 | if ($message['subject'] === 'availableBalance.change') {
340 | $this->assertArrayHasKey('currency', $message['data']);
341 | $this->assertArrayHasKey('holdBalance', $message['data']);
342 | $this->assertArrayHasKey('availableBalance', $message['data']);
343 | $this->assertArrayHasKey('timestamp', $message['data']);
344 | }
345 |
346 | if ($message['subject'] === 'withdrawHold.change') {
347 | $this->assertArrayHasKey('currency', $message['data']);
348 | $this->assertArrayHasKey('withdrawHold', $message['data']);
349 | $this->assertArrayHasKey('timestamp', $message['data']);
350 | }
351 |
352 | // Stop for phpunit
353 | $loop->stop();
354 | }, function ($code, $reason) {
355 | echo "OnClose: {$code} {$reason}\n";
356 | }, $options);
357 | }
358 | }
359 |
--------------------------------------------------------------------------------
/tests/OrderTest.php:
--------------------------------------------------------------------------------
1 | uniqid(),
24 | 'type' => 'limit',
25 | 'side' => 'buy',
26 | 'symbol' => 'XBTUSDM',
27 | 'leverage' => 2,
28 | 'remark' => '\中文备注 ',
29 |
30 | 'price' => 100,
31 | 'size' => 1,
32 | ];
33 | $data = $api->create($order);
34 | $this->assertInternalType('array', $data);
35 | $this->assertArrayHasKey('orderId', $data);
36 | }
37 |
38 | /**
39 | * @dataProvider apiProvider
40 | * @param Order $api
41 | * @return array|string
42 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
43 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
44 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
45 | */
46 | public function testCreateMarket(Order $api)
47 | {
48 | $order = [
49 | 'clientOid' => uniqid(),
50 | 'type' => 'market',
51 | 'side' => 'buy',
52 | 'symbol' => 'XBTUSDM',
53 | 'leverage' => 2,
54 | 'remark' => 'Test Order ' . time(),
55 |
56 | 'size' => 1,
57 | ];
58 | $data = $api->create($order);
59 | $this->assertInternalType('array', $data);
60 | $this->assertArrayHasKey('orderId', $data);
61 | }
62 |
63 | /**
64 | * @dataProvider apiProvider
65 | * @param Order $api
66 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
67 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
68 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
69 | */
70 | public function testGetList(Order $api)
71 | {
72 | $data = $api->getList(['symbol' => 'XBTUSDM'], ['currentPage' => 1, 'pageSize' => 10]);
73 | $this->assertPagination($data);
74 | foreach ($data['items'] as $item) {
75 | $this->assertArrayHasKey('symbol', $item);
76 | $this->assertArrayHasKey('hidden', $item);
77 | $this->assertArrayHasKey('type', $item);
78 | $this->assertArrayHasKey('iceberg', $item);
79 | $this->assertArrayHasKey('createdAt', $item);
80 | $this->assertArrayHasKey('stopTriggered', $item);
81 | $this->assertArrayHasKey('id', $item);
82 | $this->assertArrayHasKey('timeInForce', $item);
83 | $this->assertArrayHasKey('side', $item);
84 | $this->assertArrayHasKey('dealSize', $item);
85 | $this->assertArrayHasKey('stp', $item);
86 | $this->assertArrayHasKey('postOnly', $item);
87 | $this->assertArrayHasKey('size', $item);
88 | $this->assertArrayHasKey('stop', $item);
89 | $this->assertArrayHasKey('settleCurrency', $item);
90 | $this->assertArrayHasKey('status', $item);
91 | $this->assertArrayHasKey('updatedAt', $item);
92 | $this->assertArrayHasKey('orderTime', $item);
93 | }
94 | }
95 |
96 | /**
97 | * @dataProvider apiProvider
98 | * @param Order $api
99 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
100 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
101 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
102 | */
103 | public function testGetDetail(Order $api)
104 | {
105 | $data = $api->getList(['symbol' => 'XBTUSDM'], ['currentPage' => 1, 'pageSize' => 10]);
106 | $this->assertPagination($data);
107 | $orders = $data['items'];
108 | if (isset($orders[0])) {
109 | $order = $api->getDetail($orders[0]['id']);
110 | $this->assertArrayHasKey('symbol', $order);
111 | $this->assertArrayHasKey('hidden', $order);
112 | $this->assertArrayHasKey('type', $order);
113 | $this->assertArrayHasKey('iceberg', $order);
114 | $this->assertArrayHasKey('createdAt', $order);
115 | $this->assertArrayHasKey('stopTriggered', $order);
116 | $this->assertArrayHasKey('id', $order);
117 | $this->assertArrayHasKey('timeInForce', $order);
118 | $this->assertArrayHasKey('side', $order);
119 | $this->assertArrayHasKey('dealSize', $order);
120 | $this->assertArrayHasKey('stp', $order);
121 | $this->assertArrayHasKey('postOnly', $order);
122 | $this->assertArrayHasKey('size', $order);
123 | $this->assertArrayHasKey('stop', $order);
124 | $this->assertArrayHasKey('settleCurrency', $order);
125 | $this->assertArrayHasKey('status', $order);
126 | $this->assertArrayHasKey('updatedAt', $order);
127 | $this->assertArrayHasKey('orderTime', $order);
128 | }
129 | }
130 |
131 | /**
132 | * @dataProvider apiProvider
133 | * @param Order $api
134 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
135 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
136 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
137 | */
138 | public function testCancel($api)
139 | {
140 | $result = $api->cancel($this->getOrderId($api));
141 | $this->assertInternalType('array', $result);
142 | $this->assertArrayHasKey('cancelledOrderIds', $result);
143 | }
144 |
145 | /**
146 | * @dataProvider apiProvider
147 | * @param Order $api
148 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
149 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
150 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
151 | */
152 | public function testBatchCancel($api)
153 | {
154 | $result = $api->batchCancel('XBTUSDM');
155 | $this->assertInternalType('array', $result);
156 | $this->assertArrayHasKey('cancelledOrderIds', $result);
157 | }
158 |
159 | /**
160 | * @dataProvider apiProvider
161 | * @param Order $api
162 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
163 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
164 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
165 | */
166 | public function testGetRecentList(Order $api)
167 | {
168 | $items = $api->getRecentDoneOrders();
169 | foreach ($items as $order) {
170 | $this->assertArrayHasKey('symbol', $order);
171 | $this->assertArrayHasKey('hidden', $order);
172 | $this->assertArrayHasKey('type', $order);
173 | $this->assertArrayHasKey('iceberg', $order);
174 | $this->assertArrayHasKey('createdAt', $order);
175 | $this->assertArrayHasKey('stopTriggered', $order);
176 | $this->assertArrayHasKey('id', $order);
177 | $this->assertArrayHasKey('timeInForce', $order);
178 | $this->assertArrayHasKey('side', $order);
179 | $this->assertArrayHasKey('dealSize', $order);
180 | $this->assertArrayHasKey('stp', $order);
181 | $this->assertArrayHasKey('postOnly', $order);
182 | $this->assertArrayHasKey('size', $order);
183 | $this->assertArrayHasKey('stop', $order);
184 | }
185 | }
186 |
187 | /**
188 | * @dataProvider apiProvider
189 | * @param Order $api
190 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
191 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
192 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
193 | */
194 | public function testOpenOrderStatistics($api)
195 | {
196 | $result = $api->getOpenOrderStatistics('XBTUSDM');
197 | $this->assertInternalType('array', $result);
198 | $this->assertArrayHasKey('openOrderBuySize', $result);
199 | $this->assertArrayHasKey('openOrderSellSize', $result);
200 | $this->assertArrayHasKey('openOrderBuyCost', $result);
201 | $this->assertArrayHasKey('openOrderSellCost', $result);
202 | }
203 |
204 | /**
205 | * @dataProvider apiProvider.
206 | *
207 | * @param Order $api
208 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
209 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
210 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
211 | */
212 | private function getOrderId($api)
213 | {
214 | $order = [
215 | 'clientOid' => uniqid(),
216 | 'type' => 'limit',
217 | 'side' => 'buy',
218 | 'symbol' => 'XBTUSDM',
219 | 'leverage' => 2,
220 | 'remark' => '\中文备注 ',
221 |
222 | 'price' => 100,
223 | 'size' => 1,
224 | ];
225 | $data = $api->create($order);
226 | $this->assertInternalType('array', $data);
227 | $this->assertArrayHasKey('orderId', $data);
228 | return $data['orderId'];
229 | }
230 |
231 | /**
232 | * @dataProvider apiProvider
233 | * @param Order $api
234 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
235 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
236 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
237 | */
238 | public function testGetDetailByClientOid(Order $api)
239 | {
240 | $clientOid = uniqid();
241 | $order = [
242 | 'clientOid' => $clientOid,
243 | 'type' => 'limit',
244 | 'side' => 'buy',
245 | 'symbol' => 'XBTUSDTM',
246 | 'leverage' => 1,
247 | 'remark' => 'create test order',
248 | 'price' => '1',
249 | 'size' => '1',
250 | ];
251 |
252 | $api->create($order);
253 | $order = $api->getDetailByClientOid($clientOid);
254 | $this->assertArrayHasKey('symbol', $order);
255 | $this->assertArrayHasKey('hidden', $order);
256 | $this->assertArrayHasKey('type', $order);
257 | $this->assertArrayHasKey('iceberg', $order);
258 | $this->assertArrayHasKey('createdAt', $order);
259 | $this->assertArrayHasKey('stopTriggered', $order);
260 | $this->assertArrayHasKey('id', $order);
261 | $this->assertArrayHasKey('timeInForce', $order);
262 | $this->assertArrayHasKey('side', $order);
263 | $this->assertArrayHasKey('dealSize', $order);
264 | $this->assertArrayHasKey('stp', $order);
265 | $this->assertArrayHasKey('postOnly', $order);
266 | $this->assertArrayHasKey('size', $order);
267 | $this->assertArrayHasKey('stop', $order);
268 | $this->assertArrayHasKey('settleCurrency', $order);
269 | $this->assertArrayHasKey('status', $order);
270 | $this->assertArrayHasKey('updatedAt', $order);
271 | $this->assertArrayHasKey('orderTime', $order);
272 | $api->cancel($order['id']);
273 | }
274 |
275 | /**
276 | * @dataProvider apiProvider
277 | * @param Order $api
278 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
279 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
280 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
281 | */
282 | public function testCancelByClientOid($api)
283 | {
284 | $clientId = uniqid();
285 | $symbol = 'DOTUSDTM';
286 | $order = [
287 | 'clientOid' => $clientId,
288 | 'type' => 'limit',
289 | 'side' => 'buy',
290 | 'symbol' => $symbol,
291 | 'leverage' => 5,
292 | 'remark' => 'test cancel order',
293 |
294 | 'price' => 6,
295 | 'size' => 1,
296 | ];
297 |
298 | $api->create($order);
299 | $result = $api->cancelByClientOid($clientId, $symbol);
300 | $this->assertInternalType('array', $result);
301 | $this->assertArrayHasKey('clientOid', $result);
302 | }
303 |
304 | /**
305 | * @dataProvider apiProvider
306 | * @param Order $api
307 | * @return void
308 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
309 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
310 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
311 | */
312 | public function testCreateTest(Order $api)
313 | {
314 | $order = [
315 | 'clientOid' => uniqid(),
316 | 'type' => 'limit',
317 | 'side' => 'buy',
318 | 'symbol' => 'DOTUSDM',
319 | 'leverage' => 2,
320 | 'remark' => 'create test order',
321 |
322 | 'price' => '1',
323 | 'size' => '1',
324 | ];
325 | $data = $api->createTest($order);
326 | $this->assertInternalType('array', $data);
327 | $this->assertArrayHasKey('orderId', $data);
328 | }
329 |
330 | /**
331 | * @dataProvider apiProvider
332 | *
333 | * @param Order $api
334 | * @return void
335 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
336 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
337 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
338 | */
339 | public function testCreateMultiOrders(Order $api)
340 | {
341 | $orders = [
342 | [
343 | 'clientOid' => uniqid(),
344 | 'type' => 'limit',
345 | 'side' => 'buy',
346 | 'symbol' => 'AAVEUSDTM',
347 | 'leverage' => 5,
348 | 'remark' => 'create test order',
349 | 'price' => '1',
350 | 'size' => '1',
351 | ],
352 | [
353 | 'clientOid' => uniqid(),
354 | 'type' => 'limit',
355 | 'side' => 'buy',
356 | 'symbol' => 'ETHUSDTM',
357 | 'leverage' => 5,
358 | 'remark' => 'create test order',
359 | 'price' => '1',
360 | 'size' => '1',
361 | ],
362 | ];
363 |
364 | $result = $api->createMultiOrders($orders);
365 | foreach ($result as $item) {
366 | $this->assertInternalType('array', $item);
367 | $this->assertArrayHasKey('orderId', $item);
368 | $this->assertArrayHasKey('clientOid', $item);
369 | $this->assertArrayHasKey('symbol', $item);
370 | }
371 | }
372 |
373 | /**
374 | * @dataProvider apiProvider
375 | *
376 | * @param Order $api
377 | * @return void
378 | * @throws \KuCoin\Futures\SDK\Exceptions\BusinessException
379 | * @throws \KuCoin\Futures\SDK\Exceptions\HttpException
380 | * @throws \KuCoin\Futures\SDK\Exceptions\InvalidApiUriException
381 | */
382 | public function testCreateStOrder(Order $api)
383 | {
384 | $order = [
385 | 'clientOid' => uniqid(),
386 | 'type' => 'limit',
387 | 'side' => 'buy',
388 | 'symbol' => 'XBTUSDTM',
389 | 'leverage' => 1,
390 | 'remark' => 'create test order',
391 | 'price' => '800',
392 | 'size' => 1,
393 | 'stopPriceType' => 'TP',
394 | 'triggerStopUpPrice' => '9000',
395 | 'triggerStopDownPrice' => '700',
396 | 'marginMode' => 'ISOLATED',
397 | ];
398 | $result = $api->createStOrder($order);
399 | $this->assertInternalType('array', $result);
400 | $this->assertArrayHasKey('orderId', $result);
401 | $this->assertArrayHasKey('clientOid', $result);
402 | }
403 | }
404 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP SDK for KuCoin Futures API
2 |
3 | > The detailed document [https://docs.kucoin.com/futures/](https://docs.kucoin.com/futures/), in order to receive the latest API change notifications, please `Watch` this repository.
4 |
5 | [](https://github.com/Kucoin/kucoin-futures-php-sdk/releases)
6 | [](https://secure.php.net)
7 | [](https://travis-ci.org/Kucoin/kucoin-futures-php-sdk)
8 | [](https://packagist.org/packages/kucoin/kucoin-futures-php-sdk)
9 | [](LICENSE)
10 |
11 | ## Requirements
12 |
13 | | Dependency | Requirement |
14 | |-------------------------------------------------------|-----------------------------|
15 | | [PHP](https://secure.php.net/manual/en/install.php) | `>=5.5.0` `Recommend PHP7+` |
16 | | [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) | `^6.0\|^7.0` |
17 |
18 | ## Install
19 |
20 | > Install package via [Composer](https://getcomposer.org/).
21 |
22 | ```shell
23 | composer require "kucoin/kucoin-futures-php-sdk:~1.0.0"
24 | ```
25 |
26 | ## Usage
27 |
28 | ### Choose environment
29 |
30 | | Environment | BaseUri |
31 | |--------------|-------------------------------------------|
32 | | *Production* | `https://api-futures.kucoin.com(DEFAULT)` |
33 |
34 | ```php
35 | use KuCoin\Futures\SDK\KuCoinFuturesApi;
36 | // Switch to the sandbox environment
37 | KuCoinFuturesApi::setBaseUri('https://api-sandbox-futures.kucoin.com');
38 | ```
39 |
40 | ### Debug mode & logging
41 |
42 | ```php
43 | use KuCoin\Futures\SDK\KuCoinFuturesApi;
44 | // Debug mode will record the logs of API and WebSocket to files in the directory "KuCoinFuturesApi::getLogPath()" according to the minimum log level "KuCoinFuturesApi::getLogLevel()".
45 | KuCoinFuturesApi::setDebugMode(true);
46 |
47 | // Logging in your code
48 | // KuCoinFuturesApi::setLogPath('/tmp');
49 | // KuCoinFuturesApi::setLogLevel(Monolog\Logger::DEBUG);
50 | KuCoinFuturesApi::getLogger()->debug("I'm a debug message");
51 | ```
52 |
53 | ### Examples
54 |
55 | > See the [test case](tests) for more examples.
56 |
57 | #### Example of API `without` authentication
58 |
59 | ```php
60 | use KuCoin\Futures\SDK\PublicApi\Time;
61 |
62 | $api = new Time();
63 | $timestamp = $api->timestamp();
64 | var_dump($timestamp);
65 | ```
66 |
67 | #### Example of API `with` authentication
68 |
69 | ##### **Note**
70 |
71 | To reinforce the security of the API, KuCoin upgraded the API key to version 2.0, the validation logic has also been changed. It is recommended to create(https://www.kucoin.com/account/api) and update your API key to version 2.0. The API key of
72 | version 1.0 will be still valid until May 1, 2021
73 |
74 | ```php
75 | use KuCoin\Futures\SDK\Auth;
76 | use KuCoin\Futures\SDK\PrivateApi\Account;
77 | use KuCoin\Futures\SDK\Exceptions\HttpException;
78 | use KuCoin\Futures\SDK\Exceptions\BusinessException;
79 |
80 | // Auth version v2 (recommend)
81 | $auth = new Auth('key', 'secret', 'passphrase', Auth::API_KEY_VERSION_V2);
82 | // Auth version v1
83 | // $auth = new Auth('key', 'secret', 'passphrase');
84 |
85 | $api = new Account($auth);
86 |
87 | try {
88 | $result = $api->getOverview();
89 | var_dump($result);
90 | } catch (HttpException $e) {
91 | var_dump($e->getMessage());
92 | } catch (BusinessException $e) {
93 | var_dump($e->getMessage());
94 | }
95 | ```
96 |
97 | #### Example of WebSocket feed
98 |
99 | ```php
100 | use KuCoin\Futures\SDK\Auth;
101 | use KuCoin\Futures\SDK\KuCoinFuturesApi;
102 | use KuCoin\Futures\SDK\PrivateApi\WebSocketFeed;
103 | use Ratchet\Client\WebSocket;
104 | use React\EventLoop\Factory;
105 | use React\EventLoop\LoopInterface;
106 |
107 | $auth = null;
108 | // Need to pass the Auth parameter when subscribing to a private channel($api->subscribePrivateChannel()).
109 | // Auth version v2 (recommend)
110 | // $auth = new Auth('key', 'secret', 'passphrase', Auth::API_KEY_VERSION_V2);
111 | // Auth version v1
112 | // $auth = new Auth('key', 'secret', 'passphrase');
113 | $api = new WebSocketFeed($auth);
114 |
115 | // Use a custom event loop instance if you like
116 | //$loop = Factory::create();
117 | //$loop->addPeriodicTimer(1, function () {
118 | // var_dump(date('Y-m-d H:i:s'));
119 | //});
120 | //$api->setLoop($loop);
121 |
122 | $query = ['connectId' => uniqid('', true)];
123 | $channels = [
124 | ['topic' => '/market/ticker:KCS-BTC'], // Subscribe multiple channels
125 | ['topic' => '/market/ticker:ETH-BTC'],
126 | ];
127 |
128 | $api->subscribePublicChannels($query, $channels, function (array $message, WebSocket $ws, LoopInterface $loop) use ($api) {
129 | var_dump($message);
130 |
131 | // Subscribe another channel
132 | // $ws->send(json_encode($api->createSubscribeMessage('/contractMarket/ticker:ETHUSDTM')));
133 |
134 | // Unsubscribe the channel
135 | // $ws->send(json_encode($api->createUnsubscribeMessage('/contractMarket/ticker:XBTUSDM')));
136 |
137 | // Stop loop
138 | // $loop->stop();
139 | }, function ($code, $reason) {
140 | echo "OnClose: {$code} {$reason}\n";
141 | });
142 | ```
143 |
144 | #### ⚡️Coroutine HTTP client for asynchronous IO
145 |
146 | > See the [benchmark](examples/BenchmarkCoroutine.php), almost `20x` faster than `curl`.
147 |
148 | ```bash
149 | pecl install swoole
150 | composer require swlib/saber
151 | ```
152 |
153 | ```php
154 | use KuCoin\Futures\SDK\Auth;
155 | use KuCoin\Futures\SDK\Http\SwooleHttp;
156 | use KuCoin\Futures\SDK\KuCoinFuturesApi;
157 | use KuCoin\Futures\SDK\PrivateApi\Order;
158 | use KuCoin\Futures\SDK\PublicApi\Time;
159 |
160 | // Require PHP 7.1+ and Swoole 2.1.2+
161 | // Require running in cli mode
162 |
163 | go(function () {
164 | $api = new Time(null, new SwooleHttp);
165 | $timestamp = $api->timestamp();
166 | var_dump($timestamp);
167 | });
168 |
169 | go(function () {
170 | // Auth version v2 (recommend)
171 | $auth = new Auth('key', 'secret', 'passphrase', Auth::API_KEY_VERSION_V2);
172 | // Auth version v1
173 | // $auth = new Auth('key', 'secret', 'passphrase');
174 | $api = new Order($auth, new SwooleHttp);
175 | // Create 50 orders CONCURRENTLY in 1 second
176 | for ($i = 0; $i < 50; $i++) {
177 | go(function () use ($api, $i) {
178 | $order = [
179 | 'clientOid' => uniqid(),
180 | 'price' => '1',
181 | 'size' => '1',
182 | 'symbol' => 'BTC-USDT',
183 | 'type' => 'limit',
184 | 'side' => 'buy',
185 | 'remark' => 'ORDER#' . $i,
186 | ];
187 | try {
188 | $result = $api->create($order);
189 | var_dump($result);
190 | } catch (\Throwable $e) {
191 | var_dump($e->getMessage());
192 | }
193 | });
194 | }
195 | });
196 | ```
197 |
198 | ### API list
199 |
200 |
201 | KuCoin\Futures\SDK\PrivateApi\Account
202 |
203 | | API | Authentication | Description |
204 | |----------------------------------------------------------------|----------------|-------------------------------------------------------------------------------------|
205 | | KuCoin\Futures\SDK\PrivateApi\Account::getOverview() | YES | https://docs.kucoin.com/futures/#account |
206 | | KuCoin\Futures\SDK\PrivateApi\Account::getTransactionHistory() | YES | https://docs.kucoin.com/futures/#get-transaction-history |
207 | | KuCoin\Futures\SDK\PrivateApi\Account::transferIn() | YES | `deprecated` |
208 | | KuCoin\Futures\SDK\PrivateApi\Account::transferOut() | YES | `deprecated` https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account |
209 | | KuCoin\Futures\SDK\PrivateApi\Account::transferOutV2() | YES | https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2 |
210 | | KuCoin\Futures\SDK\PrivateApi\Account::cancelTransferOut() | YES | `deprecated` https://docs.kucoin.com/futures/#cancel-transfer-out-request |
211 | | KuCoin\Futures\SDK\PrivateApi\Account::getTransferList() | YES | https://docs.kucoin.com/futures/#get-transfer-out-request-records |
212 | | KuCoin\Futures\SDK\PrivateApi\Account::getSubApikey() | YES | https://docs.kucoin.com/futures/#get-sub-account-futures-api-list |
213 | | KuCoin\Futures\SDK\PrivateApi\Account::createSubApikey() | YES | https://docs.kucoin.com/futures/#create-futures-apis-for-sub-account |
214 | | KuCoin\Futures\SDK\PrivateApi\Account::modifySubApikey() | YES | https://docs.kucoin.com/futures/#modify-sub-account-futures-apis |
215 | | KuCoin\Futures\SDK\PrivateApi\Account::deleteSubApikey() | YES | https://docs.kucoin.com/futures/#delete-sub-account-futures-apis |
216 | | KuCoin\Futures\SDK\PrivateApi\Account::transferOutV3() | YES | https://docs.kucoin.com/futures/#transfer-to-main-or-trade-account |
217 |
218 |
219 |
220 |
221 | KuCoin\Futures\SDK\PrivateApi\Deposit
222 |
223 | | API | Authentication | Description |
224 | |------------------------------------------------------|----------------|------------------------------------------------------|
225 | | KuCoin\Futures\SDK\PrivateApi\Deposit::getAddress() | YES | https://docs.kucoin.com/futures/#get-deposit-address |
226 | | KuCoin\Futures\SDK\PrivateApi\Deposit::getDeposits() | YES | https://docs.kucoin.com/futures/#get-deposit-list |
227 |
228 |
229 |
230 |
231 | KuCoin\Futures\SDK\PrivateApi\Fill
232 |
233 | | API | Authentication | Description |
234 | |-----------------------------------------------------|----------------|-----------------------------------------------|
235 | | KuCoin\Futures\SDK\PrivateApi\Fill::getFills() | YES | https://docs.kucoin.com/futures/#get-fills |
236 | | KuCoin\Futures\SDK\PrivateApi\Fill::getRecentList() | YES | https://docs.kucoin.com/futures/#recent-fills |
237 |
238 |
239 |
240 |
241 |
242 | KuCoin\Futures\SDK\PrivateApi\Fee
243 |
244 | | API | Authentication | Description |
245 | |---------------------------------------------------|----------------|------------------------------------------------------------------------------------|
246 | | KuCoin\Futures\SDK\PrivateApi\Fee::getTradeFees() | YES | https://www.kucoin.com/docs/rest/funding/trade-fee/trading-pair-actual-fee-futures |
247 |
248 |
249 |
250 |
251 | KuCoin\Futures\SDK\PrivateApi\Order
252 |
253 | | API | Authentication | Description |
254 | |---------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------|
255 | | KuCoin\Futures\SDK\PrivateApi\Order::create() | YES | https://docs.kucoin.com/futures/#place-an-order |
256 | | KuCoin\Futures\SDK\PrivateApi\Order::cancel() | YES | https://docs.kucoin.com/futures/#cancel-an-order |
257 | | KuCoin\Futures\SDK\PrivateApi\Order::batchCancel() | YES | https://docs.kucoin.com/futures/#limit-order-mass-cancelation |
258 | | KuCoin\Futures\SDK\PrivateApi\Order::stopOrders() | YES | https://docs.kucoin.com/futures/#stop-order-mass-cancelation |
259 | | KuCoin\Futures\SDK\PrivateApi\Order::getList() | YES | https://docs.kucoin.com/futures/#get-order-list |
260 | | KuCoin\Futures\SDK\PrivateApi\Order::getStopOrders() | YES | https://docs.kucoin.com/futures/#get-untriggered-stop-order-list |
261 | | KuCoin\Futures\SDK\PrivateApi\Order::getRecentDoneOrders() | YES | https://docs.kucoin.com/futures/#get-list-of-orders-completed-in-24h |
262 | | KuCoin\Futures\SDK\PrivateApi\Order::getDetail() | YES | https://docs.kucoin.com/futures/#get-details-of-a-single-order |
263 | | KuCoin\Futures\SDK\PrivateApi\Order::getDetailByClientOid() | YES | https://docs.kucoin.com/futures/#get-details-of-a-single-order |
264 | | KuCoin\Futures\SDK\PrivateApi\Order::getOpenOrderStatistics() | YES | https://docs.kucoin.com/futures/#active-order-value-calculation |
265 | | KuCoin\Futures\SDK\PrivateApi\Order::cancelByClientOid() | YES | https://www.kucoin.com/docs/rest/futures-trading/orders/cancel-order-by-clientoid |
266 | | KuCoin\Futures\SDK\PrivateApi\Order::createTest() | YES | https://www.kucoin.com/docs/rest/futures-trading/orders/place-order-test |
267 | | KuCoin\Futures\SDK\PrivateApi\Order::createStOrder() | YES | https://www.kucoin.com/docs/rest/futures-trading/orders/place-take-profit-and-stop-loss-order |
268 | | KuCoin\Futures\SDK\PrivateApi\Order::createMultiOrders() | YES | https://www.kucoin.com/docs/rest/futures-trading/orders/place-multiple-orders |
269 |
270 |
271 |
272 | KuCoin\Futures\SDK\PrivateApi\Position
273 |
274 | | API | Authentication | Description |
275 | |-------------------------------------------------------------------|----------------|-------------------------------------------------------------------------------------------|
276 | | KuCoin\Futures\SDK\PrivateApi\Position::getList() | YES | https://docs.kucoin.com/futures/#get-position-list |
277 | | KuCoin\Futures\SDK\PrivateApi\Position::getDetail() | YES | https://docs.kucoin.com/futures/#get-position-details |
278 | | KuCoin\Futures\SDK\PrivateApi\Position::changeAutoAppendStatus() | YES | https://docs.kucoin.com/futures/#enable-disable-of-auto-deposit-margin |
279 | | KuCoin\Futures\SDK\PrivateApi\Position::marginAppend() | YES | https://docs.kucoin.com/futures/#add-margin-manually |
280 | | KuCoin\Futures\SDK\PrivateApi\Position::getMaxWithdrawMargin() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/get-max-withdraw-margin |
281 | | KuCoin\Futures\SDK\PrivateApi\Position::withdrawMargin() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/remove-margin-manually |
282 | | KuCoin\Futures\SDK\PrivateApi\Position::getHistoryPositions() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/get-positions-history |
283 | | KuCoin\Futures\SDK\PrivateApi\Position::getMaxOpenSize() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/get-maximum-open-position-size |
284 | | KuCoin\Futures\SDK\PrivateApi\Position::modifyCrossUserLeverage() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/modify-cross-margin-leverage |
285 | | KuCoin\Futures\SDK\PrivateApi\Position::getCrossUserLeverage() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/get-cross-margin-leverage |
286 | | KuCoin\Futures\SDK\PrivateApi\Position::modifyMarginMode() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/modify-margin-mode |
287 | | KuCoin\Futures\SDK\PrivateApi\Position::getMarginMode() | YES | https://www.kucoin.com/docs/rest/futures-trading/positions/get-margin-mode |
288 |
289 |
290 |
291 |
292 | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed
293 |
294 | | API | Authentication | Description |
295 | |-------------------------------------------------------------------------|----------------|------------------------------------------------------|
296 | | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed::getPublicServer() | NO | https://docs.kucoin.com/futures/#apply-connect-token |
297 | | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed::getPrivateServer() | YES | https://docs.kucoin.com/futures/#apply-connect-token |
298 | | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed::subscribePublicChannel() | NO | https://docs.kucoin.com/futures/#public-channels |
299 | | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed::subscribePublicChannels() | NO | https://docs.kucoin.com/futures/#public-channels |
300 | | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed::subscribePrivateChannel() | YES | https://docs.kucoin.com/futures/#private-channels |
301 | | KuCoin\Futures\SDK\PrivateApi\WebSocketFeed::subscribePrivateChannels() | YES | https://docs.kucoin.com/futures/#private-channels |
302 |
303 |
304 |
305 |
306 | KuCoin\Futures\SDK\PrivateApi\Withdrawal
307 |
308 | | API | Authentication | Description |
309 | |-------------------------------------------------------|----------------|-------------------------------------------------------|
310 | | KuCoin\Futures\SDK\PrivateApi\Withdrawal::getQuotas() | YES | https://docs.kucoin.com/futures/#get-withdrawal-limit |
311 | | KuCoin\Futures\SDK\PrivateApi\Withdrawal::getList() | YES | https://docs.kucoin.com/futures/#get-withdrawal-list |
312 | | KuCoin\Futures\SDK\PrivateApi\Withdrawal::apply() | YES | https://docs.kucoin.com/futures/#withdraw-funds |
313 | | KuCoin\Futures\SDK\PrivateApi\Withdrawal::cancel() | YES | https://docs.kucoin.com/futures/#cancel-withdrawal |
314 |
315 |
316 |
317 |
318 | KuCoin\Futures\SDK\PrivateApi\RiskLimitLevel
319 |
320 | | API | Authentication | Description |
321 | |----------------------------------------------------------------------|----------------|------------------------------------------------------------------|
322 | | KuCoin\Futures\SDK\PrivateApi\RiskLimitLevel::getRiskLimitLevel | YES | https://docs.kucoin.com/futures/#obtain-futures-risk-limit-level |
323 | | KuCoin\Futures\SDK\PrivateApi\RiskLimitLevel::changeRiskLimitLevel() | YES | https://docs.kucoin.com/futures/#adjust-risk-limit-level |
324 |
325 |
326 |
327 |
328 | KuCoin\Futures\SDK\PublicApi\Symbol
329 |
330 | | API | Authentication | Description |
331 | |------------------------------------------------------------|----------------|------------------------------------------------------------------------------------------|
332 | | KuCoin\Futures\SDK\PublicApi\Symbol::getTicker() | NO | https://docs.kucoin.com/futures/#get-ticker |
333 | | KuCoin\Futures\SDK\PublicApi\Symbol::getLevel2Snapshot() | NO | https://docs.kucoin.com/futures/#get-full-order-book-level-2 |
334 | | KuCoin\Futures\SDK\PublicApi\Symbol::getLevel3Snapshot() | NO | https://docs.kucoin.com/futures/#get-full-order-book-level-3 |
335 | | KuCoin\Futures\SDK\PublicApi\Symbol::getV2Level3Snapshot() | NO | https://docs.kucoin.com/futures/#get-full-order-book-level-3-v2 |
336 | | KuCoin\Futures\SDK\PublicApi\Symbol::getLevel2Message() | NO | `deprecated` https://docs.kucoin.com/futures/##level-2-pulling-messages |
337 | | KuCoin\Futures\SDK\PublicApi\Symbol::getLevel3Message() | NO | `deprecated` https://docs.kucoin.com/futures/##level-3-pulling-messages |
338 | | KuCoin\Futures\SDK\PublicApi\Symbol::getTradeHistory() | NO | https://docs.kucoin.com/futures/#get-trade-histories |
339 | | KuCoin\Futures\SDK\PublicApi\Symbol::getKLines() | NO | https://docs.kucoin.com/futures/?lang=en_US#get-k-line-data-of-contract |
340 | | KuCoin\Futures\SDK\PublicApi\Symbol::getLevel2Depth20 | NO | https://docs.kucoin.com/futures/cn/#level-2-2 |
341 | | KuCoin\Futures\SDK\PublicApi\Symbol::getLevel2Depth100 | NO | https://docs.kucoin.com/futures/cn/#level-2-2 |
342 | | KuCoin\Futures\SDK\PublicApi\Symbol::getFundingRates | NO | https://www.kucoin.com/docs/rest/futures-trading/funding-fees/get-public-funding-history |
343 |
344 |
345 |
346 |
347 | KuCoin\Futures\SDK\PublicApi\Contract
348 |
349 | | API | Authentication | Description |
350 | |--------------------------------------------------------|----------------|--------------------------------------------------------------------------------------------------|
351 | | KuCoin\Futures\SDK\PublicApi\Contract::getList() | NO | https://www.kucoin.com/docs/rest/futures-trading/market-data/get-symbols-list |
352 | | KuCoin\Futures\SDK\PublicApi\Contract::getDetail() | NO | https://www.kucoin.com/docs/rest/futures-trading/market-data/get-symbol-detail |
353 | | KuCoin\Futures\SDK\PublicApi\Contract::getAllTickers() | NO | https://www.kucoin.com/docs/rest/futures-trading/market-data/get-latest-ticker-for-all-contracts |
354 |
355 |
356 |
357 |
358 | KuCoin\Futures\SDK\PublicApi\Time
359 |
360 | | API | Authentication | Description |
361 | |------------------------------------------------|----------------|----------------------------------------------|
362 | | KuCoin\Futures\SDK\PublicApi\Time::timestamp() | NO | https://docs.kucoin.com/futures/#server-time |
363 |
364 |
365 |
366 |
367 | KuCoin\Futures\SDK\PublicApi\Status
368 |
369 | | API | Authentication | Description |
370 | |-----------------------------------------------|----------------|---------------------------------------------------------|
371 | | KuCoin\Futures\SDK\PublicApi\Status::status() | NO | https://docs.kucoin.com/futures/#get-the-service-status |
372 |
373 |
374 |
375 | ## Run tests
376 |
377 | > Modify your API key in `phpunit.xml` first.
378 |
379 | ```shell
380 | # Add your API configuration items into the environmental variable first
381 | export API_BASE_URI=https://api-futures.kucoin.com
382 | export API_KEY=key
383 | export API_SECRET=secret
384 | export API_PASSPHRASE=passphrase
385 | export API_KEY_VERSION=2
386 | export API_DEBUG_MODE=1
387 |
388 | composer test
389 | ```
390 |
391 | ## License
392 |
393 | [MIT](LICENSE)
394 |
--------------------------------------------------------------------------------