diff --git a/.github/workflow-settings.json b/.github/workflow-settings.json new file mode 100644 index 0000000..24b1cdd --- /dev/null +++ b/.github/workflow-settings.json @@ -0,0 +1,16 @@ +{ + "EXCLUDE_MESSAGES": [ + "update package version", + "update packages", + "update wp version", + "trigger workflow", + "update TOC" + ], + "PROJECT": "Backlog", + "ISSUE_COLUMN": "To do", + "PR_COLUMN": "In progress", + "PR_BODY_TITLE": "## Changes", + "TOC_FOLDING": "1", + "TOC_MAX_HEADER_LEVEL": "3", + "TOC_TITLE": "Summary" +} \ No newline at end of file diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml new file mode 100644 index 0000000..7d819fa --- /dev/null +++ b/.github/workflows/npmpublish.yml @@ -0,0 +1,61 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages + +name: Publish to NPM + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + #- run: npm ci + #- run: npm test + + publish-npm: + needs: build + runs-on: ubuntu-latest + steps: + - name: Package Version Updated + uses: MontyD/package-json-updated-action@1.0.1 + id: version-updated + with: + path: package.json + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@v2 + if: steps.version-updated.outputs.has-updated + + - uses: actions/setup-node@v1 + if: steps.version-updated.outputs.has-updated + with: + node-version: 12 + registry-url: https://registry.npmjs.org/ + + #- run: npm ci + - run: npm publish + if: steps.version-updated.outputs.has-updated + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} + + #publish-gpr: + #needs: build + #runs-on: ubuntu-latest + #steps: + #- uses: actions/checkout@v2 + #- uses: actions/setup-node@v1 + # with: + # node-version: 12 + # registry-url: https://npm.pkg.github.com/ + #- run: npm ci + #- run: npm publish + # env: + # NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/README.md b/README.md index f59e514..90b5328 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,24 @@ -# @pxtrn/bybit-api +# bybit-api [![npm version](https://img.shields.io/npm/v/bybit-api.svg)][1] [![npm size](https://img.shields.io/bundlephobia/min/bybit-api.svg)][1] [![npm downloads](https://img.shields.io/npm/dt/orderbooks.svg)][1] +[![CodeFactor](https://www.codefactor.io/repository/github/tiagosiebler/bybit-api/badge)](https://www.codefactor.io/repository/github/tiagosiebler/bybit-api) -An unofficial node.js lowlevel wrapper for the Bybit Cryptocurrency Derivative -exchange API. +[1]: https://www.npmjs.com/package/bybit-api +An unofficial node.js lowlevel wrapper for the Bybit Cryptocurrency Derivative exchange API. Forked from [@pxtrn/bybit-api](https://github.com/pixtron/bybit-api), due to low activity on fixes & improvements. ## Installation - -`npm install --save @pxtrn/bybit-api` - +`npm install --save bybit-api` ## Usage - Create API credentials at bybit (obviously you need to be logged in): - [Livenet](https://bybit.com/app/user/api-management) - [Testnet](https://testnet.bybit.com/app/user/api-management) +## Documentation +Most of the documentation is in [Bybit's official API docs](https://bybit-exchange.github.io/docs/inverse/#t-introduction). Most of this library's methods accept objects that directly correspond to expectations from Bybit's API docs. ### Rest client - -```js -const {RestClient} = require('@pxtrn/bybit-api'); +```javascript +const {RestClient} = require('bybit-api'); const API_KEY = 'xxx'; const PRIVATE_KEY = 'yyy'; @@ -37,11 +36,9 @@ client.changeUserLeverage({leverage: 4, symbol: 'ETHUSD'}) See rest client [api docs](./doc/rest-client.md) for further information. - ### Websocket client - -```js -const {WebsocketClient} = require('@pxtrn/bybit-api'); +```javascript +const {WebsocketClient} = require('bybit-api'); const API_KEY = 'xxx'; const PRIVATE_KEY = 'yyy'; @@ -78,7 +75,7 @@ See websocket client [api docs](./doc/websocket-client.md) for further informati Pass a custom logger which supports the log methods `silly`, `debug`, `notice`, `info`, `warning` and `error`, or override methods from the default logger as desired: ```js -const { RestClient, WebsocketClient, DefaultLogger } = require('@pxtrn/bybit-api'); +const { RestClient, WebsocketClient, DefaultLogger } = require('bybit-api'); // Disable all logging on the silly level DefaultLogger.silly = () => {}; @@ -89,11 +86,23 @@ const PRIVATE_KEY = 'yyy'; const ws = new WebsocketClient({key: API_KEY, secret: PRIVATE_KEY}, DefaultLogger); ``` -## Donations - -If this library helps you to trade better on bybit, feel free to donate a coffee, -or create a bybit account using my [ref link](https://www.bybit.com/app/register?ref=j8q5l). +## Contributions & Thanks +### Donations +#### pixtron +This library was started by @pixtron. If this library helps you to trade better on bybit, feel free to donate a coffee to @pixtron or create a bybit account using his [ref link](https://www.bybit.com/app/register?ref=j8q5l). - BTC `1Fh1158pXXudfM6ZrPJJMR7Y5SgZUz4EdF` - ETH `0x21aEdeC53ab7593b77C9558942f0c9E78131e8d7` - LTC `LNdHSVtG6UWsriMYLJR3qLdfVNKwJ6GSLF` + +#### tiagosiebler +If you found this project interesting or useful, create accounts with my referral links: +- [Bybit](https://www.bybit.com/en-US/register?affiliate_id=9410&language=en-US&group_id=0&group_type=1) +- [Binance](https://www.binance.com/en/register?ref=20983262) + +Or feed my coffee addiction using any of these: +- BTC: `1C6GWZL1XW3jrjpPTS863XtZiXL1aTK7Jk` +- ETH (ERC20): `0xd773d8e6a50758e1ada699bb6c4f98bb4abf82da` + +### Contributions & Pull Requests +Contributions are encouraged, I will review any incoming pull requests. See the issues tab for todo items. diff --git a/doc/rest-client.md b/doc/rest-client.md index 8a2828d..1f4db12 100644 --- a/doc/rest-client.md +++ b/doc/rest-client.md @@ -2,8 +2,6 @@ ## Class: RestClient - - ### new RestClient([key][, secret][, livenet][, options]) - `key` {String} Bybit API Key - `secret` {String} Bybit private key @@ -12,11 +10,9 @@ - `recv_window` {Number} Optional, default 5000. Increase if recv errors are seen. - `sync_interval_ms` {Number} Optional, default 3600000. Interval at which syncTime is performed. -If you only use the [public endpoints](#public-endpoints) you can ommit key and secret. - +If you only use the [public endpoints](#public-endpoints) you can omit key and secret. ### Private enpoints - #### async placeActiveOrder(params) [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-placev2active) @@ -126,12 +122,10 @@ Returns symbol information (such as tick size & min notional): Returns the time offset in ms to the server time retrieved by [`async getServerTime`](#async-getservertime). If positive the time on the server is ahead of the clients time, if negative the time on the server is behind the clients time. - - ## Example -```js -const {RestClient} = require('@pxtrn/bybit-api'); +```javascript +const {RestClient} = require('bybit-api'); const API_KEY = 'xxx'; const PRIVATE_KEY = 'yyy'; diff --git a/doc/websocket-client.md b/doc/websocket-client.md index 828ab62..23ecfbd 100644 --- a/doc/websocket-client.md +++ b/doc/websocket-client.md @@ -1,19 +1,16 @@ # Websocket API - - ## Class: WebsocketClient The `WebsocketClient` inherits from `EventEmitter`. After establishing a connection, the client sends heartbeats in regular intervalls, and reconnects to the server once connection has been lost. - ### new WebsocketClient([options][, logger]) - `options` {Object} Configuration options - `key` {String} Bybit API Key. Only needed if private topics are subscribed - `secret` {String} Bybit private Key. Only needed if private topics are subscribed - - `livenet` {Bool} Weather to connect to livenet (`true`). Default `false`. + - `livenet` {Bool} Weather to connect to livenet (`true`). Default `false`. - `pingInterval` {Integer} Interval in ms for heartbeat ping. Default: `10000`, - `pongTimeout` {Integer} Timeout in ms waiting for heartbeat pong response from server. Default: `1000`, @@ -21,45 +18,36 @@ to the server once connection has been lost. to reconnect after a lost connection. Default: 500 - `logger` {Object} Optional custom logger - Custom logger must contain the following methods: - ```js - const logger = { - silly: function(message, data) {}, - debug: function(message, data) {}, - notice: function(message, data) {}, - info: function(message, data) {}, - warning: function(message, data) {}, - error: function(message, data) {}, - } - ``` +Custom logger must contain the following methods: +```js +const logger = { + silly: function(message, data) {}, + debug: function(message, data) {}, + notice: function(message, data) {}, + info: function(message, data) {}, + warning: function(message, data) {}, + error: function(message, data) {}, +} +``` ### ws.subscribe(topics) - - `topics` {String|Array} Single topic as string or multiple topics as array of strings. Subscribe to one or multiple topics. See [available topics](#available-topics) ### ws.unsubscribe(topics) - - `topics` {String|Array} Single topic as string or multiple topics as array of strings. Unsubscribe from one or multiple topics. ### ws.close() - Close the connection to the server. - ### Event: 'open' - Emmited when the connection has been opened for the first time. - ### Event: 'reconnected' - Emmited when the client has been opened after a reconnect. - ### Event: 'update' - - `message` {Object} - `topic` {String} the topic for which the update occured - `data` {Array|Object} updated data (see docs for each [topic](#available-topics)). @@ -67,9 +55,7 @@ Emmited when the client has been opened after a reconnect. Emmited whenever an update to a subscribed topic occurs. - ### Event: 'response' - - `response` {Object} - `success` {Bool} - `ret_msg` {String} empty if operation was successfull, otherwise error message. @@ -80,108 +66,86 @@ Emmited whenever an update to a subscribed topic occurs. Emited when the server responds to an operation sent by the client (usually after subscribing to a topic). - ### Event: 'close' - Emitted when the connection has been finally closed, after a call to `ws.close()` - ### Event: 'reconnect' - Emitted when the connection has been closed, but the client will try to reconnect. - ### Event: 'error' - - `error` {Error} Emitted when an error occurs. - ## Available Topics - Generaly all [public](https://bybit-exchange.github.io/docs/inverse/#t-publictopics) and [private](https://bybit-exchange.github.io/docs/inverse/#t-privatetopics) topics are available. ### Private topics - #### Positions of your account - All positions of your account. Topic: `position` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketposition) #### Execution message - Execution message, whenever an order has been (partially) filled. Topic: `execution` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketexecution) #### Update for your orders - Updates for your active orders Topic: `order` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketorder) #### Update for your conditional orders - Updates for your active conditional orders Topic: `stop_order` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketstoporder) - ### Public topics - #### Candlestick chart - Candlestick OHLC "candles" for selected symbol and interval. Example topic: `klineV2.BTCUSD.1m` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketklinev2) #### Real-time trading information - All trades as they occur. Topic: `trade` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websockettrade) #### Daily insurance fund update - Topic: `insurance` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketinsurance) #### OrderBook of 25 depth per side - OrderBook for selected symbol Example topic: `orderBookL2_25.BTCUSD` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketorderbook25) #### OrderBook of 200 depth per side - OrderBook for selected symbol Example topic: `orderBook_200.100ms.BTCUS` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketorderbook200) #### Latest information for symbol - Latest information for selected symbol Example topic: `instrument_info.100ms.BTCUSD` [See bybit documentation](https://bybit-exchange.github.io/docs/inverse/#t-websocketinstrumentinfo) - -## Example - -```js -const {WebsocketClient} = require('@pxtrn/bybit-api'); +## Examples +### Klines +```javascript +const {WebsocketClient} = require('bybit-api'); const API_KEY = 'xxx'; const PRIVATE_KEY = 'yyy'; @@ -211,3 +175,49 @@ ws.on('error', function(err) { console.error('ERR', err); }); ``` + +### OrderBook Events +```javascript +const { WebsocketClient, DefaultLogger } = require('bybit-api'); +const { OrderBooksStore, OrderBookLevel } = require('orderbooks'); + +const OrderBooks = new OrderBooksStore({ traceLog: true, checkTimestamps: false }); + +// connect to a websocket and relay orderbook events to handlers +DefaultLogger.silly = () => {}; +const ws = new WebsocketClient({ livenet: true }); +ws.on('update', message => { + if (message.topic.toLowerCase().startsWith('orderbook')) { + return handleOrderbookUpdate(message); + } +}); +ws.subscribe('orderBookL2_25.BTCUSD'); + +// parse orderbook messages, detect snapshot vs delta, and format properties using OrderBookLevel +const handleOrderbookUpdate = message => { + const { topic, type, data, timestamp_e6 } = message; + const [ topicKey, symbol ] = topic.split('.'); + + if (type == 'snapshot') { + return OrderBooks.handleSnapshot(symbol, data.map(mapBybitBookSlice), timestamp_e6 / 1000, message).print(); + } + + if (type == 'delta') { + const deleteLevels = data.delete.map(mapBybitBookSlice); + const updateLevels = data.update.map(mapBybitBookSlice); + const insertLevels = data.insert.map(mapBybitBookSlice); + return OrderBooks.handleDelta( + symbol, + deleteLevels, + updateLevels, + insertLevels, + timestamp_e6 / 1000 + ).print(); + } +} + +// Low level map of exchange properties to expected local properties +const mapBybitBookSlice = level => { + return OrderBookLevel(level.symbol, +level.price, level.side, level.size); +}; +``` diff --git a/package.json b/package.json index 9c8b8c3..e7b9dcf 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@pxtrn/bybit-api", + "name": "bybit-api", "version": "1.1.6", "description": "An unofficial node.js lowlevel wrapper for the Bybit Cryptocurrency Derivative exchange API", "main": "index.js", @@ -8,7 +8,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/pixtron/bybit-api.git" + "url": "git+https://github.com/tiagosiebler/bybit-api.git" }, "keywords": [ "bybit", @@ -17,11 +17,14 @@ "rest" ], "author": "Stefan Aebischer (https://pixtron.ch)", + "contributors": [ + "Tiago Siebler (https://github.com/tiagosiebler)" + ] "license": "MIT", "bugs": { - "url": "https://github.com/pixtron/bybit-api/issues" + "url": "https://github.com/tiagosiebler/bybit-api/issues" }, - "homepage": "https://github.com/pixtron/bybit-api#readme", + "homepage": "https://github.com/tiagosiebler/bybit-api#readme", "dependencies": { "request": "^2.88.0", "ws": "^7.1.2"