tiagosiebler / bybit-api

Node.js SDK for the Bybit APIs and WebSockets, with TypeScript & browser support.
https://www.npmjs.com/package/bybit-api
MIT License
244 stars 80 forks source link

Support linear contracts #24

Closed tiagosiebler closed 3 years ago

tiagosiebler commented 3 years ago

Explore plans to support linear contracts for bybit. The linear APIs may have differences to the inverse APIs, but there should be reusable logic: https://bybit-exchange.github.io/docs/linear/#t-introduction

Proposals

These are in no particular order:

1. Introduce dedicated linear-client.js

See beppu's post below:

2. Expand existing rest-client.js for automatic handling

3. Introduce new rest-clientv2.js for automatic handling

4. inverse-client vs linear-client vs rest-clientv2

beppu commented 3 years ago

Thoughts

One way to organize support for the linear API is to introduce a lib/linear-client.js that's very similar to lib/rest-client.js except that it uses the endpoints for the linear API when applicable. The main goal would be to break as little existing code as possible, and this shouldn't break anything. index.js would still export DefaultLogger, WebsocketClient, RestClient, and it would also export a new LinearClient. It would then be the responsibility of the user of this library to know which client is needed to trade a particular market.

Extra Credit

In Closing...

You don't have to do it this way, but I just wanted to put some ideas out there. Also, I haven't looked at how other bybit API client libraries try to tackle this problem, but that's probably worth looking into as well.

tiagosiebler commented 3 years ago

Thanks for the ideas @beppu! These are definitely helpful and I definitely share some of these thoughts too. Adding a LinearClient without introducing breaking changes into the current clients seems the most logical step to get this done.

While we're adding support for another subset of APIs I do wonder whether this is an opportunity to introduce a v2 client.

One of the python libraries (pybit, I think?) handles the selection of the correct API automatically depending on the params used. I don't want to affect existing implementations, so I'd like to avoid breaking changes in rest-client for as long as constructively possible (although we can add a deprecation warning if a successor is ready).

That still brings an architectural question though in how we organise this, which might bring us to your idea of LinearClient vs InverseClient again...

Even if we have a singular "RestClientV2" it could wrap around both of these, automatically deciding which to use. It would keep things organised, allow implementation of a singular client if desired, but also allow "lazy" use of the 2-in-1 V2 client, which can automatically decide which to use.

I've edited the post to summarise the ideas so far. I think I'm leaning towards (4), which is essentially in line with your thoughts although we try to avoid breaking changes in the existing rest-client. Linear-only users could then specifically only require the linear part, or they could use RestClientV2 without worrying about the details on how a client is chosen (and the underlying logic passes calls to the LinearClient as needed).

beppu commented 3 years ago

When you proposed (3), I started imagining something like (4) as well, so I'm glad you arrived at a similar idea on your own. The only thing I would advise against is having rest-client.js wrap inverse-client.js or vice versa. To solve the problem of not duplicating code for the shared endpoints, I would introduce another new file called shared-endpoints.js. This file would export an object that contained the methods for those shared endpoints. Then I would have both InverseClient and LinearClient mix in SharedEndpoints.

const SharedEndpoints = require('./shared-endpoints')
class LinearClient {
  // only implement methods specific to the linear API
}
class InverseClient {
  // only implement methods specific to the inverse API
}
Object.assign(LinearClient.prototype, SharedEndpoints)
Object.assign(InverseClient.prototype, SharedEndpoints)

This would keep the client code sufficiently DRY.


Regarding adding a v2 client that's smart enough to know which market needs which client, I think that's a good idea.

tiagosiebler commented 3 years ago

I do agree with your point on wrapping inverse, but overall seems like (4) is the way to go!

beppu commented 3 years ago

I went through the official Bybit API docs, and I mapped out the inverse and linear endpoints. I also isolated the shared endpoints. I noticed you were doing some TypeScript work, and I was wondering if the LinearClient work should be done against that branch instead of master. Anyway, here's the table of endpoints:

method inverse endpoint linear endpoint shared endpoint
getOrderBook /v2/public/orderBook/L2
getKline /v2/public/kline/list /public/linear/kline
getLatestInformation /v2/public/tickers
getPublicTradingRecords /v2/public/trading-records /public/linear/recent-trading-records
getSymbols /v2/public/symbols
getPublicLiquidations /v2/public/liq-records
getMarkPriceKline * /v2/public/mark-price-kline /public/linear/mark-price-kline
getOpenInterest /v2/public/open-interest
getLatestBigDeal /v2/public/big-deal
getLongShortRatio /v2/public/account-ratio
placeActiveOrder /v2/private/order/create /private/linear/order/create
getActiveOrder /v2/private/order/list /private/linear/order/list
cancelActiveOrder /v2/private/order/cancel /private/linear/order/cancel
cancelAllActiveOrders /v2/private/order/cancelAll /private/linear/order/cancel-all
replaceActiveOrder /v2/private/order/replace /private/linear/order/replace
queryActiveOrder /v2/private/order /private/linear/order/search
placeConditionalOrder /v2/private/stop-order/create /private/linear/stop-order/create
getConditionalOrder /v2/private/stop-order/list /private/linear/stop-order/list
cancelConditionalOrder /v2/private/stop-order/cancel /private/linear/stop-order/cancel
cancelAllConditionalOrders /v2/private/stop-order/cancelAll /private/linear/stop-order/cancel-all
replaceConditionalOrder /v2/private/stop-order/replace /private/linear/stop-order/replace
queryConditionalOrder /v2/private/stop-order /private/linear/stop-order/search
getPosition /v2/private/position/list /private/linear/position/list
setAutoAddMargin /private/linear/position/set-auto-add-margin
switchIsolated /private/linear/position/switch-isolated
switchMode /private/linear/tpsl/switch-mode
addMargin /private/linear/position/add-margin
setLeverage /private/linear/position/set-leverage
changePositionMargin /position/change-position-margin
setTradingStop /open-api/position/trading-stop /private/linear/position/trading-stop
changeUserLeverage /user/leverage/save
getTradeRecords /v2/private/execution/list /private/linear/trade/execution/list
getClosedPNL * /v2/private/trade/closed-pnl/list /private/linear/trade/closed-pnl/list
getRiskLimitList /open-api/wallet/risk-limit/list /public/linear/risk-limit
setRiskLimit /open-api/wallet/risk-limit
getLastFundingRate /open-api/funding/prev-funding-rate
getMyLastFundingFee /open-api/funding/prev-funding /private/linear/funding/prev-funding
getPredictedFunding /open-api/funding/predicted-funding /private/linear/funding/predicted-funding
getAPIKeyInfo * /open-api/api-key
getLCPInfo * /v2/private/account/lcp
getWalletBalance /v2/private/wallet/balance
getWalletFundRecords /open-api/wallet/fund/records
getWithdrawRecords /open-api/wallet/withdraw/list
getAssetExchangeRecords /v2/private/exchange-order/list
getServerTime /v2/public/time
getAnnouncements * /v2/public/announcement
tiagosiebler commented 3 years ago

Hey @beppu - that's extremely useful! Yes please, I'm looking to get a very basic typescript transition done at first (introducing almost no changes where possible, meaning types will be relatively flexible at first).

If you're happy to start working on this, please base it on the typescript branch. It's up to date, just pending some more sanity checks I want to run on my side as well as some input from bybit's team.

peepo5 commented 3 years ago

TS Version Update: #75

tiagosiebler commented 3 years ago

Resolved with version 2.0.0, see #75