diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index b152f32e..8a26c4b0 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -31,8 +31,10 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress - - name: Tests + - name: Static Tests run: composer test + - name: Live Tests + run: composer live-tests # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" # Docs: https://getcomposer.org/doc/articles/scripts.md diff --git a/.gitignore b/.gitignore index b8341e4d..27694189 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -composer.lock +# composer.lock vendor** .buildpath .project diff --git a/README.md b/README.md index 0b96f4bb..b36baf40 100755 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/683459a5a71c4875956cf23078a0c39b)](https://www.codacy.com/app/dmzoneill/php-binance-api?utm_source=github.com&utm_medium=referral&utm_content=jaggedsoft/php-binance-api&utm_campaign=Badge_Grade) --> # PHP Binance API -This project is designed to help you make your own projects that interact with [Binance](https://accounts.binance.com/register?ref=PGDFCE46). You can stream candlestick chart data, market depth, or use other advanced features such as setting stop losses and iceberg orders. This project seeks to have complete API coverage including WebSockets. +This project is designed to help you make your own projects that interact with [Binance](https://accounts.binance.com/register?ref=PGDFCE46). You can stream candlestick chart data, market depth, or use other advanced features such as setting stop losses and iceberg orders. This project seeks to have complete API coverage (spot and futures) including WebSockets. #### Installation ``` diff --git a/composer.json b/composer.json index 46f07a82..f32532aa 100755 --- a/composer.json +++ b/composer.json @@ -8,14 +8,14 @@ "url": "https://github.com/jaggedsoft/php-binance-api" }], "require": { - "php": ">=7.0", + "php": ">=7.4", "ext-curl": "*", "ratchet/pawl": "^0.4.0", "react/socket": "^1.0 || ^0.8 || ^0.7", "ratchet/rfc6455": "^0.3" }, "require-dev": { - "phpunit/phpunit": "~6", + "phpunit/phpunit": "^12.0", "codacy/coverage": "dev-master" }, "config": { @@ -27,5 +27,9 @@ "php-binance-api.php", "php-binance-api-rate-limiter.php" ] + }, + "scripts": { + "test": "phpunit tests/BinanceStaticTests.php", + "live-tests": "phpunit tests/BinanceLiveTests.php" } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..6fbf9835 --- /dev/null +++ b/composer.lock @@ -0,0 +1,3517 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "28935d50104c1b0223eaf4b0081c1fd1", + "packages": [ + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ratchet/pawl", + "version": "v0.4.3", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/Pawl.git", + "reference": "2c582373c78271de32cb04c755c4c0db7e09c9c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/Pawl/zipball/2c582373c78271de32cb04c755c4c0db7e09c9c0", + "reference": "2c582373c78271de32cb04c755c4c0db7e09c9c0", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0", + "guzzlehttp/psr7": "^2.0", + "php": ">=7.4", + "ratchet/rfc6455": "^0.3.1 || ^0.4.0", + "react/socket": "^1.9" + }, + "require-dev": { + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8" + }, + "suggest": { + "reactivex/rxphp": "~2.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "Ratchet\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Asynchronous WebSocket client", + "keywords": [ + "Ratchet", + "async", + "client", + "websocket", + "websocket client" + ], + "support": { + "issues": "https://github.com/ratchetphp/Pawl/issues", + "source": "https://github.com/ratchetphp/Pawl/tree/v0.4.3" + }, + "time": "2025-03-19T16:47:38+00:00" + }, + { + "name": "ratchet/rfc6455", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/RFC6455.git", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/7c964514e93456a52a99a20fcfa0de242a43ccdb", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2 || ^1.7", + "php": ">=5.4.2" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "react/socket": "^1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ratchet\\RFC6455\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "role": "Developer" + }, + { + "name": "Matt Bonneau", + "role": "Developer" + } + ], + "description": "RFC6455 WebSocket protocol handler", + "homepage": "http://socketo.me", + "keywords": [ + "WebSockets", + "rfc6455", + "websocket" + ], + "support": { + "chat": "https://gitter.im/reactphp/reactphp", + "issues": "https://github.com/ratchetphp/RFC6455/issues", + "source": "https://github.com/ratchetphp/RFC6455/tree/v0.3.1" + }, + "time": "2021-12-09T23:20:49+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/socket", + "version": "v1.16.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.16.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-07-26T10:38:09+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + } + ], + "packages-dev": [ + { + "name": "codacy/coverage", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/codacy/php-codacy-coverage.git", + "reference": "656913b35e22ae0d1ec352bc00e3ad90616efb7a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codacy/php-codacy-coverage/zipball/656913b35e22ae0d1ec352bc00e3ad90616efb7a", + "reference": "656913b35e22ae0d1ec352bc00e3ad90616efb7a", + "shasum": "" + }, + "require": { + "gitonomy/gitlib": ">=1.0", + "php": ">=5.3.3", + "symfony/console": "~2.5|~3.0|~4.0|~5.0" + }, + "require-dev": { + "clue/phar-composer": "^1.1", + "phpunit/phpunit": "~6.5" + }, + "bin": [ + "bin/codacycoverage" + ], + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakob Pupke", + "email": "jakob.pupke@gmail.com" + } + ], + "description": "Sends PHP test coverage information to Codacy.", + "homepage": "https://github.com/codacy/php-codacy-coverage", + "support": { + "issues": "https://github.com/codacy/php-codacy-coverage/issues", + "source": "https://github.com/codacy/php-codacy-coverage/tree/master" + }, + "abandoned": true, + "time": "2020-02-11T15:55:24+00:00" + }, + { + "name": "gitonomy/gitlib", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/gitonomy/gitlib.git", + "reference": "ac17834888bf399a4ecae5e108be52c8c5f93958" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/ac17834888bf399a4ecae5e108be52c8c5f93958", + "reference": "ac17834888bf399a4ecae5e108be52c8c5f93958", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "php": "^8.0", + "symfony/polyfill-mbstring": "^1.7", + "symfony/process": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "ext-fileinfo": "*", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.20 || ^9.5.9", + "psr/log": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Gitonomy\\Git\\": "src/Gitonomy/Git/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Julien Didier", + "email": "genzo.wm@gmail.com", + "homepage": "https://github.com/juliendidier" + }, + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info", + "homepage": "https://github.com/lyrixx" + }, + { + "name": "Alexandre Salomé", + "email": "alexandre.salome@gmail.com", + "homepage": "https://github.com/alexandresalome" + } + ], + "description": "Library for accessing git", + "support": { + "issues": "https://github.com/gitonomy/gitlib/issues", + "source": "https://github.com/gitonomy/gitlib/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/gitonomy/gitlib", + "type": "tidelift" + } + ], + "time": "2024-11-03T15:59:21+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "12.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "05c33d01a856f9f62488d144bafddc3d7b7a4ebb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/05c33d01a856f9f62488d144bafddc3d7b7a4ebb", + "reference": "05c33d01a856f9f62488d144bafddc3d7b7a4ebb", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-04-03T14:34:39+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:37+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:58+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:16+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:38+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "12.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "6f2775cc4b7b19ba5a411c188e855eb0cc78a711" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6f2775cc4b7b19ba5a411c188e855eb0cc78a711", + "reference": "6f2775cc4b7b19ba5a411c188e855eb0cc78a711", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.1.2", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.0.0", + "sebastian/comparator": "^7.0.1", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.0", + "sebastian/exporter": "^7.0.0", + "sebastian/global-state": "^8.0.0", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.2", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.1-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.2" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-04-08T08:05:27+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/6d584c727d9114bcdc14c86711cd1cad51778e7c", + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:53:50+00:00" + }, + { + "name": "sebastian/comparator", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "b478f34614f934e0291598d0c08cbaba9644bee5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b478f34614f934e0291598d0c08cbaba9644bee5", + "reference": "b478f34614f934e0291598d0c08cbaba9644bee5", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-07T07:00:32+00:00" + }, + { + "name": "sebastian/complexity", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "8afe311eca49171bf95405cc0078be9a3821f9f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8afe311eca49171bf95405cc0078be9a3821f9f2", + "reference": "8afe311eca49171bf95405cc0078be9a3821f9f2", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:56:08+00:00" + }, + { + "name": "sebastian/exporter", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "76432aafc58d50691a00d86d0632f1217a47b688" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/76432aafc58d50691a00d86d0632f1217a47b688", + "reference": "76432aafc58d50691a00d86d0632f1217a47b688", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:56:42+00:00" + }, + { + "name": "sebastian/global-state", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc", + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:56:59+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:28+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:48+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:17+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c405ae3a63e01b32eb71577f8ec1604e39858a7c", + "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:01+00:00" + }, + { + "name": "sebastian/type", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/1d7cd6e514384c36d7a390347f57c385d4be6069", + "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-18T13:37:31+00:00" + }, + { + "name": "sebastian/version", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/console", + "version": "v5.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", + "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-06T11:30:55+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-13T12:21:46+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v6.4.15", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.4.15" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-13T13:31:12+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "codacy/coverage": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4", + "ext-curl": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/php-binance-api.php b/php-binance-api.php index 93778a83..d3d5c02c 100755 --- a/php-binance-api.php +++ b/php-binance-api.php @@ -33,7 +33,13 @@ class API protected $baseTestnet = 'https://testnet.binance.vision/api/'; // /< Testnet REST endpoint for the currency exchange protected $wapi = 'https://api.binance.com/wapi/'; // /< REST endpoint for the withdrawals protected $sapi = 'https://api.binance.com/sapi/'; // /< REST endpoint for the supporting network API - protected $fapi = 'https://fapi.binance.com/'; // /< REST endpoint for the futures API + protected $fapi = 'https://fapi.binance.com/fapi/'; // /< REST endpoint for the futures API + protected $fapiData = 'https://fapi.binance.com/futures/data/'; // /< REST endpoint for the futures API + protected $fapiTestnet = 'https://testnet.binancefuture.com/fapi/'; // /< Testnet REST endpoint for the futures API + protected $dapi = 'https://dapi.binance.com/dapi/'; // /< REST endpoint for the delivery API + protected $dapiData = 'https://dapi.binance.com/futures/data/'; // /< REST endpoint for the delivery API + protected $dapiTestnet = 'https://testnet.binancefuture.com/dapi/'; // /< Testnet REST endpoint for the delivery API + protected $papi = 'https://papi.binance.com/papi/'; // /< REST endpoint for the options API protected $bapi = 'https://www.binance.com/bapi/'; // /< REST endpoint for the internal Binance API protected $stream = 'wss://stream.binance.com:9443/ws/'; // /< Endpoint for establishing websocket connections protected $streamTestnet = 'wss://testnet.binance.vision/ws/'; // /< Testnet endpoint for establishing websocket connections @@ -54,17 +60,21 @@ class API protected $requestCount = 0; // /< This stores the amount of API requests protected $httpDebug = false; // /< If you enable this, curl will output debugging information protected $subscriptions = []; // /< View all websocket subscriptions - protected $btc_value = 0.00; // /< value of available assets - protected $btc_total = 0.00; // /< value of available onOrder assets - + protected $exchangeInfo = null; + protected $futuresExchangeInfo = null; protected $lastRequest = []; protected $xMbxUsedWeight = 0; protected $xMbxUsedWeight1m = 0; + public $headers = []; + + private $SPOT_ORDER_PREFIX = "x-HNA2TXFJ"; + private $CONTRACT_ORDER_PREFIX = "x-Cb7ytekJ"; + /** * Constructor for the class, * send as many argument as you want. @@ -219,6 +229,20 @@ protected function setupProxyConfigFromFile(string $file = null) } } + public static function uuid22($length = 22) { + return bin2hex(random_bytes(intval($length / 2))); + } + + protected function generateSpotClientOrderId() + { + return $this->SPOT_ORDER_PREFIX . self::uuid22(); + } + + protected function generateFuturesClientOrderId() + { + return $this->CONTRACT_ORDER_PREFIX . self::uuid22();; + } + /** * buy attempts to create a currency order * each currency supports a number of order types, such as @@ -378,8 +402,8 @@ public function marketBuyTest(string $symbol, $quantity, array $flags = []) { return $this->order("BUY", $symbol, $quantity, 0, "MARKET", $flags, true); } - - + + /** * numberOfDecimals() returns the signifcant digits level based on the minimum order amount. * @@ -495,7 +519,7 @@ public function cancel(string $symbol, $orderid, $flags = []) * $order = $api->orderStatus("BNBBTC", $orderid); * * @param $symbol string the currency symbol - * @param $orderid string the orderid to cancel + * @param $orderid string the orderid to fetch * @return array with error message or the order details * @throws \Exception */ @@ -570,6 +594,8 @@ public function orders(string $symbol, int $limit = 500, int $fromOrderId = 0, a /** * history Get the complete account trade history for all or a specific currency + * @deprecated + * use myTrades() instead * * $BNBHistory = $api->history("BNBBTC"); * $limitBNBHistory = $api->history("BNBBTC",5); @@ -602,6 +628,19 @@ public function history(string $symbol, int $limit = 500, int $fromTradeId = -1, return $this->httpRequest("v3/myTrades", "GET", $parameters, true); } + /** + * myTrades + * another name for history + * @see history() + * + * @return array with error message or array of orderDetails array + * @throws \Exception + */ + public function myTrades(string $symbol, int $limit = 500, int $fromTradeId = -1, int $startTime = null, int $endTime = null) + { + return $this->history($symbol, $limit, $fromTradeId, $startTime, $endTime); + } + /** * useServerTime adds the 'useServerTime'=>true to the API request to avoid time errors * @@ -633,7 +672,7 @@ public function time() /** * exchangeInfo - Gets the complete exchange info, including limits, currency options etc. - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#exchange-information * * $info = $api->exchangeInfo(); @@ -660,32 +699,32 @@ public function exchangeInfo($symbols = null) if (gettype($symbols) == "string") { $parameters["symbol"] = $symbols; $arr = $this->httpRequest("v3/exchangeInfo", "GET", $parameters); - } + } if (gettype($symbols) == "array") { - $arr = $this->httpRequest('v3/exchangeInfo?symbols=' . '["' . implode('","', $symbols) . '"]'); + $arr = $this->httpRequest("v3/exchangeInfo?symbols=" . '["' . implode('","', $symbols) . '"]'); } } else { $arr = $this->httpRequest("v3/exchangeInfo"); } - + $this->exchangeInfo = $arr; $this->exchangeInfo['symbols'] = null; - + foreach ($arr['symbols'] as $key => $value) { $this->exchangeInfo['symbols'][$value['symbol']] = $value; } } - + return $this->exchangeInfo; } - + /** * assetDetail - Fetch details of assets supported on Binance - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#asset-detail-user_data - * + * * @property int $weight 1 - * + * * @param string $asset (optional) Should be an asset, e.g. BNB or empty to get the full list * * @return array containing the response @@ -711,10 +750,10 @@ public function assetDetail($asset = '') 'success' => 0, 'assetDetail' => array(), ); - + } } - + /** * userAssetDribbletLog - Log of the conversion of the dust assets to BNB * @deprecated @@ -725,17 +764,17 @@ public function userAssetDribbletLog() trigger_error('Deprecated - function will disappear on 2021-08-01 from Binance. Please switch to $api->dustLog().', E_USER_DEPRECATED); return $this->httpRequest("v3/userAssetDribbletLog.html", 'GET', $params, true); } - + /** * dustLog - Log of the conversion of the dust assets to BNB - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#dustlog-user_data - * + * * @property int $weight 1 - * + * * @param long $startTime (optional) Start time, e.g. 1617580799000 * @param long $endTime (optional) End time, e.g. 1617580799000. Endtime is mandatory if startTime is set. - * + * * @return array containing the response * @throws \Exception */ @@ -752,13 +791,13 @@ public function dustLog($startTime = NULL, $endTime = NULL) /** * dustTransfer - Convert dust assets ( < 0.001 BTC) to BNB - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#dust-transfer-user_data - * + * * @property int $weight 1 - * + * * @param string|array $assets (mandatory) Asset(s), e.g. IOST or array like ['IOST','AAVE','CHZ'] - * + * * @return array containing the response * @throws \Exception */ @@ -769,7 +808,7 @@ public function dustTransfer($assets) return $this->httpRequest("v1/asset/dust", 'POST', $params, true); } - + /** * Fetch current(daily) trade fee of symbol, values in percentage. * for more info visit binance official api document @@ -789,16 +828,16 @@ public function tradeFee(string $symbol) /** * commissionFee - Fetch commission trade fee - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#trade-fee-user_data - * + * * @property int $weight 1 - * + * * @param string $symbol (optional) Should be a symbol, e.g. BNBUSDT or empty to get the full list - * + * * @return array containing the response * @throws \Exception - */ + */ public function commissionFee($symbol = '') { $params = array('sapi' => true); @@ -810,23 +849,23 @@ public function commissionFee($symbol = '') /** * withdraw - Submit a withdraw request to move an asset to another wallet - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi - * + * * @example https://github.com/jaggedsoft/php-binance-api#withdraw Standard withdraw * @example https://github.com/jaggedsoft/php-binance-api#withdraw-with-addresstag Withdraw with addressTag for e.g. XRP - * + * * @property int $weight 1 - * + * * @param string $asset (mandatory) An asset, e.g. BTC * @param string $address (mandatory) The address where to send, e.g. 1C5gqLRs96Xq4V2ZZAR1347yUCpHie7sa or 44tLjmXrQNrWJ5NBsEj2R77ZBEgDa3fEe9GLpSf2FRmhexPvfYDUAB7EXX1Hdb3aMQ9FLqdJ56yaAhiXoRsceGJCRS3Jxkn * @param string $amount (mandatory) The amount, e.g. 0.2 * @param string $addressTag (optional) Mandatory secondary address for some assets (XRP,XMR,etc), e.g. 0e5e38a01058dbf64e53a4333a5acf98e0d5feb8e523d32e3186c664a9c762c1 * @param string $addressName (optional) Description of the address * @param string $transactionFeeFlag (optional) When making internal transfer, true for returning the fee to the destination account; false for returning the fee back to the departure account. - * @param string $network (optional) + * @param string $network (optional) * @param string $orderId (optional) Client id for withdraw - * + * * @return array containing the response * @throws \Exception */ @@ -846,7 +885,7 @@ public function withdraw(string $asset, string $address, $amount, $addressTag = $options['addressTag'] = $addressTag; } if ($transactionFeeFlag) $options['transactionFeeFlag'] = true; - + if (is_null($network) === false && empty($network) === false) { $options['network'] = $network; } @@ -858,14 +897,14 @@ public function withdraw(string $asset, string $address, $amount, $addressTag = /** * depositAddress - Get the deposit address for an asset - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data - * + * * @property int $weight 1 - * + * * @param string $asset (mandatory) An asset, e.g. BTC - * @param string $network (optional) You can get network in networkList from /sapi/v1/capital/config/getall - * + * @param string $network (optional) You can get network in networkList from /sapi/v1/capital/config/getall + * * @return array containing the response * @throws \Exception */ @@ -878,13 +917,13 @@ public function depositAddress(string $asset, $network = null) if (is_null($network) === false && empty($network) === false) { $params['network'] = $network; } - + $return = $this->httpRequest("v1/capital/deposit/address", "GET", $params, true); // Adding for backwards compatibility with wapi $return['asset'] = $return['coin']; $return['addressTag'] = $return['tag']; - + if (!empty($return['address'])) { $return['success'] = 1; } else { @@ -896,14 +935,14 @@ public function depositAddress(string $asset, $network = null) /** * depositHistory - Get the deposit history for one or all assets - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#deposit-history-supporting-network-user_data - * + * * @property int $weight 1 - * + * * @param string $asset (optional) An asset, e.g. BTC - or leave empty for all - * @param array $params (optional) An array of additional parameters that the API endpoint allows - * + * @param array $params (optional) An array of additional parameters that the API endpoint allows + * * @return array containing the response * @throws \Exception */ @@ -919,21 +958,21 @@ public function depositHistory(string $asset = null, array $params = []) foreach ($return as $key=>$item) { $return[$key]['asset'] = $item['coin']; } - + return $return; - + } /** * withdrawHistory - Get the withdraw history for one or all assets - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data - * + * * @property int $weight 1 - * + * * @param string $asset (optional) An asset, e.g. BTC - or leave empty for all - * @param array $params (optional) An array of additional parameters that the API endpoint allows: status, offset, limit, startTime, endTime - * + * @param array $params (optional) An array of additional parameters that the API endpoint allows: status, offset, limit, startTime, endTime + * * @return array containing the response * @throws \Exception */ @@ -947,7 +986,7 @@ public function withdrawHistory(string $asset = null, array $params = []) $return = array( 'withdrawList' => $this->httpRequest("v1/capital/withdraw/history", "GET", $params, true) ); - + // Adding for backwards compatibility with wapi $return['success'] = 1; @@ -956,11 +995,11 @@ public function withdrawHistory(string $asset = null, array $params = []) /** * withdrawFee - Get the withdrawal fee for an asset - * + * * @property int $weight 1 - * + * * @param string $asset (mandatory) An asset, e.g. BTC - * + * * @return array containing the response * @throws \Exception */ @@ -975,6 +1014,126 @@ public function withdrawFee(string $asset) } } + /** + * transfer - Transfer asset between accounts + * possible types of transfer are: + * - MAIN_UMFUTURE - Spot account transfer to USDⓈ-M Futures account + * - MAIN_CMFUTURE - Spot account transfer to COIN-M Futures account + * - MAIN_MARGIN - Spot account transfer to Margin(cross)account + * - UMFUTURE_MAIN - USDⓈ-M Futures account transfer to Spot account + * - UMFUTURE_MARGIN - USDⓈ-M Futures account transfer to Margin(cross)account + * - CMFUTURE_MAIN - COIN-M Futures account transfer to Spot account + * - CMFUTURE_MARGIN - COIN-M Futures account transfer to Margin(cross) account + * - MARGIN_MAIN - Margin(cross)account transfer to Spot account + * - MARGIN_UMFUTURE - Margin(cross)account transfer to USDⓈ-M Futures + * - MARGIN_CMFUTURE - Margin(cross)account transfer to COIN-M Futures + * - ISOLATEDMARGIN_MARGIN - Isolated margin account transfer to Margin(cross) account + * - MARGIN_ISOLATEDMARGIN - Margin(cross) account transfer to Isolated margin account + * - ISOLATEDMARGIN_ISOLATEDMARGIN - Isolated margin account transfer to Isolated margin account + * - MAIN_FUNDING - Spot account transfer to Funding account + * - FUNDING_MAIN - Funding account transfer to Spot account + * - FUNDING_UMFUTURE - Funding account transfer to UMFUTURE account + * - UMFUTURE_FUNDING - UMFUTURE account transfer to Funding account + * - MARGIN_FUNDING - MARGIN account transfer to Funding account + * - FUNDING_MARGIN - Funding account transfer to Margin account + * - FUNDING_CMFUTURE - Funding account transfer to CMFUTURE account + * - CMFUTURE_FUNDING - CMFUTURE account transfer to Funding account + * - MAIN_OPTION - Spot account transfer to Options account + * - OPTION_MAIN - Options account transfer to Spot account + * - UMFUTURE_OPTION - USDⓈ-M Futures account transfer to Options account + * - OPTION_UMFUTURE - Options account transfer to USDⓈ-M Futures account + * - MARGIN_OPTION - Margin(cross)account transfer to Options account + * - OPTION_MARGIN - Options account transfer to Margin(cross)account + * - FUNDING_OPTION - Funding account transfer to Options account + * - OPTION_FUNDING - Options account transfer to Funding account + * - MAIN_PORTFOLIO_MARGIN - Spot account transfer to Portfolio Margin account + * - PORTFOLIO_MARGIN_MAIN - Portfolio Margin account transfer to Spot account + * + * @link https://developers.binance.com/docs/wallet/asset/user-universal-transfer + * + * @property int $weight 900 + * + * @param string $type (mandatory) type of transfer, e.g. MAIN_MARGIN + * @param string $asset (mandatory) an asset, e.g. BTC + * @param string $amount (mandatory) the amount to transfer + * @param string $fromSymbol (optional) must be sent when type are ISOLATEDMARGIN_MARGIN and ISOLATEDMARGIN_ISOLATEDMARGIN + * @param string $toSymbol (optional) must be sent when type are MARGIN_ISOLATEDMARGIN and ISOLATEDMARGIN_ISOLATEDMARGIN + * @param int $recvWindow (optional) the time in milliseconds to wait for the transfer to complete + * + * @return array containing the response + * @throws \Exception + */ + public function transfer(string $type, string $asset, string $amount, $fromSymbol = null, $toSymbol = null, int $recvWindow = null) + { + $params = [ + 'type' => $type, + 'asset' => $asset, + 'amount' => $amount, + ]; + // todo: check this method with real account + if ($fromSymbol) { + $params['fromSymbol'] = $fromSymbol; + } + if ($toSymbol) { + $params['toSymbol'] = $toSymbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + + return $this->httpRequest("v1/asset/transfer", 'POST', $params, true); + } + + /** + * transfersHistory - get the transfer history between accounts + * + * @link https://developers.binance.com/docs/wallet/asset/query-user-universal-transfer + * + * @property int $weight 1 + * + * @param string $type (optional) type of transfer, e.g. MAIN_MARGIN (@see transfer()) + * @param string $startTime (optional) start time in milliseconds + * @param string $endTime (optional) end time in milliseconds + * @param int $limit (optional) the number of records to return (default 10, max 100) + * @param int $current (optional) default 1 + * @param string $fromSymbol (optional) must be sent when type are ISOLATEDMARGIN_MARGIN and ISOLATEDMARGIN_ISOLATEDMARGIN + * @param string $toSymbol (optional) must be sent when type are MARGIN_ISOLATEDMARGIN and ISOLATEDMARGIN_ISOLATEDMARGIN + * @param int $recvWindow (optional) the time in milliseconds to wait for the transfer to complete + * + * @return array containing the response + * @throws \Exception + */ + public function transfersHistory(string $type, $startTime = null, $endTime = null, $limit = null, $current = null, $fromSymbol = null, $toSymbol = null, $recvWindow = null) + { + $params = [ + 'type' => $type, + ]; + // todo: check this method with real account + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['size'] = $limit; + } + if ($current) { + $params['current'] = $current; + } + if ($fromSymbol) { + $params['fromSymbol'] = $fromSymbol; + } + if ($toSymbol) { + $params['toSymbol'] = $toSymbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + + return $this->httpRequest("v1/asset/transfer", 'GET', $params, true); + } + /** * prices get all the current prices * @@ -1064,7 +1223,7 @@ public function aggTrades(string $symbol) "symbol" => $symbol, ])); } - + /** * historicalTrades - Get historical trades for a specific currency * @@ -1134,30 +1293,43 @@ public function depth(string $symbol, int $limit = 100) /** * balances get balances for the account assets * - * $balances = $api->balances($ticker); + * $balances = $api->balances(); + * + * @param string $market_type (optional) market type - "spot" or "futures" (default is "spot") + * @param int $recvWindow (optional) the time in milliseconds to wait for the transfer to complete (not for spot) + * @param string $api_version (optional) not for spot - the api version to use (default is v2) * - * @param bool $priceData array of the symbols balances are required for * @return array with error message or array of balances * @throws \Exception */ - public function balances($priceData = false) + public function balances(string $market_type = 'spot', $recvWindow = null, string $api_version = 'v2') { - if (is_array($priceData) === false) { - $priceData = false; + $is_spot = $market_type === 'spot'; + $params = []; + if ($is_spot) { + $url = "v3/account"; + } else { + $params['fapi'] = true; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + if ($api_version === 'v2') { + $url = "v2/balance"; + } else if ($api_version === 'v3') { + $url = "v3/balance"; + } else { + throw new \Exception("Invalid API version specified. Use 'v2' or 'v3'."); + } } - - $account = $this->httpRequest("v3/account", "GET", [], true); - - if (is_array($account) === false) { + $response = $this->httpRequest($url, "GET", $params, true); + if (is_array($response) === false) { echo "Error: unable to fetch your account details" . PHP_EOL; } - - if (isset($account['balances']) === false || empty($account['balances'])) { + if (empty($response) || ($is_spot && (isset($response['balances']) === false || empty($response['balances'])))) { echo "Error: your balances were empty or unset" . PHP_EOL; return []; } - - return $this->balanceData($account, $priceData); + return $this->balanceData($response, $market_type); } /** @@ -1169,7 +1341,7 @@ public function balances($priceData = false) */ public function coins() { - return $this->httpRequest('v1/capital/config/getall', 'GET', [ 'sapi' => true ], true); + return $this->httpRequest("v1/capital/config/getall", 'GET', [ 'sapi' => true ], true); } /** @@ -1236,6 +1408,20 @@ public function setProxy(array $proxyconf) $this->proxyConf = $proxyconf; } + + protected function curl_exec($curl) + { + return curl_exec($curl); + } + + protected function curl_set_url($curl, $endpoint) { + curl_setopt($curl, CURLOPT_URL, $endpoint); + } + + protected function curl_set_body($curl, $option, $query) { + curl_setopt($curl, $option, $query); + } + /** * httpRequest curl wrapper for all http api requests. * You can't call this function directly, use the helper functions @@ -1264,8 +1450,78 @@ protected function httpRequest(string $url, string $method = "GET", array $param } } + $base = $this->base; + if ($this->useTestnet) { + $base = $this->baseTestnet; + } + + if (isset($params['wapi'])) { + if ($this->useTestnet) { + throw new \Exception("wapi endpoints are not available in testnet"); + } + unset($params['wapi']); + $base = $this->wapi; + } + + if (isset($params['sapi'])) { + if ($this->useTestnet) { + throw new \Exception("sapi endpoints are not available in testnet"); + } + unset($params['sapi']); + $base = $this->sapi; + } + + if (isset($params['fapi'])) { + unset($params['fapi']); + $base = $this->useTestnet ? $this->fapiTestnet : $this->fapi; + } + + if (isset($params['fapiData'])) { + if ($this->useTestnet) { + throw new \Exception("fapiData endpoints are not available in testnet"); + } + unset($params['fapiData']); + $base = $this->fapiData; + } + + if (isset($params['dapi'])) { + unset($params['dapi']); + $base = $this->useTestnet ? $this->dapiTestnet : $this->dapi; + } + + if (isset($params['dapiData'])) { + if ($this->useTestnet) { + throw new \Exception("dapiData endpoints are not available in testnet"); + } + unset($params['dapiData']); + $base = $this->dapiData; + } + + if (isset($params['papi'])) { + if ($this->useTestnet) { + throw new \Exception("papi endpoints are not available in testnet"); + } + unset($params['papi']); + $base = $this->papi; + } + + if (isset($params['bapi'])) { + if ($this->useTestnet) { + throw new \Exception("bapi endpoints are not available in testnet"); + } + unset($params['bapi']); + $base = $this->bapi; + } + $curl = curl_init(); curl_setopt($curl, CURLOPT_VERBOSE, $this->httpDebug); + + //set custom headers if any + curl_setopt_array($curl, [ + CURLOPT_HTTPHEADER => $this->headers, + // Optional: other cURL options + ]); + $query = $this->binance_build_query($params); // signed with params @@ -1278,34 +1534,8 @@ protected function httpRequest(string $url, string $method = "GET", array $param throw new \Exception("signedRequest error: API Secret not set!"); } - $base = $this->getRestEndpoint(); $ts = (microtime(true) * 1000) + $this->info['timeOffset']; $params['timestamp'] = number_format($ts, 0, '.', ''); - if (isset($params['wapi'])) { - if ($this->useTestnet) { - throw new \Exception("wapi endpoints are not available in testnet"); - } - unset($params['wapi']); - $base = $this->wapi; - } - - if (isset($params['sapi'])) { - if ($this->useTestnet) { - throw new \Exception("sapi endpoints are not available in testnet"); - } - unset($params['sapi']); - $base = $this->sapi; - } - - if (isset($params['fapi'])) { - unset($params['fapi']); - $base = $this->fapi; - } - - if (isset($params['bapi'])) { - unset($params['bapi']); - $base = $this->bapi; - } $query = $this->binance_build_query($params); $query = str_replace([ '%40' ], [ '@' ], $query);//if send data type "e-mail" then binance return: [Signature for this request is not valid.] $signature = hash_hmac('sha256', $query, $this->api_secret); @@ -1317,18 +1547,18 @@ protected function httpRequest(string $url, string $method = "GET", array $param $endpoint = $base . $url . '?' . $query . '&signature=' . $signature; } - curl_setopt($curl, CURLOPT_URL, $endpoint); + $this->curl_set_url($curl, $endpoint); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'X-MBX-APIKEY: ' . $this->api_key, )); } // params so buildquery string and append to url elseif (count($params) > 0) { - curl_setopt($curl, CURLOPT_URL, $this->getRestEndpoint() . $url . '?' . $query); + $this->curl_set_url($curl, $base . $url . '?' . $query); } // no params so just the base url else { - curl_setopt($curl, CURLOPT_URL, $this->getRestEndpoint() . $url); + $this->curl_set_url($curl, $base . $url); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'X-MBX-APIKEY: ' . $this->api_key, )); @@ -1337,7 +1567,7 @@ protected function httpRequest(string $url, string $method = "GET", array $param // Post and postfields if ($method === "POST") { curl_setopt($curl, CURLOPT_POST, true); - curl_setopt($curl, CURLOPT_POSTFIELDS, $query); + $this->curl_set_body($curl, CURLOPT_POSTFIELDS, $query); } // Delete Method if ($method === "DELETE") { @@ -1372,22 +1602,22 @@ protected function httpRequest(string $url, string $method = "GET", array $param } } - $output = curl_exec($curl); + $output = $this->curl_exec($curl); // Check if any error occurred - if (curl_errno($curl) > 0) { - // should always output error, not only on httpdebug - // not outputing errors, hides it from users and ends up with tickets on github - throw new \Exception('Curl error: ' . curl_error($curl)); - } - + // if (curl_errno($curl) > 0) { + // // should always output error, not only on httpdebug + // // not outputing errors, hides it from users and ends up with tickets on github + // throw new \Exception('Curl error: ' . curl_error($curl)); + // } + $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE); $header = $this->get_headers_from_curl_response($output); $output = substr($output, $header_size); - + curl_close($curl); - + $json = json_decode($output, true); - + $this->lastRequest = [ 'url' => $url, 'method' => $method, @@ -1405,7 +1635,7 @@ protected function httpRequest(string $url, string $method = "GET", array $param } if (isset($json['msg']) && !empty($json['msg'])) { - if ( $url != 'v1/system/status' && $url != 'v3/systemStatus.html' && $url != 'v3/accountStatus.html') { + if ($json['msg'] !== 'success' && $url != 'v1/system/status' && $url != 'v3/systemStatus.html' && $url != 'v3/accountStatus.html' && $url != 'v1/allOpenOrders') { // should always output error, not only on httpdebug // not outputing errors, hides it from users and ends up with tickets on github throw new \Exception('signedRequest error: '.print_r($output, true)); @@ -1418,11 +1648,11 @@ protected function httpRequest(string $url, string $method = "GET", array $param /** * binance_build_query - Wrapper for http_build_query to allow arrays as parameters - * + * * sapi v1/asset/dust can have an array, so it needs a conversion - * + * * @param array $params (mandatory) Parameters to convert to http query - * + * * @return array containing the response * @throws \Exception */ @@ -1443,8 +1673,8 @@ protected function binance_build_query($params = []) $query = $query_add . $query; return $query; - } - + } + /** * Converts the output of the CURL header to an array * @@ -1534,11 +1764,13 @@ public function order(string $side, string $symbol, $quantity, $price, string $t if (isset($flags['newOrderRespType'])) { $opt['newOrderRespType'] = $flags['newOrderRespType']; } - + if (isset($flags['newClientOrderId'])) { $opt['newClientOrderId'] = $flags['newClientOrderId']; + } else { + $opt['newClientOrderId'] = $this->generateSpotClientOrderId(); } - + $qstring = ($test === false) ? "v3/order" : "v3/order/test"; return $this->httpRequest($qstring, "POST", $opt, true); } @@ -1549,7 +1781,7 @@ public function order(string $side, string $symbol, $quantity, $price, string $t * * $candles = $api->candlesticks("BNBBTC", "5m"); * - * @param $symbol string to query + * @param $symbol market symbol to get the response for, e.g. ETHUSDT * @param $interval string to request * @param $limit int limit the amount of candles * @param $startTime string request candle information starting from here @@ -1598,88 +1830,40 @@ public function candlesticks(string $symbol, string $interval = "5m", int $limit /** * balanceData Converts all your balances into a nice array - * If priceData is passed from $api->prices() it will add btcValue & btcTotal to each symbol - * This function sets $btc_value which is your estimated BTC value of all assets combined and $btc_total which includes amount on order - * - * $candles = $api->candlesticks("BNBBTC", "5m"); * - * @param $array array of your balances * @param $priceData array of prices * @return array containing the response */ - protected function balanceData(array $array, $priceData) + protected function balanceData(array $array, string $marketType = 'spot') { $balances = []; - - if (is_array($priceData)) { - $btc_value = $btc_total = 0.00; - } - - if (empty($array) || empty($array['balances'])) { + $is_spot = $marketType === 'spot'; + if (empty($array) || ($is_spot && empty($array['balances']))) { // WPCS: XSS OK. echo "balanceData error: Please make sure your system time is synchronized: call \$api->useServerTime() before this function" . PHP_EOL; echo "ERROR: Invalid request. Please double check your API keys and permissions." . PHP_EOL; return []; } - - foreach ($array['balances'] as $obj) { + $rawBalances = $is_spot ? $array['balances'] : $array; + foreach ($rawBalances as $obj) { $asset = $obj['asset']; - $balances[$asset] = [ - "available" => $obj['free'], - "onOrder" => $obj['locked'], - "btcValue" => 0.00000000, - "btcTotal" => 0.00000000, - ]; - - if (is_array($priceData) === false) { - continue; - } - - if ($obj['free'] + $obj['locked'] < 0.00000001) { - continue; - } - - if ($asset === 'BTC') { - $balances[$asset]['btcValue'] = $obj['free']; - $balances[$asset]['btcTotal'] = $obj['free'] + $obj['locked']; - $btc_value += $obj['free']; - $btc_total += $obj['free'] + $obj['locked']; - continue; - } elseif ($asset === 'USDT' || $asset === 'USDC' || $asset === 'PAX' || $asset === 'BUSD') { - $btcValue = $obj['free'] / $priceData['BTCUSDT']; - $btcTotal = ($obj['free'] + $obj['locked']) / $priceData['BTCUSDT']; - $balances[$asset]['btcValue'] = $btcValue; - $balances[$asset]['btcTotal'] = $btcTotal; - $btc_value += $btcValue; - $btc_total += $btcTotal; - continue; - } - - $symbol = $asset . 'BTC'; - - if ($symbol === 'BTCUSDT') { - $btcValue = number_format($obj['free'] / $priceData['BTCUSDT'], 8, '.', ''); - $btcTotal = number_format(($obj['free'] + $obj['locked']) / $priceData['BTCUSDT'], 8, '.', ''); - } elseif (isset($priceData[$symbol]) === false) { - $btcValue = $btcTotal = 0; + $avaliable = 0.00000000; + $onOrder = 0.00000000; + if ($is_spot) { + $avaliable = $obj['free']; + $onOrder = $obj['locked']; + $total = $avaliable + $onOrder; } else { - $btcValue = number_format($obj['free'] * $priceData[$symbol], 8, '.', ''); - $btcTotal = number_format(($obj['free'] + $obj['locked']) * $priceData[$symbol], 8, '.', ''); + $avaliable = $obj['availableBalance']; + $total = $obj['balance']; + $onOrder = $total - $avaliable; } - - $balances[$asset]['btcValue'] = $btcValue; - $balances[$asset]['btcTotal'] = $btcTotal; - $btc_value += $btcValue; - $btc_total += $btcTotal; - } - if (is_array($priceData)) { - uasort($balances, function ($opA, $opB) { - if ($opA == $opB) - return 0; - return ($opA['btcValue'] < $opB['btcValue']) ? 1 : -1; - }); - $this->btc_value = $btc_value; - $this->btc_total = $btc_total; + $balances[$asset] = [ + "available" => $avaliable, + "onOrder" => $onOrder, + "total" => $total, + "info" => $obj, + ]; } return $balances; } @@ -1780,16 +1964,8 @@ protected function executionHandler(\stdClass $json) * @param $ticks array of the canbles array * @return array object of the chartdata */ - protected function chartData(string $symbol, string $interval, array $ticks) + protected function chartData(string $symbol, string $interval, array $ticks, string $market_type = "spot", string $kline_type = 'klines') { - if (!isset($this->info[$symbol])) { - $this->info[$symbol] = []; - } - - if (!isset($this->info[$symbol][$interval])) { - $this->info[$symbol][$interval] = []; - } - $output = []; foreach ($ticks as $tick) { list($openTime, $open, $high, $low, $close, $assetVolume, $closeTime, $baseVolume, $trades, $assetBuyVolume, $takerBuyVolume, $ignored) = $tick; @@ -1810,8 +1986,32 @@ protected function chartData(string $symbol, string $interval, array $ticks) ]; } - if (isset($openTime)) { - $this->info[$symbol][$interval]['firstOpen'] = $openTime; + if ($market_type !== "spot") { + if (!isset($this->info[$market_type])) { + $this->info[$market_type] = []; + } + if (!isset($this->info[$market_type][$symbol])) { + $this->info[$market_type][$symbol] = []; + } + if (!isset($this->info[$market_type][$symbol][$kline_type])) { + $this->info[$market_type][$symbol][$kline_type] = []; + } + if (!isset($this->info[$market_type][$symbol][$kline_type][$interval])) { + $this->info[$market_type][$symbol][$kline_type][$interval] = []; + } + if (isset($openTime)) { + $this->info[$market_type][$symbol][$kline_type][$interval]['firstOpen'] = $openTime; + } + } else { + if (!isset($this->info[$symbol])) { + $this->info[$symbol] = []; + } + if (!isset($this->info[$symbol][$interval])) { + $this->info[$symbol][$interval] = []; + } + if (isset($openTime)) { + $this->info[$symbol][$interval]['firstOpen'] = $openTime; + } } return $output; @@ -2017,7 +2217,7 @@ public function displayDepth(array $array) * @param $json array of the depth infomration * @return array of the depth information */ - protected function depthData(string $symbol, array $json) + protected function depthData(string $symbol, array $json, string $product_type = null) { $bids = $asks = []; foreach ($json['bids'] as $obj) { @@ -2026,10 +2226,16 @@ protected function depthData(string $symbol, array $json) foreach ($json['asks'] as $obj) { $asks[$obj[0]] = $obj[1]; } - return $this->depthCache[$symbol] = [ + $result = [ "bids" => $bids, "asks" => $asks, ]; + if (isset($product_type)) { + $this->depthCache[$symbol][$product_type] = $result; + } else { + $this->depthCache[$symbol] = $result; + } + return $result; } /** @@ -2808,7 +3014,7 @@ protected function downloadCurlCaBundle() fwrite($fp, $result); fclose($fp); } - + protected function floorDecimal($n, $decimals=2) { return floor($n * pow(10, $decimals)) / pow(10, $decimals); @@ -2835,11 +3041,6 @@ public function getXMbxUsedWeight1m() : int return $this->xMbxUsedWeight1m; } - private function getRestEndpoint() : string - { - return $this->useTestnet ? $this->baseTestnet : $this->base; - } - private function getWsEndpoint() : string { return $this->useTestnet ? $this->streamTestnet : $this->stream; @@ -2855,9 +3056,10 @@ public function isOnTestnet() : bool * * @link https://binance-docs.github.io/apidocs/spot/en/#test-connectivity * @link https://binance-docs.github.io/apidocs/spot/en/#system-status-system - * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api + * * @property int $weight 2 - * + * * @return array containing the response * @throws \Exception */ @@ -2866,27 +3068,34 @@ public function systemStatus() $arr = array(); $api_status = $this->httpRequest("v3/ping", 'GET'); if ( empty($api_status) ) { - $arr['api']['status'] = 'ping ok'; + $arr['api']['status'] = 'ping ok'; + } else { + $arr['api']['status'] = $api_status; + } + + $fapi_status = $this->httpRequest("v1/ping", 'GET', [ 'fapi' => true ]); + if ( empty($fapi_status) ) { + $arr['fapi']['status'] = 'ping ok'; } else { - $arr['api']['status'] = $api_status; + $arr['fapi']['status'] = $fapi_status; } - - $arr['sapi'] = $this->httpRequest("v1/system/status", 'GET', [ 'sapi' => true ], true); + + $arr['sapi'] = $this->httpRequest("v1/system/status", 'GET', [ 'sapi' => true ]); return $arr; } - + /** * accountSnapshot - Daily Account Snapshot at 00:00:00 UTC - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#daily-account-snapshot-user_data - * + * * @property int $weight 1 - * + * * @param string $type (mandatory) Should be SPOT, MARGIN or FUTURES * @param int $nbrDays (optional) Number of days. Default 5, min 5, max 30 * @param long $startTime (optional) Start time, e.g. 1617580799000 * @param long $endTime (optional) End time, e.g. 1617667199000 - * + * * @return array containing the response * @throws \Exception */ @@ -2894,29 +3103,29 @@ public function accountSnapshot($type, $nbrDays = 5, $startTime = 0, $endTime = { if ($nbrDays < 5 || $nbrDays > 30) $nbrDays = 5; - + $params = [ 'sapi' => true, 'type' => $type, ]; - + if ($startTime > 0) $params['startTime'] = $startTime; if ($endTime > 0) $params['endTime'] = $startTime; if ($nbrDays != 5) $params['limit'] = $nbrDays; - + return $this->httpRequest("v1/accountSnapshot", 'GET', $params, true); } - + /** * accountStatus - Fetch account status detail. - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#account-status-user_data - * + * * @property int $weight 1 - * + * * @return array containing the response * @throws \Exception */ @@ -2941,14 +3150,14 @@ public function apiRestrictions() { return $this->httpRequest("v1/account/apiRestrictions", 'GET', ['sapi' => true], true); } - + /** * apiTradingStatus - Fetch account API trading status detail. - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#account-api-trading-status-user_data - * + * * @property int $weight 1 - * + * * @return array containing the response * @throws \Exception */ @@ -2958,14 +3167,14 @@ public function apiTradingStatus() $arr['sapi'] = $this->httpRequest("v1/account/apiTradingStatus", 'GET', [ 'sapi' => true ], true); return $arr; } - + /** * ocoOrder - Create a new OCO order - * + * * @link https://binance-docs.github.io/apidocs/spot/en/#new-oco-trade - * + * * @property int $weight 1 - * + * * @param string $side (mandatory) Should be SELL or BUY * @param string $symbol (mandatory) The symbol, e.g. BTCBUSD * @param float $quantity (mandatory) Quantity to buy/sell @@ -2974,7 +3183,7 @@ public function apiTradingStatus() * @param int $stoplimitprice (optional) Stop Limit Price * @param int $stoplimittimeinforce (optional) GTC, FOK or IOC * @param array $flags (optional) Extra flags/parameters - * + * * @return array containing the response * @throws \Exception */ @@ -3023,7 +3232,7 @@ public function ocoOrder(string $side, string $symbol, $quantity, $price, $stopp } return $this->httpRequest("v3/order/oco", "POST", $opt, true); - } + } /** * avgPrice - get the average price of a symbol based on the last 5 minutes @@ -3043,13 +3252,13 @@ public function avgPrice(string $symbol) return $ticker['price']; } - + /********************************************* - * + * * Binance Liquid Swap (bswap) functions - * + * * https://binance-docs.github.io/apidocs/spot/en/#bswap-endpoints - * + * *********************************************/ /** @@ -3071,7 +3280,2822 @@ public function bswapQuote($baseAsset, $quoteAsset, $quoteQty) { 'baseAsset' => $baseAsset, 'quoteQty' => $quoteQty, ]; - + return $this->httpRequest("v1/bswap/quote", 'GET', $opt, true); } -} + + /********************************************* + * + * Binance futures (fapi) functions + * + * https://developers.binance.com/docs/derivatives/usds-margined-futures/general-info + * + *********************************************/ + + /** + * futuresTime Gets the server time + * + * $time = $api->futuresTime(); + * + * @return array with error message or array with server time key + * @throws \Exception + */ + public function futuresTime() + { + return $this->httpRequest("v1/time", "GET", [ 'fapi' => true ]); + } + + /** + * futuresExchangeInfo - Gets the complete exchange info, including limits, currency options etc. for futures + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Exchange-Information + * + * $info = $api->futuresExchangeInfo(); + * + * @property int $weight 1 + * + * @return array containing the response + * @throws \Exception + */ + public function futuresExchangeInfo() + { + if (!$this->futuresExchangeInfo) { + $arr = array(); + $arr['symbols'] = array(); + + $arr = $this->httpRequest("v1/exchangeInfo", "GET", [ 'fapi' => true ]); + + $this->futuresExchangeInfo = $arr; + $this->futuresExchangeInfo['symbols'] = null; + + foreach ($arr['symbols'] as $key => $value) { + $this->futuresExchangeInfo['symbols'][$value['symbol']] = $value; + } + } + + return $this->futuresExchangeInfo; + } + + /** + * futuresDepth get Market depth for futures + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Order-Book + * + * $depth = $api->futuresDepth("ETHBTC"); + * + * @property int $weight 10 + * for limit 5, 10, 20, 50 - weight 2 + * for limit 100 - weight 5 + * for limit 500 (default) - weight 10 + * for limit 1000 - weight 20 + * + * @param string $symbol (mandatory) the symbol to get the depth information for, e.g. ETHUSDT + * @param int $limit (optional) $limit set limition for number of market depth data, default 500, max 1000 (possible values are 5, 10, 20, 50, 100, 500, 1000) + * @return array with error message or array of market depth + * @throws \Exception + */ + public function futuresDepth(string $symbol, int $limit = null) + { + if (isset($symbol) === false || is_string($symbol) === false) { + // WPCS: XSS OK. + echo "asset: expected bool false, " . gettype($symbol) . " given" . PHP_EOL; + } + + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($limit) { + $params['limit'] = $limit; + } + $json = $this->httpRequest("v1/depth", "GET", $params); + if (isset($this->info[$symbol]) === false) { + $this->info[$symbol] = []; + $this->info[$symbol]['futures'] = []; + } + $this->info[$symbol]['futures']['firstUpdate'] = $json['lastUpdateId']; + return $this->depthData($symbol, $json, 'futures'); + } + + /** + * futuresRecentTrades - Get recent trades for a specific currency + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Recent-Trades-List + * + * $trades = $api->futuresRecentTrades("ETHBTC"); + * + * @property int $weight 5 + * + * @param string $symbol (mandatory) the symbol to query, e.g. ETHUSDT + * @param int $limit (optional) limit the amount of trades, default 500, max 1000 + * + * @return array containing the response + * @throws \Exception + */ + public function futuresRecentTrades(string $symbol, int $limit = null) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($limit) { + $parameters['limit'] = $limit; + } + return $this->httpRequest("v1/trades", "GET", $parameters); + } + + /** + * futuresHistoricalTrades - Get historical trades for a specific currency + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Old-Trades-Lookup + * + * $trades = $api->futuresHistoricalTrades("ETHBTC"); + * + * @property int $weight 20 + * + * @param string $symbol (mandatory) the symbol to query, e.g. ETHUSDT + * @param int $limit (optional) limit the amount of trades, default 100, max 500 + * @param int $tradeId (optional) return the orders from this orderId onwards, negative to get recent ones + * + * @return array containing the response + * @throws \Exception + */ + public function futuresHistoricalTrades(string $symbol, int $limit = null, int $tradeId = null) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($limit) { + $parameters['limit'] = $limit; + } + if ($tradeId) { + $parameters['fromId'] = $tradeId; + } + return $this->httpRequest("v1/historicalTrades", "GET", $parameters, true); + } + + /** + * futuresAggTrades get Market History / Aggregate Trades + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Compressed-Aggregate-Trades-List + * + * $trades = $api->futuresAggTrades("BNBBTC"); + * + * @property int $weight 20 + * + * @param string $symbol (mandatory) the symbol to get the trade information for, e.g. ETHUSDT + * @param int $fromId (optional) ID to get aggregate trades from INCLUSIVE + * @param int $startTime (optional) timestamp in ms to get aggregate trades from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get aggregate trades until INCLUSIVE + * @param int $limit (optional) the amount of trades, default 500, max 1000 + * + * @return array with error message or array of market history + * @throws \Exception + */ + public function futuresAggTrades(string $symbol, int $fromId = null, int $startTime = null, int $endTime = null, int $limit = null) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($fromId) { + $parameters['fromId'] = $fromId; + } + if ($startTime) { + $parameters['startTime'] = $startTime; + } + if ($endTime) { + $parameters['endTime'] = $endTime; + } + if ($limit) { + $parameters['limit'] = $limit; + } + return $this->tradesData($this->httpRequest("v1/aggTrades", "GET", $parameters)); + } + + /** + * futuresCandlesticks get the candles for the given intervals + * 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Kline-Candlestick-Data + * + * $candles = $api->futuresCandlesticks("BNBBTC", "5m"); + * + * @property int $weight 5 + * for limit < 100 - weight 1 + * for limit < 500 - weight 2 + * for limit <= 1000 - weight 5 + * for limit > 1000 - weight 10 + * + * @param string $symbol (mandatory) the symbol to query, e.g. ETHUSDT + * @param string $interval (optional) string to request - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M (default 5m) + * @param int $limit (optional) int limit the amount of candles (default 500, max 1000) + * @param int $startTime (optional) string request candle information starting from here + * @param int $endTime (optional) string request candle information ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresCandlesticks(string $symbol, string $interval = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->futuresCandlesticksHelper($symbol, $interval, $limit, $startTime, $endTime, 'klines'); + } + + /** + * futuresContinuousCandlesticks get the candles for the given intervals + * 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Continuous-Contract-Kline-Candlestick-Data + * + * $candles = $api->futuresContinuousCandlesticks("BNBBTC", "5m"); + * + * @property int $weight 5 + * for limit < 100 - weight 1 + * for limit < 500 - weight 2 + * for limit <= 1000 - weight 5 + * for limit > 1000 - weight 10 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $interval (optional) string to request - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M (default 5m) + * @param int $limit (optional) int limit the amount of candles (default 500, max 1000) + * @param int $startTime (optional) string request candle information starting from here + * @param int $endTime (optional) string request candle information ending here + * @param string $contractType (optional) string to request - PERPETUAL, CURRENT_QUARTER, NEXT_QUARTER (default PERPETUAL) + * + * @return array containing the response + * @throws \Exception + */ + public function futuresContinuousCandlesticks(string $symbol, string $interval = '5m', int $limit = null, $startTime = null, $endTime = null, $contractType = 'PERPETUAL') + { + return $this->futuresCandlesticksHelper($symbol, $interval, $limit, $startTime, $endTime, 'continuousKlines', $contractType); + } + + /** + * futuresIndexPriceCandlesticks get the candles for the given intervals + * 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Index-Price-Kline-Candlestick-Data + * + * $candles = $api->futuresIndexPriceCandlesticks("BNBBTC", "5m"); + * + * @property int $weight 5 + * for limit < 100 - weight 1 + * for limit < 500 - weight 2 + * for limit <= 1000 - weight 5 + * for limit > 1000 - weight 10 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $interval (optional) string to request - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M (default 5m) + * @param int $limit (optional) int limit the amount of candles (default 500, max 1000) + * @param int $startTime (optional) string request candle information starting from here + * @param int $endTime (optional) string request candle information ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresIndexPriceCandlesticks(string $symbol, string $interval = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->futuresCandlesticksHelper($symbol, $interval, $limit, $startTime, $endTime, 'indexPriceKlines'); + } + + /** + * futuresMarkPriceCandlesticks get the candles for the given intervals + * 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Mark-Price-Kline-Candlestick-Data + * + * $candles = $api->futuresMarkPriceCandlesticks("BNBBTC", "5m"); + * + * @property int $weight 5 + * for limit < 100 - weight 1 + * for limit < 500 - weight 2 + * for limit <= 1000 - weight 5 + * for limit > 1000 - weight 10 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $interval (optional) string to request - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M (default 5m) + * @param int $limit (optional) int limit the amount of candles (default 500, max 1000) + * @param int $startTime (optional) string request candle information starting from here + * @param int $endTime (optional) string request candle information ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresMarkPriceCandlesticks(string $symbol, string $interval = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->futuresCandlesticksHelper($symbol, $interval, $limit, $startTime, $endTime, 'markPriceKlines'); + } + + /** + * futuresPremiumIndexKlines get the candles for the given intervals + * 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Premium-Index-Kline-Data + * + * $candles = $api->futuresPremiumIndexKlines("ETHBTC", "5m"); + * + * @property int $weight 5 + * for limit < 100 - weight 1 + * for limit < 500 - weight 2 + * for limit <= 1000 - weight 5 + * for limit > 1000 - weight 10 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $interval (optional) string to request - 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M (default 5m) + * @param int $limit (optional) int limit the amount of candles (default 500, max 1000) + * @param int $startTime (optional) string request candle information starting from here + * @param int $endTime (optional) string request candle information ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPremiumIndexKlines(string $symbol, string $interval = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->futuresCandlesticksHelper($symbol, $interval, $limit, $startTime, $endTime, 'premiumIndexKlines'); + } + + /** + * futuresCandlesticksHelper + * helper for routing the futuresCandlesticks, futuresContinuousCandlesticks, futuresIndexPriceCandlesticks, futuresMarkPriceCandlesticks and futuresPremiumIndexKlines + */ + private function futuresCandlesticksHelper($symbol, $interval, $limit, $startTime, $endTime, $klineType, $contractType = null) + { + if (!isset($this->charts['futures'])) { + $this->charts['futures'] = []; + } + if (!isset($this->charts['futures'][$symbol])) { + $this->charts['futures'][$symbol] = []; + } + if (!isset($this->charts['futures'][$symbol][$type])) { + $this->charts['futures'][$symbol][$type] = []; + } + if (!isset($this->charts['futures'][$symbol][$type][$interval])) { + $this->charts['futures'][$symbol][$type][$interval] = []; + } + $params = [ + 'interval' => $interval, + 'fapi' => true, + ]; + if ($klineType === 'continuousKlines' || $klineType === 'indexPriceKlines') { + $params['pair'] = $symbol; + } else { + $params['symbol'] = $symbol; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($contractType) { + $params['contractType'] = $contractType; + } + + $response = $this->httpRequest("v1/{$klineType}", 'GET', $params); + + if (is_array($response) === false) { + return []; + } + if (count($response) === 0) { + echo "warning: fapi/v1/{$klineType} returned empty array, usually a blip in the connection or server" . PHP_EOL; + return []; + } + + $candlesticks = $this->chartData($symbol, $interval, $response, 'futures', $klineType); + $this->charts['futures'][$symbol][$klineType][$interval] = $candlesticks; + return $candlesticks; + } + + /** + * futuresMarkPrice get the mark price for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Mark-Price + * + * $markPrice = $api->futuresMarkPrice(); + * $markPrice = $api->futuresMarkPrice("ETHBTC"); + * + * @property int $weight 1 + * + * @param string $symbol (optional) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresMarkPrice(string $symbol = null) + { + $parameters = [ + 'fapi' => true, + ]; + if ($symbol) { + $parameters['symbol'] = $symbol; + } + return $this->httpRequest("v1/premiumIndex", "GET", $parameters); + } + + /** + * futuresFundingRateHistory get the funding rate history for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Get-Funding-Rate-History + * + * $fundingRate = $api->futuresFundingRateHistory(); + * $fundingRate = $api->futuresFundingRateHistory("ETHBTC"); + * + * @param string $symbol (optional) market symbol to get the response for, e.g. ETHUSDT + * @param int $limit (optional) int limit the amount of funding rate history (default 100, max 1000) + * @param int $startTime (optional) string request funding rate history starting from here + * @param int $endTime (optional) string request funding rate history ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresFundingRateHistory(string $symbol = null, int $limit = null, $startTime = null, $endTime = null) + { + $parameters = [ + 'fapi' => true, + ]; + if ($symbol) { + $parameters['symbol'] = $symbol; + } + if ($limit) { + $parameters['limit'] = $limit; + } + if ($startTime) { + $parameters['startTime'] = $startTime; + } + if ($endTime) { + $parameters['endTime'] = $endTime; + } + return $this->httpRequest("v1/fundingRate", "GET", $parameters); + } + + /** + * futuresFundingInfo get the funding rate history for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Get-Funding-Rate-Info + * + * $fundingInfo = $api->futuresFundingInfo(); + * + * @property int $weight 1 + * + * @return array containing the response + * @throws \Exception + */ + public function futuresFundingInfo() + { + $parameters = [ + 'fapi' => true, + ]; + return $this->httpRequest("v1/fundingInfo", "GET", $parameters); + } + + /** + * futuresPrevDay get 24 hour price change statistics for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/24hr-Ticker-Price-Change-Statistics + * + * $ticker = $api->futuresPrevDay(); + * $ticker = $api->futuresPrevDay("ETHBTC"); + * + * @property int $weight 1 + * if the symbol parameter is omitted weight is 40 + * + * @param string $symbol (optional) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPrevDay(string $symbol = null) + { + $parameters = [ + 'fapi' => true, + ]; + if ($symbol) { + $parameters['symbol'] = $symbol; + } + return $this->httpRequest("v1/ticker/24hr", "GET", $parameters); + } + + /** + * futuresPrice get the latest price for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Symbol-Price-Ticker + * + * $price = $api->futuresPrice('ETHUSDT'); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPrice(string $symbol) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + $ticker = $this->httpRequest("v1/ticker/price", "GET", $parameters); + return $ticker['price']; + } + + /** + * futuresPrices get the latest price for all symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Symbol-Price-Ticker + * + * $price = $api->futuresPrices(); + * + * @property int $weight 2 + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPrices() + { + $parameters = [ + 'fapi' => true, + ]; + return $this->priceData($this->httpRequest("v1/ticker/price", "GET", $parameters)); + } + + /** + * futuresPriceV2 get the latest price for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Symbol-Price-Ticker-v2 + * + * $price = $api->futuresPriceV2('ETHBTC'); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPriceV2(string $symbol) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + $ticker = $this->httpRequest("v2/ticker/price", "GET", $parameters); + return $ticker['price']; + } + + /** + * futuresPricesV2 get the latest price for all symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Symbol-Price-Ticker-v2 + * + * $price = $api->futuresPricesV2(); + * + * @property int $weight 2 + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPricesV2() + { + $parameters = [ + 'fapi' => true, + ]; + return $this->priceData($this->httpRequest("v2/ticker/price", "GET", $parameters)); + } + + /** + * futuresSymbolOrderBookTicker get the best price/qty on the order book for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Symbol-Order-Book-Ticker + * + * $ticker = $api->futuresSymbolOrderBookTicker(); + * $ticker = $api->futuresSymbolOrderBookTicker("ETHBTC"); + * + * @property int $weight 2 + * 5 when the symbol parameter is omitted + * + * @param string $symbol (optional) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresSymbolOrderBookTicker(string $symbol = null): array + { + $parameters = [ + 'fapi' => true, + ]; + if ($symbol) { + $parameters['symbol'] = $symbol; + } + return $this->httpRequest("v1/ticker/bookTicker", "GET", $parameters); + } + + /** + * futuresDeliveryPrice get the latest delivery price for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Delivery-Price + * + * $price = $api->futuresDeliveryPrice("ETHBTC"); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresDeliveryPrice(string $symbol): array + { + $parameters = [ + 'pair' => $symbol, + 'fapiData' => true, + ]; + + return $this->httpRequest("delivery-price", "GET", $parameters); + } + + /** + * futuresOpenInterest get the open interest for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Open-Interest + * + * $openInterest = $api->futuresOpenInterest("ETHBTC"); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresOpenInterest(string $symbol): array + { + $parameters = [ + 'symbol'=> $symbol, + 'fapi' => true, + ]; + return $this->httpRequest("v1/openInterest", 'GET', $parameters); + } + + /** + * symbolPeriodLimitStartEndRequest + * helper for routing GET methods that require symbol, period, limit, startTime and endTime + */ + private function symbolPeriodLimitStartEndContractTypeRequest($symbol, $period, $limit, $startTime, $endTime, $url, $base = 'fapi', $contractType = null) + { + $parameters = [ + 'symbol' => $symbol, + 'period' => $period, + ]; + $parameters[$base] = true; + if ($limit) { + $parameters['limit'] = $limit; + } + if ($startTime) { + $parameters['startTime'] = $startTime; + } + if ($endTime) { + $parameters['endTime'] = $endTime; + } + return $this->httpRequest($url, 'GET', $parameters); + } + + /** + * futuresOpenInterestHistory get the open interest history for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Open-Interest-Statistics + * + * $openInterest = $api->futuresOpenInterestHistory("ETHBTC", 5m); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $period (optional) string of period to query - 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d (default 5m) + * @param int $limit (optional) int limit the amount of open interest history (default 100, max 1000) + * @param int $startTime (optional) string request open interest history starting from here + * @param int $endTime (optional) string request open interest history ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresOpenInterestHistory(string $symbol, string $period = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->symbolPeriodLimitStartEndRequest($symbol, $period, $limit, $startTime, $endTime, 'openInterestHist', 'fapiData'); + } + + /** + * futuresTopLongShortPositionRatio get the proportion of net long and net short positions to total open positions of the top 20% users with the highest margin balance + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Top-Trader-Long-Short-Ratio + * + * $ratio = $api->futuresTopLongShortPositionRatio("ETHBTC", 5m); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $period (optional) string of period to query - 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d (default 5m) + * @param int $limit (optional) int limit the amount of open interest history (default 30, max 500) + * @param int $startTime (optional) string request open interest history starting from here + * @param int $endTime (optional) string request open interest history ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresTopLongShortPositionRatio(string $symbol, string $period = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->symbolPeriodLimitStartEndRequest($symbol, $period, $limit, $startTime, $endTime, 'topLongShortPositionRatio', 'fapiData'); + } + + /** + * futuresTopLongShortAccountRatio get the proportion of net long and net short accounts to total accounts of the top 20% users with the highest margin balance + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Top-Long-Short-Account-Ratio + * + * $ratio = $api->futuresTopLongShortAccountRatio("ETHBTC", 5m); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $period (optional) string of period to query - 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d (default 5m) + * @param int $limit (optional) int limit the amount of open interest history (default 30, max 500) + * @param int $startTime (optional) string request open interest history starting from here + * @param int $endTime (optional) string request open interest history ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresTopLongShortAccountRatio(string $symbol, string $period = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->symbolPeriodLimitStartEndRequest($symbol, $period, $limit, $startTime, $endTime, 'topLongShortAccountRatio', 'fapiData'); + } + + /** + * futuresGlobalLongShortAccountRatio get the Long/Short Ratio for symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Long-Short-Ratio + * + * $ratio = $api->futuresGlobalLongShortAccountRatio("ETHBTC", 5m); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $period (optional) string of period to query - 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d (default 5m) + * @param int $limit (optional) int limit the amount of open interest history (default 30, max 500) + * @param int $startTime (optional) string request open interest history starting from here + * @param int $endTime (optional) string request open interest history ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresGlobalLongShortAccountRatio(string $symbol, string $period = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->symbolPeriodLimitStartEndRequest($symbol, $period, $limit, $startTime, $endTime, 'globalLongShortAccountRatio', 'fapiData'); + } + + /** + * futuresTakerLongShortRatio get the taker Long/Short Ratio for symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Taker-BuySell-Volume + * + * $ratio = $api->futuresTakerLongShortRatio("ETHBTC", 5m); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $period (optional) string of period to query - 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d (default 5m) + * @param int $limit (optional) int limit the amount of open interest history (default 30, max 500) + * @param int $startTime (optional) string request open interest history starting from here + * @param int $endTime (optional) string request open interest history ending here + * + * @return array containing the response + * @throws \Exception + */ + public function futuresTakerLongShortRatio(string $symbol, string $period = '5m', int $limit = null, $startTime = null, $endTime = null) + { + return $this->symbolPeriodLimitStartEndRequest($symbol, $period, $limit, $startTime, $endTime, 'takerlongshortRatio', 'fapiData'); + } + + /** + * futuresBasis get future basis for symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Basis + * + * $basis = $api->futuresBasis("ETHBTC", 5m); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $period (optional) string of period to query - 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d (default 5m) + * @param int $limit (optional) int limit the amount of open interest history (default 30, max 500) + * @param int $startTime (optional) string request open interest history starting from here + * @param int $endTime (optional) string request open interest history ending here + * @param string $contractType (optional) string of period to query - PERPETUAL, CURRENT_QUARTER, NEXT_QUARTER (default PERPETUAL) + * + * @return array containing the response + * @throws \Exception + */ + public function futuresBasis(string $symbol, string $period = '5m', int $limit = 30, $startTime = null, $endTime = null, $contractType = 'PERPETUAL') + { + $parameters = [ + 'pair' => $symbol, + 'period' => $period, + 'contractType' => $contractType, + 'fapiData' => true, + ]; + if ($limit) { + $parameters['limit'] = $limit; + } + if ($startTime) { + $parameters['startTime'] = $startTime; + } + if ($endTime) { + $parameters['endTime'] = $endTime; + } + return $this->httpRequest("basis", 'GET', $parameters); + } + + /** + * futuresIndexInfo get composite index symbol information + * only for composite index symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Composite-Index-Symbol-Information + * + * $indexInfo = $api->futuresIndexInfo("DEFIUSDT"); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. DEFIUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresIndexInfo(string $symbol) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + return $this->httpRequest("v1/indexInfo", 'GET', $parameters); + } + + /** + * asset assetIndex get the asset index for a symbol or all symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Multi-Assets-Mode-Asset-Index + * + * $assetIndex = $api->futuresAssetIndex(); + * $assetIndex = $api->futuresAssetIndex("USDCUSD"); + * + * @property int $weight 1 + * with symbol parameter omitted weight is 10 + * + * @param string $symbol (optional) market symbol to get the response for, e.g. USDCUSD + * + * @return array containing the response + * @throws \Exception + */ + public function futuresAssetIndex(string $symbol = null) + { + $parameters = [ + 'fapi' => true, + ]; + if ($symbol) { + $parameters['symbol'] = $symbol; + } + return $this->httpRequest("v1/assetIndex", 'GET', $parameters); + } + + /** + * futuresConstituents get the index price constituents + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Index-Constituents + * + * $constituents = $api->futuresConstituents("BTCUSDT"); + * + * @property int $weight 2 + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * + * @return array containing the response + * @throws \Exception + */ + public function futuresConstituents(string $symbol) + { + $parameters = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + return $this->httpRequest("v1/indexInfo", 'GET', $parameters); + } + + /** + * createFuturesOrderRequest + * helper for creating the request for futures order + * @return array containing the request + * @throws \Exception + */ + protected function createFuturesOrderRequest(string $side, string $symbol, $quantity = null, $price = null, string $type = 'LIMIT', array $flags = []) { + $opt = [ + 'symbol' => $symbol, + 'side' => $side, + 'type' => $type, + ]; + + // someone has preformated there 8 decimal point double already + // dont do anything, leave them do whatever they want + if ($price && gettype($price) !== 'string') { + // for every other type, lets format it appropriately + $price = number_format($price, 8, '.', ''); + } + + if ($quantity) { + if (is_numeric($quantity) === false) { + // WPCS: XSS OK. + echo "warning: quantity expected numeric got " . gettype($quantity) . PHP_EOL; + } + if (isset($flags['closePosition']) && $flags['closePosition'] === true) { + // WPCS: XSS OK. + echo "warning: closePosition is set to true, quantity will be ignored" . PHP_EOL; + } else { + $opt['quantity'] = $quantity; + } + } + + if ($price && is_string($price) === false) { + // WPCS: XSS OK. + echo "warning: price expected string got " . gettype($price) . PHP_EOL; + } + + if ($type === "LIMIT" || $type === "STOP_LOSS_LIMIT" || $type === "TAKE_PROFIT_LIMIT") { + $opt["price"] = $price; + if (!isset($flags['timeInForce'])) { + $opt['timeInForce'] = 'GTC'; + } + } + + if (isset($flags['positionSide'])) { + $opt['positionSide'] = $flags['positionSide']; + } + + if (isset($flags['timeInForce'])) { + $opt['timeInForce'] = $flags['timeInForce']; + } + + if (isset($flags['reduceOnly'])) { + $reduceOnly = $flags['reduceOnly']; + if ($reduceOnly === true) { + $opt['reduceOnly'] = 'true'; + } else { + $opt['reduceOnly'] = 'false'; + } + } + + if (isset($flags['newClientOrderId'])) { + $opt['newClientOrderId'] = $flags['newClientOrderId']; + } else { + $opt['newClientOrderId'] = $this->generateFuturesClientOrderId(); + } + + if (isset($flags['stopPrice'])) { + $opt['stopPrice'] = $flags['stopPrice']; + } + + if (isset($flags['closePosition'])) { + $closePosition = $flags['closePosition']; + if ($closePosition === true) { + $opt['closePosition'] = 'true'; + } else { + $opt['closePosition'] = 'false'; + } + } + + if (isset($flags['activationPrice'])) { + $opt['activationPrice'] = $flags['activationPrice']; + } + + if (isset($flags['callbackRate'])) { + $opt['callbackRate'] = $flags['callbackRate']; + } + + if (isset($flags['workingType'])) { + $opt['workingType'] = $flags['workingType']; + } + + if (isset($flags['priceProtect'])) { + $priceProtect = $flags['priceProtect']; + if ($priceProtect === true) { + $opt['priceProtect'] = 'TRUE'; + } else { + $opt['priceProtect'] = 'FALSE'; + } + } + + if (isset($flags['newOrderRespType'])) { + $opt['newOrderRespType'] = $flags['newOrderRespType']; + } + + if (isset($flags['priceMatch'])) { + $opt['priceMatch'] = $flags['priceMatch']; + } + + if (isset($flags['selfTradePreventionMode'])) { + $opt['selfTradePreventionMode'] = $flags['selfTradePreventionMode']; + } + + if (isset($flags['goodTillDate'])) { + $opt['goodTillDate'] = $flags['goodTillDate']; + } + + if (isset($flags['recvWindow'])) { + $opt['recvWindow'] = $flags['recvWindow']; + } + + return $opt; + } + + /** + * futuresOrder formats the orders before sending them to the curl wrapper function + * You can call this function directly or use the helper functions + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api + * + * @see futuresBuy() + * @see sell() + * @see marketBuy() + * @see marketSell() + * + * @param string $side (mandatory) typically "BUY" or "SELL" + * @param string $symbol (mandatory) market symbol + * @param string $quantity (optional) of the order (Cannot be sent with closePosition=true (Close-All)) + * @param string $price (optional) price per unit + * @param string $type (mandatory) is determined by the symbol bu typicall LIMIT, STOP_LOSS_LIMIT etc. + * @param array $flags (optional) additional transaction options + * - @param string $flags['positionSide'] position side, "BOTH" for One-way Mode; "LONG" or "SHORT" for Hedge Mode (mandatory for Hedge Mode) + * - @param string $flags['timeInForce'] + * - @param bool $flags['reduceOnly'] default false (Cannot be sent in Hedge Mode; cannot be sent with closePosition=true) + * - @param string $flags['newClientOrderId'] new client order id + * - @param string $flags['stopPrice'] stop price (Used with STOP/STOP_MARKET or TAKE_PROFIT/TAKE_PROFIT_MARKET orders) + * - @param bool $flags['closePosition'] Close-All (used with STOP_MARKET or TAKE_PROFIT_MARKET orders) + * - @param string $flags['activationPrice'] Used with TRAILING_STOP_MARKET orders, default as the latest price (supporting different workingType) + * - @param string $flags['callbackRate'] Used with TRAILING_STOP_MARKET orders, min 0.1, max 5 where 1 for 1% + * - @param string $flags['workingType'] stopPrice triggered by: "MARK_PRICE", "CONTRACT_PRICE". Default "CONTRACT_PRICE" + * - @param bool $flags['priceProtect'] Used with STOP/STOP_MARKET or TAKE_PROFIT/TAKE_PROFIT_MARKET orders (default false) + * - @param string $flags['newOrderRespType'] response type, default "RESULT", other option is "ACK" + * - @param string $flags['priceMatch'] only avaliable for LIMIT/STOP/TAKE_PROFIT order; can be set to OPPONENT/ OPPONENT_5/ OPPONENT_10/ OPPONENT_20: /QUEUE/ QUEUE_5/ QUEUE_10/ QUEUE_20; Can't be passed together with price + * - @param string $flags['selfTradePreventionMode'] EXPIRE_TAKER:expire taker order when STP triggers/ EXPIRE_MAKER:expire taker order when STP triggers/ EXPIRE_BOTH:expire both orders when STP triggers; default NONE + * - @param string $flags['goodTillDate'] order cancel time for timeInForce GTD, mandatory when timeInforce set to GTD; order the timestamp only retains second-level precision, ms part will be ignored; The goodTillDate timestamp must be greater than the current time plus 600 seconds and smaller than 253402300799000 + * - @param int $flags['recvWindow'] + * @param $test bool whether to test or not, test only validates the query + * @return array containing the response + * @throws \Exception + */ + public function futuresOrder(string $side, string $symbol, $quantity = null, $price = null, string $type = 'LIMIT', array $flags = [], $test = false) + { + $opt = $this->createFuturesOrderRequest($side, $symbol, $quantity, $price, $type, $flags); + $opt['fapi'] = true; + $qstring = ($test === false) ? 'v1/order' : 'v1/order/test'; + return $this->httpRequest($qstring, 'POST', $opt, true); + } + + /** + * futuresBuy attempts to create a buy order + * each market supports a number of order types, such as + * -LIMIT + * -MARKET + * -STOP_LOSS + * -STOP_LOSS_LIMIT + * -TAKE_PROFIT + * -TAKE_PROFIT_LIMIT + * -LIMIT_MAKER + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api + * + * You should check the @see exchangeInfo for each currency to determine + * what types of orders can be placed against specific pairs + * + * $quantity = 1; + * $price = 0.0005; + * $order = $api->futuresBuy("BNBBTC", $quantity, $price); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $quantity (optional) the quantity required + * @param string $price (optional) price per unit + * @param string $type (mandatory) type of order + * @param array $flags (optional) addtional options for order type + * - @param string $flags['positionSide'] position side, "BOTH" for One-way Mode; "LONG" or "SHORT" for Hedge Mode (mandatory for Hedge Mode) + * - @param string $flags['timeInForce'] + * - @param bool $flags['reduceOnly'] default false (Cannot be sent in Hedge Mode; cannot be sent with closePosition=true) + * - @param string $flags['newClientOrderId'] new client order id + * - @param string $flags['stopPrice'] stop price (Used with STOP/STOP_MARKET or TAKE_PROFIT/TAKE_PROFIT_MARKET orders) + * - @param bool $flags['closePosition'] Close-All (used with STOP_MARKET or TAKE_PROFIT_MARKET orders) + * - @param string $flags['activationPrice'] Used with TRAILING_STOP_MARKET orders, default as the latest price (supporting different workingType) + * - @param string $flags['callbackRate'] Used with TRAILING_STOP_MARKET orders, min 0.1, max 5 where 1 for 1% + * - @param string $flags['workingType'] stopPrice triggered by: "MARK_PRICE", "CONTRACT_PRICE". Default "CONTRACT_PRICE" + * - @param bool $flags['priceProtect'] Used with STOP/STOP_MARKET or TAKE_PROFIT/TAKE_PROFIT_MARKET orders (default false) + * - @param string $flags['newOrderRespType'] response type, default "RESULT", other option is "ACK" + * - @param string $flags['priceMatch'] only avaliable for LIMIT/STOP/TAKE_PROFIT order; can be set to OPPONENT/ OPPONENT_5/ OPPONENT_10/ OPPONENT_20: /QUEUE/ QUEUE_5/ QUEUE_10/ QUEUE_20; Can't be passed together with price + * - @param string $flags['selfTradePreventionMode'] EXPIRE_TAKER:expire taker order when STP triggers/ EXPIRE_MAKER:expire taker order when STP triggers/ EXPIRE_BOTH:expire both orders when STP triggers; default NONE + * - @param string $flags['goodTillDate'] order cancel time for timeInForce GTD, mandatory when timeInforce set to GTD; order the timestamp only retains second-level precision, ms part will be ignored; The goodTillDate timestamp must be greater than the current time plus 600 seconds and smaller than 253402300799000 + * - @param int $flags['recvWindow'] + * @return array with error message or the order details + */ + public function futuresBuy(string $symbol, $quantity = null, $price = null, string $type = 'LIMIT', array $flags = []) + { + return $this->futuresOrder('BUY', $symbol, $quantity, $price, $type, $flags); + } + + /** + * futuresBuyTest attempts to create a TEST futures buy order + * + * @see futuresBuy() + * + * params and return value are the same as @see futuresBuy() + */ + public function futuresBuyTest(string $symbol, $quantity = null, $price = null, string $type = 'LIMIT', array $flags = []) + { + return $this->futuresOrder('BUY', $symbol, $quantity, $price, $type, $flags, true); + } + + /** + * futuresSell creates a futures sell order + * each market supports a number of order types, such as + * -LIMIT + * -MARKET + * -STOP_LOSS + * -STOP_LOSS_LIMIT + * -TAKE_PROFIT + * -TAKE_PROFIT_LIMIT + * -LIMIT_MAKER + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api + * + * You should check the @see exchangeInfo for each currency to determine + * what types of orders can be placed against specific pairs + * + * $quantity = 1; + * $price = 0.0005; + * $order = $api->futuresSell("BNBBTC", $quantity, $price); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $quantity (optional) the quantity required + * @param string $price (optional) price per unit + * @param string $type (mandatory) type of order + * @param array $flags (optional) addtional options for order type + * - @param string $flags['positionSide'] position side, "BOTH" for One-way Mode; "LONG" or "SHORT" for Hedge Mode (mandatory for Hedge Mode) + * - @param string $flags['timeInForce'] + * - @param bool $flags['reduceOnly'] default false (Cannot be sent in Hedge Mode; cannot be sent with closePosition=true) + * - @param string $flags['newClientOrderId'] new client order id + * - @param string $flags['stopPrice'] stop price (Used with STOP/STOP_MARKET or TAKE_PROFIT/TAKE_PROFIT_MARKET orders) + * - @param bool $flags['closePosition'] Close-All (used with STOP_MARKET or TAKE_PROFIT_MARKET orders) + * - @param string $flags['activationPrice'] Used with TRAILING_STOP_MARKET orders, default as the latest price (supporting different workingType) + * - @param string $flags['callbackRate'] Used with TRAILING_STOP_MARKET orders, min 0.1, max 5 where 1 for 1% + * - @param string $flags['workingType'] stopPrice triggered by: "MARK_PRICE", "CONTRACT_PRICE". Default "CONTRACT_PRICE" + * - @param bool $flags['priceProtect'] Used with STOP/STOP_MARKET or TAKE_PROFIT/TAKE_PROFIT_MARKET orders (default false) + * - @param string $flags['newOrderRespType'] response type, default "RESULT", other option is "ACK" + * - @param string $flags['priceMatch'] only avaliable for LIMIT/STOP/TAKE_PROFIT order; can be set to OPPONENT/ OPPONENT_5/ OPPONENT_10/ OPPONENT_20: /QUEUE/ QUEUE_5/ QUEUE_10/ QUEUE_20; Can't be passed together with price + * - @param string $flags['selfTradePreventionMode'] EXPIRE_TAKER:expire taker order when STP triggers/ EXPIRE_MAKER:expire taker order when STP triggers/ EXPIRE_BOTH:expire both orders when STP triggers; default NONE + * - @param string $flags['goodTillDate'] order cancel time for timeInForce GTD, mandatory when timeInforce set to GTD; order the timestamp only retains second-level precision, ms part will be ignored; The goodTillDate timestamp must be greater than the current time plus 600 seconds and smaller than 253402300799000 + * - @param int $flags['recvWindow'] + * @return array with error message or the order details + */ + public function futuresSell(string $symbol, $quantity = null, $price = null, string $type = 'LIMIT', array $flags = []) + { + return $this->futuresOrder('SELL', $symbol, $quantity, $price, $type, $flags); + } + + /** + * futuresSellTest attempts to create a TEST futures sell order + * + * @see futuresSell() + * + * params and return value are the same as @see futuresSell() + */ + public function futuresSellTest(string $symbol, $quantity = null, $price = null, $type = null, array $flags = []) + { + if ($type === null) { + $type = 'LIMIT'; + } + return $this->futuresOrder('SELL', $symbol, $quantity, $price, $type, $flags, true); + } + + /** + * createBatchOrdersRequest + * helper for creating the request for multiple futures orders + * @param array $orders (mandatory) array of orders to be placed + * objects in the array should contain literally the same keys as the @see futuresOrder but without the recvWindow + * + * @return array containing the request + * @throws \Exception + */ + protected function createBatchOrdersRequest(array $orders) + { + $formatedOrders = []; + for ($index = 0; $index < count($orders); $index++) { + $order = $orders[$index]; + if (!isset($order['quantity'])) { + $order['quantity'] = null; + } + if (!isset($order['price'])) { + $order['price'] = null; + } + if (!isset($order['flags'])) { + $order['flags'] = []; + } + $formatedOrder = $this->createFuturesOrderRequest( + $order['side'], + $order['symbol'], + $order['quantity'], + $order['price'], + $order['type'], + $order['flags'] + ); + if (isset($formatedOrder['recvWindow'])) { + // remove recvWindow from the order + unset($formatedOrder['recvWindow']); + } + if (isset($order['orderId'])) { + $formatedOrder['orderId'] = $order['orderId']; + } + if (isset($order['origClientOrderId'])) { + $formatedOrder['origClientOrderId'] = $order['origClientOrderId']; + } + $formatedOrders[$index] = $formatedOrder; + } + return $formatedOrders; + } + + /** + * futuresBatchOrders creates multiple orders in a single request + * max 5 orders + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Place-Multiple-Orders + * + * @param array $orders (mandatory) array of orders to be placed + * objects in the array should contain literally the same keys as the @see futuresOrder but without the $flags['recvWindow'] + * @param string $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response or error message + * @throws \Exception + */ + public function futuresBatchOrders(array $orders, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + $formatedOrders = $this->createBatchOrdersRequest($orders); + if (count($formatedOrders) > 5) { + throw new \Exception('futuresBatchOrders: max 5 orders allowed'); + } + if (count($formatedOrders) < 1) { + throw new \Exception('futuresBatchOrders: at least 1 order required'); + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + // current endpoint accepts orders list as a json string in the query string + $encodedOrders = json_encode($formatedOrders); + $url = 'v1/batchOrders?batchOrders=' . $encodedOrders; + return $this->httpRequest($url, 'POST', $params, true); + } + + /** + * futuresEditOrder edits the limit order + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Order + * + * @param string $symbol (mandatory) market symbol + * @param string $side (mandatory) "BUY" or "SELL" + * @param string $orderId (optional) order id to be modified (mandatory if $flags['origClientOrderId'] is not set) + * @param string $quantity (optional) of the order (Cannot be sent for orders with closePosition=true (Close-All)) + * @param string $price (mandatory) price per unit + * @param array $flags (optional) additional options + * - @param string $flags['priceMatch'] only avaliable for LIMIT/STOP/TAKE_PROFIT order; can be set to OPPONENT/ OPPONENT_5/ OPPONENT_10/ OPPONENT_20: /QUEUE/ QUEUE_5/ QUEUE_10/ QUEUE_20; Can't be passed together with price + * - @param int $flags['recvWindow'] + * - @param string $flags['origClientOrderId'] client order id to be modified (mandatory if $orderId is not set) + * @return array containing the response + * @throws \Exception + */ + public function futuresEditOrder(string $symbol, string $side, string $quantity, string $price, $orderId = null, array $flags = []) + { + $opt = $this->createFuturesOrderRequest($side, $symbol, $quantity, $price, 'LIMIT', $flags); + $origClientOrderId = null; + if (isset($flags['origClientOrderId'])) { + $origClientOrderId = $flags['origClientOrderId']; + $opt['origClientOrderId'] = $origClientOrderId; + } + if (!$origClientOrderId && !$orderId) { + throw new \Exception('futuresEditOrder: either orderId or origClientOrderId must be set'); + } + if ($orderId) { + $opt['orderId'] = $orderId; + } + unset($opt['type']); + $opt['fapi'] = true; + return $this->httpRequest("v1/order", 'PUT', $opt, true); + } + + /** + * futuresEditOrders edits the multiple limit orders + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Multiple-Orders + * + * @param array $orders (mandatory) array of orders to be modified + * objects in the array should contain literally the same keys as the @see futuresEditOrder but without the $flags['recvWindow'] + * @param string $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response or error message + * @throws \Exception + */ + public function futuresEditOrders(array $orders, $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + $formatedOrders = $this->createBatchOrdersRequest($orders); + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + // current endpoint accepts orders list as a json string in the query string + $encodedOrders = json_encode($formatedOrders); + $url = 'v1/batchOrders?batchOrders=' . $encodedOrders; + return $this->httpRequest($url, 'PUT', $params, true); + } + + /** + * futuresOrderAmendment get order modification history + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Get-Order-Modify-History + * + * $amendment = $api->futuresOrderAmendment("ETHUSDT"); + * + * @param string $symbol (mandatory) market symbol to get the response for, e.g. ETHUSDT + * @param string $orderId (optional) order id to get the response for + * @param string $origClientOrderId (optional) original client order id to get the response for + * @param int $startTime (optional) timestamp in ms to get modification history from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get modification history until INCLUSIVE + * @param int $limit (optional) limit the amount of open interest history (default 50, max 100) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresOrderAmendment(string $symbol, $orderId = null, $origClientOrderId = null, $startTime = null, $endTime = null, $limit = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($orderId) { + $params['orderId'] = $orderId; + } + if ($origClientOrderId) { + $params['origClientOrderId'] = $origClientOrderId; + } + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/orderAmendment", 'GET', $params, true); + } + + /** + * futuresCancel cancels a futures order + * + * $orderid = "123456789"; + * $order = $api->futuresCancel("BNBBTC", $orderid); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $orderid (optional) the orderid to cancel (mandatory if $flags['origClientOrderId'] is not set) + * @param array $flags (optional) additional options + * - @param string $flags['origClientOrderId'] original client order id to cancel + * - @param int $flags['recvWindow'] the time in milliseconds to wait for a response + * + * @return array with error message or the order details + * @throws \Exception + */ + public function futuresCancel(string $symbol, $orderid, $flags = []) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($orderid) { + $params['orderId'] = $orderid; + } else if (!isset($flags['origClientOrderId'])) { + throw new \Exception('futuresCancel: either orderId or origClientOrderId must be set'); + } + return $this->httpRequest("v1/order", 'DELETE', array_merge($params, $flags), true); + } + + /** + * futuresCancelBatchOrders canceles multiple futures orders + * + * $orderIds = ["123456789", "987654321"]; + * $order = $api->futuresCancelBatchOrders("BNBBTC", $orderIds); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param array $orderIdList (optional) list of ids to cancel (mandatory if origClientOrderIdList is not set) + * @param array $origClientOrderIdList (optional) list of client order ids to cancel (mandatory if orderIdList is not set) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the orders details + * @throws \Exception + */ + public function futuresCancelBatchOrders(string $symbol, $orderIdList = null, $origClientOrderIdList = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($orderIdList) { + $idsString = json_encode($orderIdList); + // remove quotes and spaces + $params['orderIdList'] = str_replace(' ', '', str_replace('"', '', str_replace("'", '', $idsString))); + } else if ($origClientOrderIdList) { + // remove spaces + $params['origClientOrderIdList'] = str_replace(' ', '', json_encode($origClientOrderIdList)); + } else { + throw new \Exception('futuresCancelBatchOrders: either orderIdList or origClientOrderIdList must be set'); + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/batchOrders", 'DELETE', $params, true); + } + + /** + * futuresCancelOpenOrders cancels all open futures orders for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Cancel-All-Open-Orders + * + * $orders = $api->futuresCancelOpenOrders("BNBBTC"); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $recvWindow the time in milliseconds to wait for a response + * + * @return array with error message or the orders details + * @throws \Exception + */ + public function futuresCancelOpenOrders(string $symbol, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/allOpenOrders", 'DELETE', $params, true); + } + + /** + * futuresCountdownCancelAllOrders cancels all open futures orders for a symbol at the end of the specified countdown + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Auto-Cancel-All-Open-Orders + * + * $orders = $api->futuresCountdownCancelAllOrders("BNBBTC", 10); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $countdownTime (mandatory) countdown in milliseconds (0 to stop the timer) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the orders details + * @throws \Exception + */ + public function futuresCountdownCancelAllOrders(string $symbol, int $countdownTime, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + 'countdownTime' => $countdownTime, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/countdownCancelAll", 'POST', $params, true); + } + + /** + * futuresOrderStatus gets the details of a futures order + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Query-Order + * + * $order = $api->futuresOrderStatus("BNBBTC", "123456789"); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $orderId (optional) order id to get the response for (mandatory if origClientOrderId is not set) + * @param string $origClientOrderId (optional) original client order id to get the response for (mandatory if orderId is not set) + * @param string $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the order details + * @throws \Exception + */ + public function futuresOrderStatus(string $symbol, $orderId = null, $origClientOrderId = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($orderId) { + $params['orderId'] = $orderId; + } else if ($origClientOrderId) { + $params['origClientOrderId'] = $origClientOrderId; + } else { + throw new \Exception('futuresOrderStatus: either orderId or origClientOrderId must be set'); + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/order", 'GET', $params, true); + } + + /** + * futuresAllOrders gets all orders for a symbol + * query time period must be less then 7 days (default as the recent 7 days) + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/All-Orders + * + * $orders = $api->futuresAllOrders("BNBBTC"); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $startTime (optional) timestamp in ms to get orders from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get orders until INCLUSIVE + * @param int $limit (optional) limit the amount of orders (default 500, max 1000) + * @param string $orderId (optional) order id to get the response from (if is set it will get orders >= that orderId) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + */ + public function futuresAllOrders(string $symbol, $startTime = null, $endTime = null, $limit = null, $orderId = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($orderId) { + $params['orderId'] = $orderId; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/allOrders", 'GET', $params, true); + } + + /** + * futuresOpenOrders gets all open orders for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Current-All-Open-Orders + * + * $orders = $api->futuresOpenOrders(); + * $orders = $api->futuresOpenOrders("BNBBTC"); + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the orders details + * @throws \Exception + */ + public function futuresOpenOrders($symbol = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/openOrders", 'GET', $params, true); + } + + /** + * futuresOpenOrder gets an open futures order + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Query-Current-Open-Order + * + * $order = $api->futuresOpenOrder("BNBBTC", "123456789"); + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $orderId (optional) order id to get the response for (mandatory if origClientOrderId is not set) + * @param string $origClientOrderId (optional) original client order id to get the response for (mandatory if orderId is not set) + * @param string $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the order details + * @throws \Exception + */ + public function futuresOpenOrder(string $symbol, $orderId = null, $origClientOrderId = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($orderId) { + $params['orderId'] = $orderId; + } else if ($origClientOrderId) { + $params['origClientOrderId'] = $origClientOrderId; + } else { + throw new \Exception('futuresOpenOrder: either orderId or origClientOrderId must be set'); + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/openOrder", 'GET', $params, true); + } + /** + * futuresForceOrders gets all futures force orders + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Users-Force-Orders + * + * $orders = $api->futuresForceOrders("BNBBTC"); + * + * @property int $weight 50 + * 20 if symbol is not passed + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $startTime (optional) timestamp in ms to get orders from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get orders until INCLUSIVE + * @param int $limit (optional) limit the amount of orders (default 500, max 1000) + * @param string $autoCloseType (optional) "LIQUIDATION" for liquidation orders, "ADL" for ADL orders + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the orders details + * @throws \Exception + */ + public function futuresForceOrders($symbol = null, $startTime = null, $endTime = null, $limit = null, $autoCloseType = null, $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($autoCloseType) { + $params['autoCloseType'] = $autoCloseType; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/forceOrders", 'GET', $params, true); + } + + /** + * futuresMyTrades gets all futures trades for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Account-Trade-List + * + * $trades = $api->futuresMyTrades("BNBBTC"); + * + * @property int $weight 5 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $startTime (optional) timestamp in ms to get trades from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get trades until INCLUSIVE + * @param int $limit (optional) limit the amount of trades (default 500, max 1000) + * @param string $orderId (optional) order id to get the trades for + * @param string $fromId (optional) trade id to get the trades from (if is set it will get trades >= that Id) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the trades details + * @throws \Exception + */ + public function futuresMyTrades(string $symbol, $startTime = null, $endTime = null, $limit = null, $orderId = null, $fromId = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($orderId) { + $params['orderId'] = $orderId; + } + if ($fromId) { + $params['fromId'] = $fromId; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/userTrades", 'GET', $params, true); + } + + /** + * futuresHistory + * another name for futuresMyTrades (for naming compatibility with spot) + * @deprecated + */ + public function futuresHistory(string $symbol, $startTime = null, $endTime = null, $limit = null, $orderId = null, $fromId = null, int $recvWindow = null) + { + return $this->futuresMyTrades($symbol, $startTime, $endTime, $limit, $orderId, $fromId, $recvWindow); + } + + /** + * futuresSetMarginMode sets the margin mode for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Change-Margin-Type + * + * $api->futuresSetMarginMode("BNBBTC", "ISOLATED"); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $marginType (mandatory) margin type, "CROSSED" or "ISOLATED" + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresSetMarginMode(string $symbol, string $marginType, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + 'marginType' => $marginType, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/marginType", 'POST', $params, true); + } + + /** + * futuresPositionMode gets the position mode for ALL symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Current-Position-Mode + * + * $response = $api->futuresPositionMode(); + * + * @property int $weight 30 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresPositionMode(int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/positionSide/dual", 'GET', $params, true); + } + + /** + * futuresSetPositionMode sets the position mode for ALL symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Change-Position-Mode + * + * $api->futuresSetPositionMode(true); + * + * @property int $weight 1 + * + * @param bool $dualSidePosition (mandatory) true for Hedge Mode, false for One-way Mode + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresSetPositionMode(bool $dualSidePosition, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + 'dualSidePosition' => $dualSidePosition ? 'true' : 'false', + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/positionSide/dual", 'POST', $params, true); + } + + /** + * futuresSetLeverage sets the leverage for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Change-Initial-Leverage + * + * $leverage = $api->futuresSetLeverage(10, "BTCUSDT"); + * + * @property int $weight 1 + * + * + * @param int $leverage (mandatory) leverage to be set (min 1, max 125) + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresSetLeverage(int $leverage, string $symbol, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + 'leverage' => $leverage, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/leverage", 'POST', $params, true); + } + + /** + * futuresMultiAssetsMarginMode gets the multi-assets margin mode for ALL symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Current-Multi-Assets-Mode + * + * $response = $api->futuresMultiAssetsMarginMode(); + * + * @property int $weight 30 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresMultiAssetsMarginMode(int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/multiAssetsMargin", 'GET', $params, true); + } + + /** + * futuresSetMultiAssetsMarginMode sets the multi-assets margin mode for ALL symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Change-Multi-Assets-Mode + * + * $response = $api->futuresSetMultiAssetsMarginMode(true); + * + * @property int $weight 1 + * + * @param bool $multiAssetsMarginMode (mandatory) true for multi-assets mode, false for single-asset mode + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresSetMultiAssetsMarginMode(bool $multiAssetsMarginMode, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + 'multiAssetsMarginMode' => $multiAssetsMarginMode ? 'true' : 'false', + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/multiAssetsMarginMode", 'POST', $params, true); + } + + /** + * modifyMarginHelper helper for adding or removing margin + * + * @see futuresAddMargin() and futuresReduceMargin() + * + * @return array containing the response + * @throws \Exception + */ + protected function modifyMarginHelper(string $symbol, string $amount, $addOrReduce, $positionSide = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + 'amount' => $amount, + 'type' => $addOrReduce, + ]; + if ($positionSide) { + $params['positionSide'] = $positionSide; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/positionMargin", 'POST', $params, true); + } + + /** + * futuresAddMargin adds margin to a position + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Isolated-Position-Margin + * + * $response = $api->futuresAddMargin("BNBBTC", 10); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $amount (mandatory) amount to be added + * @param string $positionSide (optional) position side - "BOTH" for non-hedged and "LONG" or "SHORT" for hedged (mandatory for hedged positions) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresAddMargin(string $symbol, string $amount, $positionSide = null, int $recvWindow = null) + { + return $this->modifyMarginHelper($symbol, $amount, 1, $positionSide, $recvWindow); + } + + /** + * futuresReduceMargin removes margin from a position + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Isolated-Position-Margin + * + * $response = $api->futuresReduceMargin("BNBBTC", 10); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param string $amount (mandatory) amount to be removed + * @param string $positionSide (optional) position side - "BOTH" for non-hedged and "LONG" or "SHORT" for hedged (mandatory for hedged positions) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresReduceMargin(string $symbol, string $amount, $positionSide = null, int $recvWindow = null) + { + return $this->modifyMarginHelper($symbol, $amount, 2, $positionSide, $recvWindow); + } + + /** + * futuresPositions gets the position information for a symbol or all symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Position-Information-V2 + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Position-Information-V3 + * + * $position = $api->futuresPositions("BNBBTC"); + * + * @property int $weight 5 + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * @param string $api_version (optional) API version, "v2" or "v3" (default is v3) + * + * @return array with error message or the position details + * @throws \Exception + */ + public function futuresPositions($symbol = null, $recvWindow = null, $api_version = 'v3') + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + if ($api_version !== 'v2' && $api_version !== 'v3') { + throw new \Exception('futuresPositions: api_version must be either v2 or v3'); + } + return $this->httpRequest($api_version . "/positionRisk", 'GET', $params, true); + } + + /** futuresPositionsV2 + * @see futuresPositions + */ + public function futuresPositionsV2($symbol = null, int $recvWindow = null) + { + return $this->futuresPositions($symbol, $recvWindow, 'v2'); + } + + /** + * futuresPositionsV3 + * @see futuresPositions + */ + public function futuresPositionsV3($symbol = null, int $recvWindow = null) + { + return $this->futuresPositions($symbol, $recvWindow, 'v3'); + } + + /** + * futuresPosition gets the position information for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Position-Information-V2 + * + * $position = $api->futuresPosition("BNBBTC"); + * + * @property int $weight 5 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * @param string $api_version (optional) API version, "v2" or "v3" (default is v3) + * + * @return array with error message or the position details + * @throws \Exception + */ + public function futuresPosition(string $symbol, $recvWindow = null, string $api_version = 'v3') + { + return $this->futuresPositions($symbol, $recvWindow, $api_version); + } + + /** + * futuresPositionV2 + * @see futuresPosition + */ + public function futuresPositionV2(string $symbol, int $recvWindow = null) + { + return $this->futuresPositionsV2($symbol, $recvWindow, 'v2'); + } + + /** + * futuresPositionV3 + * @see futuresPosition + */ + public function futuresPositionV3(string $symbol, int $recvWindow = null) + { + return $this->futuresPositionsV3($symbol, $recvWindow, 'v3'); + } + + /** + * futuresAdlQuantile gets the ADL quantile estimation for a symbol or all symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Position-ADL-Quantile-Estimation + * + * $response = $api->futuresAdlQuantile("BNBBTC"); + * + * @property int $weight 5 + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the ADL quantile details + * @throws \Exception + */ + public function futuresAdlQuantile($symbol = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/adlQuantile", 'GET', $params, true); + } + + /** + * futuresPositionMarginChangeHistory gets the position margin change history for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Get-Position-Margin-Change-History + * + * $history = $api->futuresPositionMarginChangeHistory("BNBBTC"); + * + * @property int $weight 1 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $startTime (optional) timestamp in ms to get history from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get history until INCLUSIVE + * @param int $limit (optional) limit the amount of history (default 500) + * @param string $addOrReduce (optional) "ADD" or "REDUCE" to filter the history + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + */ + public function futuresPositionMarginChangeHistory(string $symbol, $startTime = null, $endTime = null, $limit = null, $addOrReduce = null, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($addOrReduce) { + if (is_numeric($addOrReduce)) { + $params['addOrReduce'] = $addOrReduce; + } else if (is_string($addOrReduce)) { + $addOrReduce = strtoupper($addOrReduce); + if ($addOrReduce === 'ADD' || $addOrReduce === '1') { + $params['addOrReduce'] = 1; + } else if ($addOrReduce === 'REDUCE' || $addOrReduce === '2') { + $params['addOrReduce'] = 2; + } else { + throw new \Exception('futuresPositionMarginChangeHistory: addOrReduce must be "ADD" or "REDUCE" or 1 or 2'); + } + } else { + throw new \Exception('futuresPositionMarginChangeHistory: addOrReduce must be "ADD" or "REDUCE" or 1 or 2'); + } + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/positionMargin/history", 'GET', $params, true); + } + + /** + * futuresBalances gets the balance information futures account + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Futures-Account-Balance-V2 + * + * $balances = $api->futuresBalances(); + * + * @property int $weight 5 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * @param string $api_version (optional) API version, "v2" or "v3" (default is v3) + * + * @return array with error message or the balance details + * @throws \Exception + */ + public function futuresBalances($recvWindow = null, string $api_version = 'v3') + { + if ($api_version !== 'v2' && $api_version !== 'v3') { + throw new \Exception('futuresBalances: api_version must be either v2 or v3'); + } + return $this->balances('futures', $recvWindow, 'v3'); + } + + /** + * futuresBalancesV2 + * see futuresBalances + */ + public function futuresBalancesV2(int $recvWindow = null) + { + return $this->futuresBalances($recvWindow, 'v2'); + } + + /** + * futuresBalancesV3 + * see futuresBalances + */ + public function futuresBalancesV3(int $recvWindow = null) + { + return $this->futuresBalances($recvWindow, 'v3'); + } + + /** + * futuresAccount get all information about the api account + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Account-Information-V2 + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Account-Information-V3 + * + * $account = $api->futuresAccount(); + * + * @property int $weight 5 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * @param string $api_version (optional) API version, "v2" or "v3" (default is v3) + * + * @return array with error message or array of all the account information + * @throws \Exception + */ + public function futuresAccount($recvWindow = null, string $api_version = 'v3') + { + if ($api_version !== 'v2' && $api_version !== 'v3') { + throw new \Exception('futuresAccount: api_version must be either v2 or v3'); + } + $params = [ + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest($api_version . "/account", "GET", $params, true); + } + + /** + * futuresAccountV2 + * see futuresAccount + */ + public function futuresAccountV2(int $recvWindow = null) + { + return $this->futuresAccount($recvWindow, 'v2'); + } + + /** + * futuresAccountV3 + * see futuresAccount + */ + public function futuresAccountV3(int $recvWindow = null) + { + return $this->futuresAccount($recvWindow, 'v3'); + } + + /** + * futuresTradeFee gets the trade fee information for a symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/User-Commission-Rate + * + * $tradeFee = $api->futuresTradeFee("BNBBTC"); + * + * @property int $weight 20 + * + * @param string $symbol (mandatory) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the trade fee details + * @throws \Exception + */ + public function futuresTradeFee(string $symbol, int $recvWindow = null) + { + $params = [ + 'symbol' => $symbol, + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/commissionRate", 'GET', $params, true); + } + + /** + * futuresAccountConfig gets the account configuration information + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Account-Config + * + * $accountConfig = $api->futuresAccountConfig(); + * + * @property int $weight 5 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the account configuration details + * @throws \Exception + */ + public function futuresAccountConfig(int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/accountConfig", 'GET', $params, true); + } + + /** + * futuresMarginModes gets the margin mode for all symbols or specific symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Symbol-Config + * + * $marginMode = $api->futuresMarginModes(); + * $marginModes = $api->futuresMarginModes("BNBBTC"); + * + * @property int $weight 5 + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the margin mode details + * @throws \Exception + */ + public function futuresMarginModes($symbol = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/symbolConfig", 'GET', $params, true); + } + + /** + * futuresOrderRateLimit gets the user rate limit + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Query-Rate-Limit + * + * $rateLimit = $api->futuresOrderRateLimit(); + * + * @property int $weight 1 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the rate limit details + * @throws \Exception + */ + public function futuresOrderRateLimit(int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/rateLimit/order", 'GET', $params, true); + } + + /** + * futuresLeverages gets the leverage information for a symbol or all symbols + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Notional-and-Leverage-Brackets + * + * $leverage = $api->futuresLeverages("BNBBTC"); + * $leverages = $api->futuresLeverages(); + * + * @property int $weight 1 + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the leverage details + * @throws \Exception + */ + public function futuresLeverages($symbol = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/leverageBracket", 'GET', $params, true); + } + + /** + * futuresLedger fetch the history of changes, actions done by the user or operations that altered the balance of the user + * possible values for incomeType: + * - TRANSFER + * - TRANSFER + * - WELCOME_BONUS + * - REALIZED_PNL + * - FUNDING_FEE + * - COMMISSION + * - INSURANCE_CLEAR + * - REFERRAL_KICKBACK + * - COMMISSION_REBATE + * - API_REBATE + * - CONTEST_REWARD + * - CROSS_COLLATERAL_TRANSFER + * - OPTIONS_PREMIUM_FEE + * - OPTIONS_SETTLE_PROFIT + * - INTERNAL_TRANSFER + * - AUTO_EXCHANGE + * - DELIVERED_SETTELMENT + * - COIN_SWAP_DEPOSIT + * - COIN_SWAP_WITHDRAW + * - POSITION_LIMIT_INCREASE_FEE + * - STRATEGY_UMFUTURES_TRANSFER + * - FEE_RETURN + * - BFUSD_REWARD + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Income-History + * + * $income = $api->futuresLedger("BNBBTC"); + * $income = $api->futuresLedger("BNBBTC", "FUNDING_FEE"); + * + * @property int $weight 30 + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param string $incomeType (optional) income type to filter the response + * @param int $startTime (optional) timestamp in ms to get income from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get income until INCLUSIVE + * @param int $limit (optional) limit the amount of income (default 100, max 1000) + * @param int $page (optional) number of page to get + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the income details + * @throws \Exception + */ + public function futuresLedger($symbol = null, $incomeType = null, $startTime = null, $endTime = null, $limit = null, $page = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($incomeType) { + $params['incomeType'] = $incomeType; + } + if ($startTime) { + $params['startTime'] = $startTime; + } + if ($endTime) { + $params['endTime'] = $endTime; + } + if ($limit) { + $params['limit'] = $limit; + } + if ($page) { + $params['page'] = $page; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/income", 'GET', $params, true); + } + + /** + * futuresTradingStatus get the futures trading quantitative rules indicators + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Futures-Trading-Quantitative-Rules-Indicators + * + * $tradingStatus = $api->futuresTradingStatus(); + * + * @property int $weight 10 + * weigth is 1 if symbol is provided + * + * @param string $symbol (optional) market symbol (e.g. ETHUSDT) + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the trading status details + * @throws \Exception + */ + public function futuresTradingStatus($symbol = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($symbol) { + $params['symbol'] = $symbol; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/apiTradingStatus", 'GET', $params, true); + } + + /** + * futuresDownloadId + * helper for other metods for getting download id + */ + protected function futuresDownloadId($startTime, $endTime, $recvWindow = null, string $url = '') + { + $params = [ + 'fapi' => true, + 'startTime' => $startTime, + 'endTime' => $endTime, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest($url, 'GET', $params, true); + } + + /** + * futuresDownloadLinkByDownloadId + * helper for other metods for getting download link by download id + */ + protected function futuresDownloadLinkByDownloadId(string $downloadId, $recvWindow = null, string $url = '') + { + $params = [ + 'fapi' => true, + 'downloadId' => $downloadId, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest($url, 'GET', $params, true); + } + + /** + * futuresDownloadIdForTransactions gets the download id for transactions + * request limitation is 5 times per month, shared by front end download page and rest api + * the time between startTime and endTime can not be longer than 1 year + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Download-Id-For-Futures-Transaction-History + * + * $downloadId = $api->futuresDownloadIdForTransactions(1744105700000, 1744105722122); + * + * @property int $weight 1000 + * + * @param int $startTime (optional) timestamp in ms to get transactions from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get transactions until INCLUSIVE + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the response + * @throws \Exception + */ + public function futuresDownloadIdForTransactions(int $startTime, int $endTime, int $recvWindow = null) + { + return $this->futuresDownloadId($startTime, $endTime, $recvWindow, "v1/income/asyn"); + } + + /** + * futuresDownloadTransactionsByDownloadId get futures transaction history download link by Id + * download link expiration: 24h + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Futures-Transaction-History-Download-Link-by-Id + * + * $downloadLink = $api->futuresDownloadTransactionsByDownloadId("downloadId"); + * + * @property int $weight 10 + * + * @param string $downloadId (mandatory) download id + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the download link + * @throws \Exception + */ + public function futuresDownloadTransactionsByDownloadId(string $downloadId, int $recvWindow = null) + { + return $this->futuresDownloadLinkByDownloadId($downloadId, $recvWindow, "v1/income/asyn/id"); + } + + /** + * futuresDownloadIdForOrders gets the download id for orders + * request limitation is 10 times per month, shared by front end download page and rest api + * the time between startTime and endTime can not be longer than 1 year + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Download-Id-For-Futures-Order-History + * + * $downloadId = $api->futuresDownloadIdForOrders(1744105700000, 1744105722122); + * + * @property int $weight 1000 + * + * @param int $startTime (optional) timestamp in ms to get orders from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get orders until INCLUSIVE + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the response + * @throws \Exception + */ + public function futuresDownloadIdForOrders(int $startTime, int $endTime, int $recvWindow = null) + { + return $this->futuresDownloadId($startTime, $endTime, $recvWindow, "v1/order/asyn"); + } + + /** + * futuresDownloadOrdersByDownloadId get futures orders history download link by Id + * download link expiration: 24h + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Futures-Order-History-Download-Link-by-Id + * + * $downloadLink = $api->futuresDownloadOrdersByDownloadId("downloadId"); + * + * @property int $weight 10 + * + * @param string $downloadId (mandatory) download id + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the download link + * @throws \Exception + */ + public function futuresDownloadOrdersByDownloadId(string $downloadId, int $recvWindow = null) + { + return $this->futuresDownloadLinkByDownloadId($downloadId, $recvWindow, "v1/order/asyn/id"); + } + + /** + * futuresDownloadIdForTrades gets the download id for trades + * request limitation is 5 times per month, shared by front end download page and rest api + * the time between startTime and endTime can not be longer than 1 year + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Download-Id-For-Futures-Trade-History + * + * $downloadId = $api->futuresDownloadIdForTrades(1744105700000, 1744105722122); + * + * @property int $weight 1000 + * + * @param int $startTime (optional) timestamp in ms to get trades from INCLUSIVE + * @param int $endTime (optional) timestamp in ms to get trades until INCLUSIVE + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the response + * @throws \Exception + */ + public function futuresDownloadIdForTrades(int $startTime, int $endTime, int $recvWindow = null) + { + return $this->futuresDownloadId($startTime, $endTime, $recvWindow, "v1/trade/asyn"); + } + + /** + * futuresDownloadTradesByDownloadId get futures trades history download link by Id + * download link expiration: 24h + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-Futures-Trade-Download-Link-by-Id + * + * $downloadLink = $api->futuresDownloadTradesByDownloadId("downloadId"); + * + * @property int $weight 10 + * + * @param string $downloadId (mandatory) download id + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array with error message or the download link + * @throws \Exception + */ + public function futuresDownloadTradesByDownloadId(string $downloadId, int $recvWindow = null) + { + return $this->futuresDownloadLinkByDownloadId($downloadId, $recvWindow, "v1/trade/asyn/id"); + } + + /** + * futuresFeeBurn change user's BNB Fee Discount (Fee Discount On or Fee Discount Off ) on EVERY symbol + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Toggle-BNB-Burn-On-Futures-Trade + * + * $response = $api->futuresFeeBurn(true); + * + * @property int $weight 1 + * + * @param bool $flag (mandatory) true for BNB Fee Discount On, false for BNB Fee Discount Off + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresFeeBurn(bool $flag, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + 'feeBurn' => $flag ? 'true' : 'false', + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/feeBurn", 'POST', $params, true); + } + + /** + * futuresFeeBurnStatus gets the BNB Fee Discount status + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Get-BNB-Burn-Status + * + * $response = $api->futuresFeeBurnStatus(); + * + * @property int $weight 30 + * + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function futuresFeeBurnStatus(int $recvWindow = null) + { + $params = [ + 'fapi' => true, + ]; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/feeBurn", 'GET', $params, true); + } + + /** + * convertExchangeInfo get all convertible token pairs and the tokens’ respective upper/lower limits + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/convert + * + * $converInfo = $api->convertExchangeInfo(); + * $converInfo = $api->convertExchangeInfo("ETH", "DOGE"); + * + * @property int $weight 20 + * + * @param string $fromAsset (optional) the asset to convert from + * @param string $toAsset (optional) the asset to convert to + * + * @return array containing the response + * @throws \Exception + */ + public function convertExchangeInfo($fromAsset = null, $toAsset = null) + { + $params = [ + 'fapi' => true, + ]; + if ($fromAsset) { + $params['fromAsset'] = $fromAsset; + } + if ($toAsset) { + $params['toAsset'] = $toAsset; + } + return $this->httpRequest("v1/convert/exchangeInfo", 'GET', $params); + } + + /** + * convertSend send a convert request + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/convert/Send-quote-request + * + * $convertRequest = $api->convertSend("ETH", "DOGE", 0.1); + * + * @property int $weight 50 + * + * @param string $fromAsset (mandatory) the asset to convert from + * @param string $toAsset (mandatory) the asset to convert to + * @param string $fromAmount (optional) mandatory if $toAmount is not set + * @param string $toAmount (optional) mandatory if $fromAmount is not set + * @param string $validTime (optional) deafault "10s" + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * + * @return array containing the response + * @throws \Exception + */ + public function convertSend(string $fromAsset, string $toAsset, $fromAmount = null, $toAmount = null, $validTime = null, int $recvWindow = null) + { + $params = [ + 'fapi' => true, + 'fromAsset' => $fromAsset, + 'toAsset' => $toAsset, + ]; + if ($fromAmount) { + $params['fromAmount'] = $fromAmount; + } else if ($toAmount) { + $params['toAmount'] = $toAmount; + } else { + throw new \Exception('convertSendRequest: fromAmount or toAmount must be set'); + } + if ($validTime) { + $params['validTime'] = $validTime; + } + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest("v1/convert/getQuote", 'POST', $params, true); + } + + /** + * convertAccept accept the offered quote by quote ID + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/convert/Accept-Quote + * + * $convertAccept = $api->convertAccept("quoteId"); + * + * @property int $weight 200 + * + * @param string $quoteId (mandatory) the quote ID to accept + * @param int $recvWindow (optional) the time in milliseconds to wait for a response + * @param array $params (optional) additional parameters + * + * @return array containing the response + * @throws \Exception + */ + public function convertAccept(string $quoteId, int $recvWindow = null, array $params = []) + { + $request = [ + 'quoteId' => $quoteId, + ]; + return $this->fapiRequest("v1/cconvert/acceptQuote", 'POST', array_merge($request, $params), true, $recvWindow); + } + + /** + * fapiRequest helper for creating a fapi httpRequest + */ + protected function fapiRequest(string $url, string $method, array $params = [], $signed = false, int $recvWindow = null) + { + $params['fapi'] = true; + if ($recvWindow) { + $params['recvWindow'] = $recvWindow; + } + return $this->httpRequest($url, $method, $params, $signed); + } + + /** + * convertStatus get the status of a convert request by orderId or quoteId + * + * @link https://developers.binance.com/docs/derivatives/usds-margined-futures/convert/Order-Status + * + * $status = $api->convertStatus("orderId"); + * + * @property int $weight 50 + * + * @param string $orderId (optional) the order ID to get the status of (mandatory if $quoteId is not set) + * @param string $quoteId (optional) the quote ID to get the status of (mandatory if $orderId is not set) + * + * @return array containing the response + * @throws \Exception + */ + public function convertStatus($orderId = null, $quoteId = null) + { + $params = [ + 'fapi' => true, + ]; + if ($orderId) { + $params['orderId'] = $orderId; + } else if ($quoteId) { + $params['quoteId'] = $quoteId; + } else { + throw new \Exception('convertStatus: orderId or quoteId must be set'); + } + return $this->httpRequest("v1/convert/orderStatus", 'GET', $params, true); + } +} \ No newline at end of file diff --git a/tests/BinanceLiveTests.php b/tests/BinanceLiveTests.php new file mode 100644 index 00000000..6539968f --- /dev/null +++ b/tests/BinanceLiveTests.php @@ -0,0 +1,55 @@ +spotBinance = new API('X4BHNSimXOK6RKs2FcKqExquJtHjMxz5hWqF0BBeVnfa5bKFMk7X0wtkfEz0cPrJ', 'x8gLihunpNq0d46F2q0TWJmeCDahX5LMXSlv3lSFNbMI3rujSOpTDKdhbcmPSf2i'); + $this->spotBinance->useTestnet = true; + + $this->futuresBinance = new API('227719da8d8499e8d3461587d19f259c0b39c2b462a77c9b748a6119abd74401', 'b14b935f9cfacc5dec829008733c40da0588051f29a44625c34967b45c11d73c'); + $this->futuresBinance->useTestnet = true; + } + public function testPricesSpot() + { + $res = $this->spotBinance->prices(); + $this->assertIsArray($res); + $this->assertArrayHasKey('BTCUSDT', $res); + $this->assertIsString($res['BTCUSDT']); + } + + public function testPricesFutures() + { + $res = $this->futuresBinance->futuresPrices(); + $this->assertIsArray($res); + $this->assertArrayHasKey('BTCUSDT', $res); + $this->assertIsString($res['BTCUSDT']); + } + + public function testBalanceSpot() + { + $res = $this->spotBinance->balances(); + $this->assertIsArray($res); + // $this->assertArrayHasKey('USDT', $res); + // $this->assertIsString($res['USDT']['free']); + } + + public function testBalanceFutures() + { + $res = $this->futuresBinance->futuresAccount(); + $this->assertIsArray($res); + $assets = $res['assets']; + $first = $assets[0]; + $this->assertArrayHasKey('asset', $first); + $this->assertArrayHasKey('walletBalance', $first); + } +} diff --git a/tests/BinanceStaticTests.php b/tests/BinanceStaticTests.php new file mode 100644 index 00000000..b44c1ea9 --- /dev/null +++ b/tests/BinanceStaticTests.php @@ -0,0 +1,89 @@ +binance = new MockBinanceAPI('api_key', 'api_secret'); + } + public function testPricesSpot() + { + try { + $this->binance->prices(); + } catch(\Throwable $e) { + + } + $this->assertEquals("https://api.binance.com/api/v3/ticker/price", self::$capturedUrl); + } + + + public function testSpotOrder() + { + try { + $this->binance->order('BUY', 'BTCUSDT', 1, 1000); + } catch(\Throwable $e) { + + } + $this->assertEquals("https://api.binance.com/api/v3/order", self::$capturedUrl); + + parse_str(self::$capturedBody, $params); + + $this->assertEquals("BTCUSDT", $params['symbol']); + $this->assertEquals("BUY", $params['side']); + $this->assertEquals("LIMIT", $params['type']); + $this->assertEquals(1, $params['quantity']); + $this->assertEquals(1000, $params['price']); + $this->assertEquals("GTC", $params['timeInForce']); + $this->assertTrue(str_starts_with($params['newClientOrderId'], $this->SPOT_ORDER_PREFIX)); + } + + public function testFuturesOrder() + { + try { + $this->binance->futuresOrder('BUY', 'BTCUSDT', 1, 1000); + } catch(\Throwable $e) { + + } + $this->assertEquals("https://fapi.binance.com/fapi/v1/order", self::$capturedUrl); + + parse_str(self::$capturedBody, $params); + print_r($params); + + $this->assertEquals("BTCUSDT", $params['symbol']); + $this->assertEquals("BUY", $params['side']); + $this->assertEquals("LIMIT", $params['type']); + $this->assertEquals(1, $params['quantity']); + $this->assertEquals(1000, $params['price']); + $this->assertEquals("GTC", $params['timeInForce']); + $this->assertTrue(str_starts_with($params['newClientOrderId'], $this->CONTRACT_ORDER_PREFIX)); + } +}