Repository: ccxt/ccxt
Pull request: bybit: integrate derivatives v3
Bybit have released derivatives v3 recently, and separate two parts (unified margin and contract v3). In this PR, I'll integrate derivatives v3 for bybit.

##### For unified margin

- [x] fetchOrderBook
- [x] fetchOHLCV
- [x] fetchMarketLeverageTiers
- [x] fetchOpenInterestHistory
- [x] fetchTrades
- [x] fetchFundingRateHistory
- [x] fetchTickers
- [x] add v3 public time
- [x] update fetchBalance
- [x] update setLeverage
- [x] update createOrder
- [x] update cancelOrder
- [x] update fetchOpenOrders
- [x] update fetchOrders
- [x] update fetchClosedOrders
- [x] update cancelAllOrders
- [x] add fetchPosition
- [x] update fetchPositions

TODO for refactor:
- [x] fetchOHLCV
- [x] cancelOrder
- [x] cancelAllOrders
- [x] fetchOrders
- [x] fetchClosedOrders
- [x] fetchOpenOrders
- [x] fetchPositions
- [x] setLeverage
- [x] fetchOpenInterestHistory
- [x] fetchMarketLeverageTiers

##### For contract v3

- [x] update fetchBalance
- [x] update setLeverage
- [x] update setPositionMode
- [x] update createOrder
- [x] update cancelOrder
- [x] update fetchOpenOrders
- [x] update fetchOrders
- [x] update fetchClosedOrders
- [x] update cancelAllOrders
- [x] update fetchPosition
- [x] update fetchPositions
- [x] update fetchMyTrades


( fixes #15648 )

Problem statement:
bybit can't use fetchOrder by id after created
I tried to search a lot on issues tab but no one report about this, I also tried to look at fetchOpenOrders and fetchClosedOrders and other endpoints tried using a custom id did not work too, closed:True. Everything I could find I tried

- OS: Mac OS 12.6
- Programming Language version: Python 3.9.10
- CCXT version: 2.1.67

```
import ccxt
clientData = {
    'apiKey': 'xxx',
    'secret': 'xxx',
    'options': {
        'defaultType': 'future'
    }
}
client = ccxt.bybit(clientData)
data = client.createOrder(
    'XRPUSDT',
    'MARKET',
    'sell',
    1
)
print(data)
print(client.fetchOrder(data.get('id'), 'XRPUSDT'))
```

```
Traceback (most recent call last):
  File "/Users/ulisses/Desktop/bybit.py", line 17, in <module>
    print(client.fetchOrder(data.get('id'), 'XRPUSDT'))
  File "/Users/ulisses/Projects/env/btc24h/lib/python3.9/site-packages/ccxt/bybit.py", line 2966, in fetch_order
    raise OrderNotFound(self.id + ' fetchOrder() order ' + id + ' not found')
ccxt.base.errors.OrderNotFound: bybit fetchOrder() order xx-xx-xx-xx-xxxx not found
```

Hints from issue discussion:

Commit message: bybit: refactor fetchOHLCV

Patch to review:
diff --git a/js/bybit.js b/js/bybit.js
index e99579b4b56da..b2add3c211c9e 100644
--- a/js/bybit.js
+++ b/js/bybit.js
@@ -50,7 +50,7 @@ module.exports = class bybit extends Exchange {
                 'fetchDepositAddressesByNetwork': true,
                 'fetchDeposits': true,
                 'fetchFundingRate': true,
-                'fetchFundingRateHistory': false,
+                'fetchFundingRateHistory': true,
                 'fetchIndexOHLCV': true,
                 'fetchLedger': true,
                 'fetchMarketLeverageTiers': true,
@@ -65,6 +65,7 @@ module.exports = class bybit extends Exchange {
                 'fetchOrderBook': true,
                 'fetchOrders': true,
                 'fetchOrderTrades': true,
+                'fetchPosition': true,
                 'fetchPositions': true,
                 'fetchPremiumIndexOHLCV': true,
                 'fetchTicker': true,
@@ -173,6 +174,7 @@ module.exports = class bybit extends Exchange {
                         // data
                         'v2/public/time': 1,
                         'v2/public/announcement': 1,
+                        'v3/public/time': 1,
                         // USDC endpoints
                         // option USDC
                         'option/usdc/openapi/public/v1/order-book': 1,
@@ -550,6 +552,7 @@ module.exports = class bybit extends Exchange {
                     '34026': ExchangeError, // the limit is no change
                     '34036': BadRequest, // {"ret_code":34036,"ret_msg":"leverage not modified","ext_code":"","ext_info":"","result":null,"time_now":"1652376449.258918","rate_limit_status":74,"rate_limit_reset_ms":1652376449255,"rate_limit":75}
                     '35015': BadRequest, // {"ret_code":35015,"ret_msg":"Qty not in range","ext_code":"","ext_info":"","result":null,"time_now":"1652277215.821362","rate_limit_status":99,"rate_limit_reset_ms":1652277215819,"rate_limit":100}
+                    '110043': BadRequest, // {"retCode":110043,"retMsg":"leverage not modified","result":{},"retExtInfo":null,"time":1665720465151}
                     '130006': InvalidOrder, // {"ret_code":130006,"ret_msg":"The number of contracts exceeds maximum limit allowed: too large","ext_code":"","ext_info":"","result":null,"time_now":"1658397095.099030","rate_limit_status":99,"rate_limit_reset_ms":1658397095097,"rate_limit":100}
                     '130021': InsufficientFunds, // {"ret_code":130021,"ret_msg":"orderfix price failed for CannotAffordOrderCost.","ext_code":"","ext_info":"","result":null,"time_now":"1644588250.204878","rate_limit_status":98,"rate_limit_reset_ms":1644588250200,"rate_limit":100} |  {"ret_code":130021,"ret_msg":"oc_diff[1707966351], new_oc[1707966351] with ob[....]+AB[....]","ext_code":"","ext_info":"","result":null,"time_now":"1658395300.872766","rate_limit_status":99,"rate_limit_reset_ms":1658395300855,"rate_limit":100} caused issues/9149#issuecomment-1146559498
                     '130074': InvalidOrder, // {"ret_code":130074,"ret_msg":"expect Rising, but trigger_price[190000000] \u003c= current[211280000]??LastPrice","ext_code":"","ext_info":"","result":null,"time_now":"1655386638.067076","rate_limit_status":97,"rate_limit_reset_ms":1655386638065,"rate_limit":100}
@@ -572,6 +575,7 @@ module.exports = class bybit extends Exchange {
                 'defaultType': 'swap',  // 'swap', 'future', 'option', 'spot'
                 'defaultSubType': 'linear',  // 'linear', 'inverse'
                 'defaultSettle': 'USDT', // USDC for USDC settled markets
+                'enableUnifiedMargin': false, // enable unified margin function
                 'code': 'BTC',
                 'recvWindow': 5 * 1000, // 5 sec default
                 'timeDifference': 0, // the difference between system clock and exchange server clock
@@ -1319,19 +1323,45 @@ module.exports = class bybit extends Exchange {
         //          "theta": "-0.03262827"
         //      }
         //
+        // Unified Margin
+        //
+        //     {
+        //         "symbol": "BTCUSDT",
+        //         "bidPrice": "19255",
+        //         "askPrice": "19255.5",
+        //         "lastPrice": "19255.50",
+        //         "lastTickDirection": "ZeroPlusTick",
+        //         "prevPrice24h": "18634.50",
+        //         "price24hPcnt": "0.033325",
+        //         "highPrice24h": "19675.00",
+        //         "lowPrice24h": "18610.00",
+        //         "prevPrice1h": "19278.00",
+        //         "markPrice": "19255.00",
+        //         "indexPrice": "19260.68",
+        //         "openInterest": "48069.549",
+        //         "turnover24h": "4686694853.047006",
+        //         "volume24h": "243730.252",
+        //         "fundingRate": "0.0001",
+        //         "nextFundingTime": "1663689600000",
+        //         "predictedDeliveryPrice": "",
+        //         "basisRate": "",
+        //         "deliveryFeeRate": "",
+        //         "deliveryTime": "0"
+        //     }
+        //
         const timestamp = this.safeInteger (ticker, 'time');
         const marketId = this.safeString (ticker, 'symbol');
         const symbol = this.safeSymbol (marketId, market);
         const last = this.safeString2 (ticker, 'last_price', 'lastPrice');
-        const open = this.safeString2 (ticker, 'prev_price_24h', 'openPrice');
-        let percentage = this.safeString2 (ticker, 'price_24h_pcnt', 'change24h');
+        const open = this.safeStringN (ticker, [ 'prev_price_24h', 'openPrice', 'prevPrice24h' ]);
+        let percentage = this.safeStringN (ticker, [ 'price_24h_pcnt', 'change24h', 'price24hPcnt' ]);
         percentage = Precise.stringMul (percentage, '100');
         const quoteVolume = this.safeStringN (ticker, [ 'turnover_24h', 'turnover24h', 'quoteVolume' ]);
         const baseVolume = this.safeStringN (ticker, [ 'volume_24h', 'volume24h', 'volume' ]);
-        const bid = this.safeStringN (ticker, [ 'bid_price', 'bid', 'bestBidPrice' ]);
-        const ask = this.safeStringN (ticker, [ 'ask_price', 'ask', 'bestAskPrice' ]);
-        const high = this.safeStringN (ticker, [ 'high_price_24h', 'high24h', 'highPrice' ]);
-        const low = this.safeStringN (ticker, [ 'low_price_24h', 'low24h', 'lowPrice' ]);
+        const bid = this.safeStringN (ticker, [ 'bid_price', 'bid', 'bestBidPrice', 'bidPrice' ]);
+        const ask = this.safeStringN (ticker, [ 'ask_price', 'ask', 'bestAskPrice', 'askPrice' ]);
+        const high = this.safeStringN (ticker, [ 'high_price_24h', 'high24h', 'highPrice', 'highPrice24h' ]);
+        const low = this.safeStringN (ticker, [ 'low_price_24h', 'low24h', 'lowPrice', 'lowPrice24h' ]);
         return this.safeTicker ({
             'symbol': symbol,
             'timestamp': timestamp,
@@ -1464,6 +1494,162 @@ module.exports = class bybit extends Exchange {
         return ticker;
     }
 
+    async fetchSpotTickers (symbols = undefined, params = {}) {
+        await this.loadMarkets ();
+        symbols = this.marketSymbols (symbols);
+        const response = await this.publicGetSpotQuoteV1Ticker24hr (params);
+        //
+        //     {
+        //         "ret_code":0,
+        //         "ret_msg":null,
+        //         "result":[
+        //             {
+        //                 "time":1667198103209,
+        //                 "symbol":"XDCUSDT",
+        //                 "bestBidPrice":"0.03092",
+        //                 "bestAskPrice":"0.03093",
+        //                 "volume":"393311",
+        //                 "quoteVolume":"12189.678747",
+        //                 "lastPrice":"0.03092",
+        //                 "highPrice":"0.03111",
+        //                 "lowPrice":"0.0309",
+        //                 "openPrice":"0.0309"
+        //             }
+        //         ],
+        //         "ext_code": null,
+        //         "ext_info": null
+        //     }
+        //
+        const tickerList = this.safeValue (response, 'result', []);
+        const tickers = {};
+        for (let i = 0; i < tickerList.length; i++) {
+            const ticker = this.parseTicker (tickerList[i]);
+            const symbol = ticker['symbol'];
+            tickers[symbol] = ticker;
+        }
+        return this.filterByArray (tickers, 'symbol', symbols);
+    }
+
+    async fetchUnifiedMarginTickers (symbols = undefined, params = {}) {
+        await this.loadMarkets ();
+        symbols = this.marketSymbols (symbols);
+        const request = {};
+        let market = undefined;
+        if (symbols !== undefined) {
+            const symbol = this.safeValue (symbols, 0);
+            market = this.market (symbol);
+        }
+        if (market['option']) {
+            // bybit requires a symbol when query tockers for options markets
+            throw new NotSupported (this.id + ' fetchTickers() is not supported for option markets');
+        } else if (market['inverse']) {
+            request['category'] = 'inverse';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        }
+        const response = await this.publicGetDerivativesV3PublicTickers (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "symbol": "BTCUSDT",
+        //                     "bidPrice": "19255",
+        //                     "askPrice": "19255.5",
+        //                     "lastPrice": "19255.50",
+        //                     "lastTickDirection": "ZeroPlusTick",
+        //                     "prevPrice24h": "18634.50",
+        //                     "price24hPcnt": "0.033325",
+        //                     "highPrice24h": "19675.00",
+        //                     "lowPrice24h": "18610.00",
+        //                     "prevPrice1h": "19278.00",
+        //                     "markPrice": "19255.00",
+        //                     "indexPrice": "19260.68",
+        //                     "openInterest": "48069.549",
+        //                     "turnover24h": "4686694853.047006",
+        //                     "volume24h": "243730.252",
+        //                     "fundingRate": "0.0001",
+        //                     "nextFundingTime": "1663689600000",
+        //                     "predictedDeliveryPrice": "",
+        //                     "basisRate": "",
+        //                     "deliveryFeeRate": "",
+        //                     "deliveryTime": "0"
+        //                 }
+        //             ]
+        //         },
+        //         "retExtInfo": null,
+        //         "time": 1663670053454
+        //     }
+        //
+        let tickerList = this.safeValue (response, 'result', []);
+        if (!Array.isArray (tickerList)) {
+            tickerList = this.safeValue (tickerList, 'list');
+        }
+        const tickers = {};
+        for (let i = 0; i < tickerList.length; i++) {
+            const ticker = this.parseTicker (tickerList[i]);
+            const symbol = ticker['symbol'];
+            tickers[symbol] = ticker;
+        }
+        return this.filterByArray (tickers, 'symbol', symbols);
+    }
+
+    async fetchDerivativesTickers (symbols = undefined, params = {}) {
+        await this.loadMarkets ();
+        symbols = this.marketSymbols (symbols);
+        const response = await this.publicGetV2PublicTickers (params);
+        //
+        //     {
+        //         "ret_code": 0,
+        //         "ret_msg": "OK",
+        //         "result": [
+        //             {
+        //                 "symbol": "BTCUSD",
+        //                 "bid_price": "19244.5",
+        //                 "ask_price": "19245",
+        //                 "last_price": "19244.50",
+        //                 "last_tick_direction": "MinusTick",
+        //                 "prev_price_24h": "18780.50",
+        //                 "price_24h_pcnt": "0.024706",
+        //                 "high_price_24h": "19582.00",
+        //                 "low_price_24h": "18492.50",
+        //                 "prev_price_1h": "19217.00",
+        //                 "mark_price": "19242.60",
+        //                 "index_price": "19229.37",
+        //                 "open_interest": 4.13999123e+08,
+        //                 "countdown_hour": 0,
+        //                 "turnover_24h": "1977.97821021",
+        //                 "volume_24h": 3.7810482e+07,
+        //                 "funding_rate": "0.0001",
+        //                 "predicted_funding_rate": "",
+        //                 "next_funding_time": "2022-09-08T16:00:00Z",
+        //                 "predicted_delivery_price": "",
+        //                 "total_turnover": "",
+        //                 "total_volume": 0,
+        //                 "delivery_fee_rate": "",
+        //                 "delivery_time": "",
+        //                 "price_1h_pcnt": "",
+        //                 "open_value": ""
+        //             }
+        //         ],
+        //         "ext_code": "",
+        //         "ext_info": "",
+        //         "time_now": "1662629551.232415"
+        //     }
+        //
+        const tickerList = this.safeValue (response, 'result', []);
+        const tickers = {};
+        for (let i = 0; i < tickerList.length; i++) {
+            const ticker = this.parseTicker (tickerList[i]);
+            const symbol = ticker['symbol'];
+            tickers[symbol] = ticker;
+        }
+        return this.filterByArray (tickers, 'symbol', symbols);
+    }
+
     async fetchTickers (symbols = undefined, params = {}) {
         /**
          * @method
@@ -1492,24 +1678,16 @@ module.exports = class bybit extends Exchange {
                 isUsdcSettled = defaultSettle === 'USDC';
             }
         }
-        let method = undefined;
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
         if (type === 'spot') {
-            method = 'publicGetSpotQuoteV1Ticker24hr';
+            return await this.fetchSpotTickers (symbols, params);
+        } else if (enableUnifiedMargin) {
+            return await this.fetchUnifiedMarginTickers (symbols, params);
         } else if (!isUsdcSettled) {
-            // inverse perpetual // usdt linear // inverse futures
-            method = 'publicGetV2PublicTickers';
+            return await this.fetchDerivativesTickers (symbols, params);
         } else {
             throw new NotSupported (this.id + ' fetchTickers() is not supported for USDC markets');
         }
-        const response = await this[method] (params);
-        const result = this.safeValue (response, 'result', []);
-        const tickers = {};
-        for (let i = 0; i < result.length; i++) {
-            const ticker = this.parseTicker (result[i]);
-            const symbol = ticker['symbol'];
-            tickers[symbol] = ticker;
-        }
-        return this.filterByArray (tickers, 'symbol', symbols);
     }
 
     parseOHLCV (ohlcv, market = undefined) {
@@ -1570,6 +1748,18 @@ module.exports = class bybit extends Exchange {
         //         "0" // taker quote volume
         //     ]
         //
+        // Unified Margin
+        //
+        //     [
+        //         "1621162800",
+        //         "49592.43",
+        //         "49644.91",
+        //         "49342.37",
+        //         "49349.42",
+        //         "1451.59",
+        //         "2.4343353100000003"
+        //     ]
+        //
         if (Array.isArray (ohlcv)) {
             return [
                 this.safeNumber (ohlcv, 0),
@@ -1594,22 +1784,9 @@ module.exports = class bybit extends Exchange {
         ];
     }
 
-    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchOHLCV
-         * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
-         * @param {string} symbol unified symbol of the market to fetch OHLCV data for
-         * @param {string} timeframe the length of time each candle represents
-         * @param {int|undefined} since timestamp in ms of the earliest candle to fetch
-         * @param {int|undefined} limit the maximum amount of candles to fetch
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
-         */
+    async fetchSpotOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
         await this.loadMarkets ();
         const market = this.market (symbol);
-        const price = this.safeString (params, 'price');
-        params = this.omit (params, 'price');
         const request = {
             'symbol': market['id'],
         };
@@ -1627,74 +1804,147 @@ module.exports = class bybit extends Exchange {
         if (limit !== undefined) {
             request['limit'] = limit; // max 200, default 200
         }
-        let method = undefined;
-        let intervalKey = 'interval';
-        let sinceKey = 'from';
-        const isUsdcSettled = market['settle'] === 'USDC';
-        if (market['spot']) {
-            method = 'publicGetSpotQuoteV1Kline';
-        } else if (market['contract'] && !isUsdcSettled) {
-            if (market['linear']) {
-                // linear swaps/futures
-                const methods = {
-                    'mark': 'publicGetPublicLinearMarkPriceKline',
-                    'index': 'publicGetPublicLinearIndexPriceKline',
-                    'premiumIndex': 'publicGetPublicLinearPremiumIndexKline',
-                };
-                method = this.safeValue (methods, price, 'publicGetPublicLinearKline');
-            } else {
-                // inverse swaps/ futures
-                const methods = {
-                    'mark': 'publicGetV2PublicMarkPriceKline',
-                    'index': 'publicGetV2PublicIndexPriceKline',
-                    'premiumIndex': 'publicGetV2PublicPremiumPriceKline',
-                };
-                method = this.safeValue (methods, price, 'publicGetV2PublicKlineList');
-            }
+        request['interval'] = timeframe;
+        request['from'] = sinceTimestamp;
+        const response = await this.publicGetSpotQuoteV1Kline (params);
+        //
+        //     {
+        //         "ret_code": "0",
+        //         "ret_msg": null,
+        //         "result": [
+        //             [
+        //                 1651837620000,
+        //                 "35831.5",
+        //                 "35831.5",
+        //                 "35801.93",
+        //                 "35817.11",
+        //                 "1.23453",
+        //                 0,
+        //                 "44213.97591627",
+        //                 24,
+        //                 "0",
+        //                 "0"
+        //             ]
+        //         ],
+        //         "ext_code": null,
+        //         "ext_info": null
+        //     }
+        //
+        const ohlcvs = this.safeValue (response, 'result');
+        return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+    }
+
+    async fetchUnifiedMarginOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        const duration = this.parseTimeframe (timeframe);
+        const now = this.seconds ();
+        let sinceTimestamp = undefined;
+        if (limit === undefined) {
+            limit = 200; // default is 200 when requested with `since`
+        }
+        if (since === undefined) {
+            sinceTimestamp = now - limit * duration;
         } else {
-            // usdc markets
-            if (market['option']) {
-                throw new NotSupported (this.id + ' fetchOHLCV() is not supported for USDC options markets');
-            }
-            intervalKey = 'period';
-            sinceKey = 'startTime';
-            const methods = {
-                'mark': 'publicGetPerpetualUsdcOpenapiPublicV1MarkPriceKline',
-                'index': 'publicGetPerpetualUsdcOpenapiPublicV1IndexPriceKline',
-                'premiumIndex': 'publicGetPerpetualUsdcOpenapiPublicV1PremiumPriceKline',
-            };
-            method = this.safeValue (methods, price, 'publicGetPerpetualUsdcOpenapiPublicV1KlineList');
+            sinceTimestamp = parseInt (since / 1000);
         }
-        // spot markets use the same interval format as ccxt
-        // so we don't need  to convert it
-        request[intervalKey] = market['spot'] ? timeframe : this.timeframes[timeframe];
-        request[sinceKey] = sinceTimestamp;
-        const response = await this[method] (this.extend (request, params));
-        //
-        // inverse perpetual BTC/USD
+        if (limit !== undefined) {
+            request['limit'] = limit; // max 200, default 200
+        }
+        sinceTimestamp = sinceTimestamp * 1000;
+        // end is required parameter
+        let endTimestamp = this.safeInteger (params, 'end');
+        if (endTimestamp === undefined) {
+            endTimestamp = this.sum (sinceTimestamp, limit * duration * 1000);
+        }
+        request['end'] = endTimestamp;
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['inverse']) {
+            request['category'] = 'inverse';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        }
+        request['start'] = sinceTimestamp;
+        request['interval'] = this.timeframes[timeframe];
+        const price = this.safeString (params, 'price');
+        params = this.omit (params, 'price');
+        const methods = {
+            'mark': 'publicGetDerivativesV3PublicMarkPriceKline',
+            'index': 'publicGetDerivativesV3PublicIndexPriceKline',
+        };
+        const method = this.safeValue (methods, price, 'publicGetDerivativesV3PublicKline');
+        const response = await this[method] (params);
         //
         //     {
-        //         ret_code: 0,
-        //         ret_msg: 'OK',
-        //         ext_code: '',
-        //         ext_info: '',
-        //         result: [
-        //             {
-        //                 symbol: 'BTCUSD',
-        //                 interval: '1',
-        //                 open_time: 1583952540,
-        //                 open: '7760.5',
-        //                 high: '7764',
-        //                 low: '7757',
-        //                 close: '7763.5',
-        //                 volume: '1259766',
-        //                 turnover: '162.32773718999994'
-        //             },
-        //         ],
-        //         time_now: '1583953082.397330'
+        //         "retCode": 0,
+        //         "retMsg":"success",
+        //         "result":{
+        //             "category":"linear",
+        //             "symbol":"BTCUSDT",
+        //             "interval":"1",
+        //             "list":[
+        //                 [
+        //                     "1621162800",
+        //                     "49592.43",
+        //                     "49644.91",
+        //                     "49342.37",
+        //                     "49349.42",
+        //                     "1451.59",
+        //                     "2.4343353100000003"
+        //                 ]
+        //             ]
+        //         }
         //     }
         //
-        // linear perpetual BTC/USDT
+        const result = this.safeValue (response, 'result');
+        const ohlcvs = this.safeValue (result, 'list');
+        return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+    }
+
+    async fetchDerivativesOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        const duration = this.parseTimeframe (timeframe);
+        const now = this.seconds ();
+        let sinceTimestamp = undefined;
+        if (limit === undefined) {
+            limit = 200; // default is 200 when requested with `since`
+        }
+        if (since === undefined) {
+            sinceTimestamp = now - limit * duration;
+        } else {
+            sinceTimestamp = parseInt (since / 1000);
+        }
+        if (limit !== undefined) {
+            request['limit'] = limit; // max 200, default 200
+        }
+        request['interval'] = this.timeframes[timeframe];
+        request['from'] = sinceTimestamp;
+        let methods = {};
+        if (market['linear']) {
+            methods = {
+                'mark': 'publicGetPublicLinearMarkPriceKline',
+                'index': 'publicGetPublicLinearIndexPriceKline',
+                'premiumIndex': 'publicGetPublicLinearPremiumIndexKline',
+            };
+        } else {
+            methods = {
+                'mark': 'publicGetV2PublicMarkPriceKline',
+                'index': 'publicGetV2PublicIndexPriceKline',
+                'premiumIndex': 'publicGetV2PublicPremiumPriceKline',
+            };
+        }
+        const price = this.safeString (params, 'price');
+        params = this.omit (params, 'price');
+        const method = this.safeValue (methods, price, 'publicGetPublicLinearKline');
+        const response = await this[method] (params);
         //
         //     {
         //         "ret_code":0,
@@ -1716,73 +1966,133 @@ module.exports = class bybit extends Exchange {
         //         ],
         //         "time_now":"1587884120.168077"
         //     }
-        // spot
-        //     {
-        //    "ret_code": "0",
-        //    "ret_msg": null,
-        //     "result": [
-        //         [
-        //             1651837620000,
-        //             "35831.5",
-        //             "35831.5",
-        //             "35801.93",
-        //             "35817.11",
-        //             "1.23453",
-        //             0,
-        //             "44213.97591627",
-        //             24,
-        //             "0",
-        //             "0"
-        //         ]
-        //     ],
-        //     "ext_code": null,
-        //     "ext_info": null
-        // }
         //
-        const result = this.safeValue (response, 'result', {});
-        return this.parseOHLCVs (result, market, timeframe, since, limit);
+        const ohlcvs = this.safeValue (response, 'result');
+        return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
     }
 
-    async fetchFundingRate (symbol, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchFundingRate
-         * @description fetch the current funding rate
-         * @param {string} symbol unified market symbol
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/en/latest/manual.html#funding-rate-structure}
-         */
+    async fetchUSDCOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
         await this.loadMarkets ();
         const market = this.market (symbol);
         const request = {
             'symbol': market['id'],
         };
-        const isUsdcSettled = market['settle'] === 'USDC';
-        let method = undefined;
-        if (isUsdcSettled) {
-            method = 'privatePostPerpetualUsdcOpenapiPrivateV1PredictedFunding';
+        const duration = this.parseTimeframe (timeframe);
+        const now = this.seconds ();
+        let sinceTimestamp = undefined;
+        if (limit === undefined) {
+            limit = 200; // default is 200 when requested with `since`
+        }
+        if (since === undefined) {
+            sinceTimestamp = now - limit * duration;
         } else {
-            method = market['linear'] ? 'privateGetPrivateLinearFundingPredictedFunding' : 'privateGetV2PrivateFundingPredictedFunding';
+            sinceTimestamp = parseInt (since / 1000);
         }
-        const response = await this[method] (this.extend (request, params));
+        if (limit !== undefined) {
+            request['limit'] = limit; // max 200, default 200
+        }
+        // usdc markets
+        if (market['option']) {
+            throw new NotSupported (this.id + ' fetchUSDCOHLCV() is not supported for USDC options markets');
+        }
+        request['period'] = this.timeframes[timeframe];
+        request['startTime'] = sinceTimestamp;
+        const price = this.safeString (params, 'price');
+        params = this.omit (params, 'price');
+        const methods = {
+            'mark': 'publicGetPerpetualUsdcOpenapiPublicV1MarkPriceKline',
+            'index': 'publicGetPerpetualUsdcOpenapiPublicV1IndexPriceKline',
+            'premiumIndex': 'publicGetPerpetualUsdcOpenapiPublicV1PremiumPriceKline',
+        };
+        const method = this.safeValue (methods, price, 'publicGetPerpetualUsdcOpenapiPublicV1KlineList');
+        const response = await this[method] (params);
         //
-        // linear
         //     {
-        //       "ret_code": 0,
-        //       "ret_msg": "OK",
-        //       "ext_code": "",
-        //       "ext_info": "",
-        //       "result": {
-        //         "predicted_funding_rate": 0.0001,
-        //         "predicted_funding_fee": 0.00231849
-        //       },
-        //       "time_now": "1658446366.304113",
-        //       "rate_limit_status": 119,
-        //       "rate_limit_reset_ms": 1658446366300,
-        //       "rate_limit": 120
-        //     }
-        //
-        // inverse
+        //         "retCode":0,
+        //         "retMsg":"",
+        //         "result":[
+        //             {
+        //                 "symbol":"BTCPERP",
+        //                 "period":"1",
+        //                 "openTime":"1635648300",
+        //                 "open":"0.000066",
+        //                 "high":"0.000066",
+        //                 "low":"0.000066",
+        //                 "close":"0.000066"
+        //             }
+        //         ]
+        //     }
+        //
+        const ohlcvs = this.safeValue (response, 'result');
+        return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+    }
+
+    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchOHLCV
+         * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
+         * @param {string} symbol unified symbol of the market to fetch OHLCV data for
+         * @param {string} timeframe the length of time each candle represents
+         * @param {int|undefined} since timestamp in ms of the earliest candle to fetch
+         * @param {int|undefined} limit the maximum amount of candles to fetch
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
+         */
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const isUsdcSettled = market['settle'] === 'USDC';
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (market['spot']) {
+            return await this.fetchSpotOHLCV (symbol, timeframe, since, limit, params);
+        } else if (enableUnifiedMargin) {
+            return await this.fetchUnifiedMarginOHLCV (symbol, timeframe, since, limit, params);
+        } else if (market['contract'] && !isUsdcSettled) {
+            return await this.fetchDerivativesOHLCV (symbol, timeframe, since, limit, params);
+        }
+        return await this.fetchUSDCOHLCV (symbol, timeframe, since, limit, params);
+    }
+
+    async fetchFundingRate (symbol, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchFundingRate
+         * @description fetch the current funding rate
+         * @param {string} symbol unified market symbol
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/en/latest/manual.html#funding-rate-structure}
+         */
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        const isUsdcSettled = market['settle'] === 'USDC';
+        let method = undefined;
+        if (isUsdcSettled) {
+            method = 'privatePostPerpetualUsdcOpenapiPrivateV1PredictedFunding';
+        } else {
+            method = market['linear'] ? 'privateGetPrivateLinearFundingPredictedFunding' : 'privateGetV2PrivateFundingPredictedFunding';
+        }
+        const response = await this[method] (this.extend (request, params));
+        //
+        // linear
+        //     {
+        //       "ret_code": 0,
+        //       "ret_msg": "OK",
+        //       "ext_code": "",
+        //       "ext_info": "",
+        //       "result": {
+        //         "predicted_funding_rate": 0.0001,
+        //         "predicted_funding_fee": 0.00231849
+        //       },
+        //       "time_now": "1658446366.304113",
+        //       "rate_limit_status": 119,
+        //       "rate_limit_reset_ms": 1658446366300,
+        //       "rate_limit": 120
+        //     }
+        //
+        // inverse
         //     {
         //       "ret_code": 0,
         //       "ret_msg": "OK",
@@ -1832,6 +2142,90 @@ module.exports = class bybit extends Exchange {
         };
     }
 
+    async fetchFundingRateHistory (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchFundingRateHistory
+         * @description fetches historical funding rate prices
+         * @param {string|undefined} symbol unified symbol of the market to fetch the funding rate history for
+         * @param {int|undefined} since timestamp in ms of the earliest funding rate to fetch
+         * @param {int|undefined} limit the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure} to fetch
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @param {int|undefined} params.until timestamp in ms of the latest funding rate
+         * @returns {[object]} a list of [funding rate structures]{@link https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure}
+         */
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (!enableUnifiedMargin) {
+            throw new BadRequest (this.id + ' fetchFundingRateHistory() must enable unified margin mode');
+        }
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' fetchFundingRateHistory() requires a symbol');
+        }
+        await this.loadMarkets ();
+        const request = {};
+        const market = this.market (symbol);
+        symbol = market['symbol'];
+        request['symbol'] = market['id'];
+        if (market['option']) {
+            throw new NotSupported (this.id + ' fetchFundingRateHistory() is not supported for option markets');
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        } else if (market['inverse']) {
+            request['category'] = 'inverse';
+        }
+        if (since !== undefined) {
+            request['startTime'] = since;
+        }
+        const until = this.safeInteger2 (params, 'until', 'till'); // unified in milliseconds
+        const endTime = this.safeInteger (params, 'endTime', until); // exchange-specific in milliseconds
+        params = this.omit (params, [ 'endTime', 'till', 'until' ]);
+        if (endTime !== undefined) {
+            request['endTime'] = endTime;
+        }
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const response = await this.publicGetDerivativesV3PublicFundingHistoryFundingRate (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "symbol": "BTCUSDT",
+        //                     "fundingRate": "0.0001",
+        //                     "fundingRateTimestamp": "1657728000000"
+        //                 },
+        //                 {
+        //                     "symbol": "BTCUSDT",
+        //                     "fundingRate": "0.0001",
+        //                     "fundingRateTimestamp": "1657699200000"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657782323371
+        //     }
+        //
+        const rates = [];
+        const result = this.safeValue (response, 'result');
+        const list = this.safeValue (result, 'list');
+        for (let i = 0; i < list.length; i++) {
+            const entry = list[i];
+            const timestamp = this.safeInteger (entry, 'fundingRateTimestamp');
+            rates.push ({
+                'info': entry,
+                'symbol': this.safeSymbol (this.safeString (entry, 'symbol')),
+                'fundingRate': this.safeNumber (entry, 'fundingRate'),
+                'timestamp': timestamp,
+                'datetime': this.iso8601 (timestamp),
+            });
+        }
+        const sorted = this.sortBy (rates, 'timestamp');
+        return this.filterBySymbolSinceLimit (sorted, symbol, since, limit);
+    }
+
     async fetchIndexOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
         const request = {
             'price': 'index',
@@ -1999,38 +2393,16 @@ module.exports = class bybit extends Exchange {
         }, market);
     }
 
-    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchTrades
-         * @description get the list of most recent trades for a particular symbol
-         * @param {string} symbol unified symbol of the market to fetch trades for
-         * @param {int|undefined} since timestamp in ms of the earliest trade to fetch
-         * @param {int|undefined} limit the maximum amount of trades to fetch
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
-         */
+    async fetchSpotTrades (symbol, since = undefined, limit = undefined, params = {}) {
         await this.loadMarkets ();
         const market = this.market (symbol);
-        let method = undefined;
         const request = {
             'symbol': market['id'],
         };
-        const isUsdcSettled = market['settle'] === 'USDC';
-        if (market['type'] === 'spot') {
-            method = 'publicGetSpotQuoteV1Trades';
-        } else if (!isUsdcSettled) {
-            // inverse perpetual // usdt linear // inverse futures
-            method = market['linear'] ? 'publicGetPublicLinearRecentTradingRecords' : 'publicGetV2PublicTradingRecords';
-        } else {
-            // usdc option/ swap
-            method = 'publicGetOptionUsdcOpenapiPublicV1QueryTradeLatest';
-            request['category'] = market['option'] ? 'OPTION' : 'PERPETUAL';
-        }
         if (limit !== undefined) {
-            request['limit'] = limit; // default 500, max 1000
+            request['limit'] = limit; // Default value is 60, max 60
         }
-        const response = await this[method] (this.extend (request, params));
+        const response = await this.publicGetSpotQuoteV1Trades (this.extend (request, params));
         //
         //     {
         //         ret_code: 0,
@@ -2039,18 +2411,103 @@ module.exports = class bybit extends Exchange {
         //         ext_info: '',
         //         result: [
         //             {
-        //                 id: 43785688,
-        //                 symbol: 'BTCUSD',
-        //                 price: 7786,
-        //                 qty: 67,
-        //                 side: 'Sell',
-        //                 time: '2020-03-11T19:18:30.123Z'
+        //                 "price": "50005.12",
+        //                 "time": 1620822657672,
+        //                 "qty": "0.0001",
+        //                 "isBuyerMaker": true
         //             },
         //         ],
         //         time_now: '1583954313.393362'
         //     }
         //
-        // usdc trades
+        const trades = this.safeValue (response, 'result', {});
+        return this.parseTrades (trades, market, since, limit);
+    }
+
+    async fetchUnifiedMarginTrades (symbol, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit; // Limit for data size per page, max size is 1000. Default as showing 500 pieces of data per page
+        }
+        request['category'] = market['inverse'] ? 'inverse' : 'linear';
+        const response = await this.publicGetDerivativesV3PublicRecentTrade (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "execId": "da66abbc-f358-5864-8d34-84ef7274d853",
+        //                     "symbol": "BTCUSDT",
+        //                     "price": "20802.50",
+        //                     "size": "0.200",
+        //                     "side": "Sell",
+        //                     "time": "1657870316630"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657870326247
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        const trades = this.safeValue (result, 'list', []);
+        return this.parseTrades (trades, market, since, limit);
+    }
+
+    async fetchDerivativesTrades (symbol, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit; // Limit for data size, max size is 1000. Default size is 500
+        }
+        const method = market['linear'] ? 'publicGetPublicLinearRecentTradingRecords' : 'publicGetV2PublicTradingRecords';
+        const response = await this[method] (this.extend (request, params));
+        //
+        //     {
+        //         "ret_code": 0,
+        //         "ret_msg": "OK",
+        //         "ext_code": "",
+        //         "ext_info": "",
+        //         "result": [
+        //             {
+        //                 "id": "18368131384",
+        //                 "symbol": "BTCUSDT",
+        //                 "price": 9499.5,
+        //                 "qty": 9500,
+        //                 "side": "Buy",
+        //                 "time": "2019-11-19T08:03:04.077Z",
+        //                 "trade_time_ms":1587638305175,
+        //                 "is_block_trade": false
+        //             }
+        //         ],
+        //         "time_now": "1567109419.049271"
+        //     }
+        //
+        const trades = this.safeValue (response, 'result', {});
+        return this.parseTrades (trades, market, since, limit);
+    }
+
+    async fetchUSDCTrades (symbol, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit; // default 500
+        }
+        request['category'] = market['option'] ? 'OPTION' : 'PERPETUAL';
+        const response = await this.publicGetOptionUsdcOpenapiPublicV1QueryTradeLatest (this.extend (request, params));
+        //
         //     {
         //         "retCode": 0,
         //           "retMsg": "Success.",
@@ -2070,29 +2527,60 @@ module.exports = class bybit extends Exchange {
         //         }
         //     }
         //
-        let trades = this.safeValue (response, 'result', {});
-        if (!Array.isArray (trades)) {
-            trades = this.safeValue (trades, 'dataList', []);
-        }
+        const result = this.safeValue (response, 'result', {});
+        const trades = this.safeValue (result, 'dataList', []);
         return this.parseTrades (trades, market, since, limit);
     }
 
+    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchTrades
+         * @description get the list of most recent trades for a particular symbol
+         * @param {string} symbol unified symbol of the market to fetch trades for
+         * @param {int|undefined} since timestamp in ms of the earliest trade to fetch
+         * @param {int|undefined} limit the maximum amount of trades to fetch
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
+         */
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        const isUsdcSettled = market['settle'] === 'USDC';
+        if (market['type'] === 'spot') {
+            return this.fetchSpotTrades (symbol, since, limit, params);
+        } else if (!isUsdcSettled) {
+            if (enableUnifiedMargin) {
+                return this.fetchUnifiedMarginTrades (symbol, since, limit, params);
+            }
+            return this.fetchDerivativesTrades (symbol, since, limit, params);
+        }
+        // usdc option/ swap
+        return this.fetchUSDCTrades (symbol, since, limit, params);
+    }
+
     parseOrderBook (orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1) {
         const market = this.market (symbol);
         if (market['spot']) {
             return super.parseOrderBook (orderbook, symbol, timestamp, bidsKey, asksKey, priceKey, amountKey);
         }
-        const bids = [];
-        const asks = [];
-        for (let i = 0; i < orderbook.length; i++) {
-            const bidask = orderbook[i];
-            const side = this.safeString (bidask, 'side');
-            if (side === 'Buy') {
-                bids.push (this.parseBidAsk (bidask, priceKey, amountKey));
-            } else if (side === 'Sell') {
-                asks.push (this.parseBidAsk (bidask, priceKey, amountKey));
-            } else {
-                throw new ExchangeError (this.id + ' parseOrderBook() encountered an unrecognized bidask format: ' + this.json (bidask));
+        let bids = [];
+        let asks = [];
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            bids = this.safeValue (orderbook, 'b');
+            asks = this.safeValue (orderbook, 'a');
+        } else {
+            for (let i = 0; i < orderbook.length; i++) {
+                const bidask = orderbook[i];
+                const side = this.safeString (bidask, 'side');
+                if (side === 'Buy') {
+                    bids.push (this.parseBidAsk (bidask, priceKey, amountKey));
+                } else if (side === 'Sell') {
+                    asks.push (this.parseBidAsk (bidask, priceKey, amountKey));
+                } else {
+                    throw new ExchangeError (this.id + ' parseOrderBook() encountered an unrecognized bidask format: ' + this.json (bidask));
+                }
             }
         }
         return {
@@ -2105,38 +2593,17 @@ module.exports = class bybit extends Exchange {
         };
     }
 
-    async fetchOrderBook (symbol, limit = undefined, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchOrderBook
-         * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
-         * @param {string} symbol unified symbol of the market to fetch the order book for
-         * @param {int|undefined} limit the maximum amount of order book entries to return
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols
-         */
+    async fetchSpotOrderBook (symbol, limit = undefined, params = {}) {
         await this.loadMarkets ();
         const market = this.market (symbol);
         const request = {
             'symbol': market['id'],
         };
-        const isUsdcSettled = market['settle'] === 'USDC';
-        let method = undefined;
-        if (market['spot']) {
-            method = 'publicGetSpotQuoteV1Depth';
-        } else if (!isUsdcSettled) {
-            // inverse perpetual // usdt linear // inverse futures
-            method = 'publicGetV2PublicOrderBookL2';
-        } else {
-            // usdc option/ swap
-            method = market['option'] ? 'publicGetOptionUsdcOpenapiPublicV1OrderBook' : 'publicGetPerpetualUsdcOpenapiPublicV1OrderBook';
-        }
         if (limit !== undefined) {
             request['limit'] = limit;
         }
-        const response = await this[method] (this.extend (request, params));
+        const response = await this.publicGetSpotQuoteV1Depth (this.extend (request, params));
         //
-        // spot
         //     {
         //         "ret_code": 0,
         //         "ret_msg": null,
@@ -2153,13 +2620,80 @@ module.exports = class bybit extends Exchange {
         //         "ext_info": null
         //     }
         //
-        // linear/inverse swap/futures
+        const result = this.safeValue (response, 'result', []);
+        const timestamp = this.safeInteger (result, 'time');
+        return this.parseOrderBook (result, symbol, timestamp);
+    }
+
+    async fetchUnifiedMarginOrderBook (symbol, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['inverse']) {
+            request['category'] = 'inverse';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        }
+        const response = await this.publicGetDerivativesV3PublicOrderBookL2 (this.extend (request, params));
         //
         //     {
-        //         ret_code: 0,
-        //         ret_msg: 'OK',
-        //         ext_code: '',
-        //         ext_info: '',
+        //         "retCode": 0,
+        //         "retMsg": "success",
+        //         "result": {
+        //             "s": "BTCUSDT",
+        //             "b": [
+        //                 [
+        //                     "28806",
+        //                     "0.06"
+        //                 ],
+        //                 [
+        //                     "28807",
+        //                     "5.005"
+        //                 ]
+        //             ],
+        //             "a": [
+        //                 [
+        //                     "29004",
+        //                     "0.001"
+        //                 ],
+        //                 [
+        //                     "29012",
+        //                     "0.017"
+        //                 ]
+        //             ],
+        //             "ts": 1653638043149,
+        //             "u": 4912426
+        //         }
+        //     }
+        //
+        const result = this.safeValue (response, 'result', []);
+        const timestamp = this.safeInteger (result, 'ts');
+        return this.parseOrderBook (result, symbol, timestamp);
+    }
+
+    async fetchDerivativesOrderBook (symbol, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const response = await this.publicGetV2PublicOrderBookL2 (this.extend (request, params));
+        //
+        //     {
+        //         ret_code: 0,
+        //         ret_msg: 'OK',
+        //         ext_code: '',
+        //         ext_info: '',
         //         result: [
         //             { symbol: 'BTCUSD', price: '7767.5', size: 677956, side: 'Buy' },
         //             { symbol: 'BTCUSD', price: '7767', size: 580690, side: 'Buy' },
@@ -2168,7 +2702,22 @@ module.exports = class bybit extends Exchange {
         //         time_now: '1583954829.874823'
         //     }
         //
-        // usdc markets
+        const result = this.safeValue (response, 'result', []);
+        const timestamp = this.safeTimestamp (response, 'time_now');
+        return this.parseOrderBook (result, symbol, timestamp, 'Buy', 'Sell', 'price', 'size');
+    }
+
+    async fetchUSDCOrderBook (symbol, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const method = market['option'] ? 'publicGetOptionUsdcOpenapiPublicV1OrderBook' : 'publicGetPerpetualUsdcOpenapiPublicV1OrderBook';
+        const response = await this[method] (this.extend (request, params));
         //
         //     {
         //         "retCode": 0,
@@ -2188,15 +2737,34 @@ module.exports = class bybit extends Exchange {
         //    }
         //
         const result = this.safeValue (response, 'result', []);
-        let timestamp = this.safeTimestamp (response, 'time_now');
-        if (timestamp === undefined) {
-            timestamp = this.safeInteger (result, 'time');
+        const timestamp = this.safeInteger (response, 'time');
+        return this.parseOrderBook (result, symbol, timestamp, 'Buy', 'Sell', 'price', 'size');
+    }
+
+    async fetchOrderBook (symbol, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchOrderBook
+         * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
+         * @param {string} symbol unified symbol of the market to fetch the order book for
+         * @param {int|undefined} limit the maximum amount of order book entries to return
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols
+         */
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const isUsdcSettled = market['settle'] === 'USDC';
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (market['spot']) {
+            return this.fetchSpotOrderBook (symbol, limit, params);
+        } else if (enableUnifiedMargin) {
+            return this.fetchUnifiedMarginOrderBook (symbol, limit, params);
+        } else if (!isUsdcSettled) {
+            // inverse perpetual // usdt linear // inverse futures
+            return this.fetchDerivativesOrderBook (symbol, limit, params);
         }
-        const bidsKey = market['spot'] ? 'bids' : 'Buy';
-        const asksKey = market['spot'] ? 'asks' : 'Sell';
-        const priceKey = market['spot'] ? 0 : 'price';
-        const sizeKey = market['spot'] ? 1 : 'size';
-        return this.parseOrderBook (result, symbol, timestamp, bidsKey, asksKey, priceKey, sizeKey);
+        // usdc option/ swap
+        return this.fetchUSDCOrderBook (symbol, limit, params);
     }
 
     parseBalance (response) {
@@ -2268,16 +2836,56 @@ module.exports = class bybit extends Exchange {
         //       "retMsg": "Success."
         //    }
         //
+        // Unified Margin
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "Success",
+        //         "result": {
+        //             "totalEquity": "112.21267421",
+        //             "accountIMRate": "0.6895",
+        //             "totalMarginBalance": "80.37711012",
+        //             "totalInitialMargin": "55.42180254",
+        //             "totalAvailableBalance": "24.95530758",
+        //             "accountMMRate": "0.0459",
+        //             "totalPerpUPL": "-16.69586570",
+        //             "totalWalletBalance": "97.07311619",
+        //             "totalMaintenanceMargin": "3.68580537",
+        //             "coin": [
+        //                 {
+        //                     "currencyCoin": "ETH",
+        //                     "availableToBorrow": "0.00000000",
+        //                     "borrowSize": "0.00000000",
+        //                     "bonus": "0.00000000",
+        //                     "accruedInterest": "0.00000000",
+        //                     "availableBalanceWithoutConvert": "0.00000000",
+        //                     "totalOrderIM": "",
+        //                     "equity": "0.00000000",
+        //                     "totalPositionMM": "",
+        //                     "usdValue": "0.00000000",
+        //                     "availableBalance": "0.02441165",
+        //                     "unrealisedPnl": "",
+        //                     "totalPositionIM": "",
+        //                     "marginBalanceWithoutConvert": "0.00000000",
+        //                     "walletBalance": "0.00000000",
+        //                     "cumRealisedPnl": "",
+        //                     "marginBalance": "0.07862610"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657716037033
+        //     }
+        //
         const result = {
             'info': response,
         };
         const data = this.safeValue (response, 'result', {});
-        const balances = this.safeValue (data, 'balances');
+        const balances = this.safeValue2 (data, 'balances', 'coin');
         if (Array.isArray (balances)) {
             // spot balances
             for (let i = 0; i < balances.length; i++) {
                 const balance = balances[i];
-                const currencyId = this.safeString (balance, 'coin');
+                const currencyId = this.safeString2 (balance, 'coin', 'currencyCoin');
                 const code = this.safeCurrencyCode (currencyId);
                 const account = this.account ();
                 account['free'] = this.safeString (balance, 'availableBalance');
@@ -2310,41 +2918,9 @@ module.exports = class bybit extends Exchange {
         return this.safeBalance (result);
     }
 
-    async fetchBalance (params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchBalance
-         * @description query for balance and get the amount of funds available for trading or funds locked in orders
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
-         */
+    async fetchSpotBalance (params = {}) {
         await this.loadMarkets ();
-        const request = {};
-        let type = undefined;
-        [ type, params ] = this.handleMarketTypeAndParams ('fetchBalance', undefined, params);
-        let method = undefined;
-        if (type === 'spot') {
-            method = 'privateGetSpotV1Account';
-        } else {
-            let settle = this.safeString (this.options, 'defaultSettle');
-            settle = this.safeString2 (params, 'settle', 'defaultSettle', settle);
-            params = this.omit (params, [ 'settle', 'defaultSettle' ]);
-            const isUsdcSettled = settle === 'USDC';
-            if (!isUsdcSettled) {
-                // linear/inverse future/swap
-                method = 'privateGetV2PrivateWalletBalance';
-                const coin = this.safeString2 (params, 'coin', 'code');
-                params = this.omit (params, [ 'coin', 'code' ]);
-                if (coin !== undefined) {
-                    const currency = this.currency (coin);
-                    request['coin'] = currency['id'];
-                }
-            } else {
-                // usdc account
-                method = 'privatePostOptionUsdcOpenapiPrivateV1QueryWalletBalance';
-            }
-        }
-        const response = await this[method] (this.extend (request, params));
+        const response = await this.privateGetSpotV1Account (params);
         //
         //     {
         //         ret_code: 0,
@@ -2377,6 +2953,146 @@ module.exports = class bybit extends Exchange {
         return this.parseBalance (response);
     }
 
+    async fetchUnifiedMarginBalance (params = {}) {
+        await this.loadMarkets ();
+        const response = await this.privateGetUnifiedV3PrivateAccountWalletBalance (params);
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "Success",
+        //         "result": {
+        //             "totalEquity": "112.21267421",
+        //             "accountIMRate": "0.6895",
+        //             "totalMarginBalance": "80.37711012",
+        //             "totalInitialMargin": "55.42180254",
+        //             "totalAvailableBalance": "24.95530758",
+        //             "accountMMRate": "0.0459",
+        //             "totalPerpUPL": "-16.69586570",
+        //             "totalWalletBalance": "97.07311619",
+        //             "totalMaintenanceMargin": "3.68580537",
+        //             "coin": [
+        //                 {
+        //                     "currencyCoin": "ETH",
+        //                     "availableToBorrow": "0.00000000",
+        //                     "borrowSize": "0.00000000",
+        //                     "bonus": "0.00000000",
+        //                     "accruedInterest": "0.00000000",
+        //                     "availableBalanceWithoutConvert": "0.00000000",
+        //                     "totalOrderIM": "",
+        //                     "equity": "0.00000000",
+        //                     "totalPositionMM": "",
+        //                     "usdValue": "0.00000000",
+        //                     "availableBalance": "0.02441165",
+        //                     "unrealisedPnl": "",
+        //                     "totalPositionIM": "",
+        //                     "marginBalanceWithoutConvert": "0.00000000",
+        //                     "walletBalance": "0.00000000",
+        //                     "cumRealisedPnl": "",
+        //                     "marginBalance": "0.07862610"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657716037033
+        //     }
+        //
+        return this.parseBalance (response);
+    }
+
+    async fetchDerivativesBalance (params = {}) {
+        await this.loadMarkets ();
+        const request = {};
+        const coin = this.safeString2 (params, 'coin', 'code');
+        params = this.omit (params, [ 'coin', 'code' ]);
+        if (coin !== undefined) {
+            const currency = this.currency (coin);
+            request['coin'] = currency['id'];
+        }
+        const response = await this.privateGetV2PrivateWalletBalance (this.extend (request, params));
+        //
+        //    {
+        //        "ret_code": "0",
+        //        "ret_msg": "OK",
+        //        "ext_code": "",
+        //        "ext_info": "",
+        //        "result": {
+        //            "ADA": {
+        //                "equity": "0",
+        //                "available_balance": "0",
+        //                "used_margin": "0",
+        //                "order_margin": "0",
+        //                "position_margin": "0",
+        //                "occ_closing_fee": "0",
+        //                "occ_funding_fee": "0",
+        //                "wallet_balance": "0",
+        //                "realised_pnl": "0",
+        //                "unrealised_pnl": "0",
+        //                "cum_realised_pnl": "0",
+        //                "given_cash": "0",
+        //                "service_cash": "0"
+        //            },
+        //        },
+        //        "time_now": "1651772170.050566",
+        //        "rate_limit_status": "119",
+        //        "rate_limit_reset_ms": "1651772170042",
+        //        "rate_limit": "120"
+        //    }
+        //
+        return this.parseBalance (response);
+    }
+
+    async fetchUSDCBalance (params = {}) {
+        await this.loadMarkets ();
+        const response = await this.privatePostOptionUsdcOpenapiPrivateV1QueryWalletBalance (params);
+        //
+        //    {
+        //      "result": {
+        //           "walletBalance": "10.0000",
+        //           "accountMM": "0.0000",
+        //           "bonus": "0.0000",
+        //           "accountIM": "0.0000",
+        //           "totalSessionRPL": "0.0000",
+        //           "equity": "10.0000",
+        //           "totalRPL": "0.0000",
+        //           "marginBalance": "10.0000",
+        //           "availableBalance": "10.0000",
+        //           "totalSessionUPL": "0.0000"
+        //       },
+        //       "retCode": "0",
+        //       "retMsg": "Success."
+        //    }
+        //
+        return this.parseBalance (response);
+    }
+
+    async fetchBalance (params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchBalance
+         * @description query for balance and get the amount of funds available for trading or funds locked in orders
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
+         */
+        await this.loadMarkets ();
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('fetchBalance', undefined, params);
+        if (type === 'spot') {
+            return this.fetchSpotBalance (params);
+        }
+        let settle = this.safeString (this.options, 'defaultSettle');
+        settle = this.safeString2 (params, 'settle', 'defaultSettle', settle);
+        params = this.omit (params, [ 'settle', 'defaultSettle' ]);
+        const isUsdcSettled = settle === 'USDC';
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            return this.fetchUnifiedMarginBalance (params);
+        } else if (!isUsdcSettled) {
+            // linear/inverse future/swap
+            return this.fetchDerivativesBalance (params);
+        }
+        // usdc account
+        return this.fetchUSDCBalance (params);
+    }
+
     parseOrderStatus (status) {
         const statuses = {
             // basic orders
@@ -2752,8 +3468,11 @@ module.exports = class bybit extends Exchange {
         const market = this.market (symbol);
         symbol = market['symbol'];
         const isUsdcSettled = (market['settle'] === 'USDC');
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
         if (market['spot']) {
             return await this.createSpotOrder (symbol, type, side, amount, price, params);
+        } else if (enableUnifiedMargin) {
+            return await this.createUnifiedMarginOrder (symbol, type, side, amount, price, params);
         } else if (isUsdcSettled) {
             return await this.createUsdcOrder (symbol, type, side, amount, price, params);
         } else {
@@ -2835,6 +3554,101 @@ module.exports = class bybit extends Exchange {
         return this.parseOrder (order);
     }
 
+    async createUnifiedMarginOrder (symbol, type, side, amount, price = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        if (!market['linear'] && !market['option']) {
+            throw new NotSupported (this.id + ' createOrder does not allow inverse market orders for ' + symbol + ' markets');
+        }
+        if (price === undefined && type === 'limit') {
+            throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for limit orders');
+        }
+        const lowerCaseType = type.toLowerCase ();
+        const request = {
+            'symbol': market['id'],
+            'side': this.capitalize (side),
+            'orderType': this.capitalize (lowerCaseType), // limit or market
+            'timeInForce': 'GoodTillCancel', // ImmediateOrCancel, FillOrKill, PostOnly
+            'qty': this.amountToPrecision (symbol, amount),
+            // 'takeProfit': 123.45, // take profit price, only take effect upon opening the position
+            // 'stopLoss': 123.45, // stop loss price, only take effect upon opening the position
+            // 'reduceOnly': false, // reduce only, required for linear orders
+            // when creating a closing order, bybit recommends a True value for
+            //  closeOnTrigger to avoid failing due to insufficient available margin
+            // 'closeOnTrigger': false, required for linear orders
+            // 'orderLinkId': 'string', // unique client order id, max 36 characters
+            // 'triggerPrice': 123.45, // trigger price, required for conditional orders
+            // 'triggerBy': 'MarkPrice', // IndexPrice, MarkPrice
+            // 'tptriggerby': 'MarkPrice', // IndexPrice, MarkPrice
+            // 'slTriggerBy': 'MarkPrice', // IndexPrice, MarkPrice
+            // 'mmp': false // market maker protection
+            // 'positionIdx': 0, // Position mode. unified margin account is only available in One-Way mode, which is 0
+            // 'basePrice': '0', // It will be used to compare with the value of triggerPrice, to decide whether your conditional order will be triggered by crossing trigger price from upper side or lower side. Mainly used to identify the expected direction of the current conditional order.
+            // 'iv': '0', // Implied volatility, for options only; parameters are passed according to the real value; for example, for 10%, 0.1 is passed
+        };
+        if (market['linear']) {
+            request['category'] = 'linear';
+        } else {
+            request['category'] = 'option';
+        }
+        const isMarket = lowerCaseType === 'market';
+        const isLimit = lowerCaseType === 'limit';
+        if (isLimit) {
+            request['price'] = this.priceToPrecision (symbol, price);
+        }
+        const exchangeSpecificParam = this.safeString (params, 'time_in_force');
+        const timeInForce = this.safeStringLower (params, 'timeInForce');
+        const postOnly = this.isPostOnly (isMarket, exchangeSpecificParam === 'PostOnly', params);
+        if (postOnly) {
+            request['timeInForce'] = 'PostOnly';
+        } else if (timeInForce === 'gtc') {
+            request['timeInForce'] = 'GoodTillCancel';
+        } else if (timeInForce === 'fok') {
+            request['timeInForce'] = 'FillOrKill';
+        } else if (timeInForce === 'ioc') {
+            request['timeInForce'] = 'ImmediateOrCancel';
+        }
+        if (market['swap']) {
+            const triggerPrice = this.safeValue2 (params, 'stopPrice', 'triggerPrice');
+            const stopLossPrice = this.safeValue (params, 'stopLossPrice', triggerPrice);
+            const isStopLossOrder = stopLossPrice !== undefined;
+            const takeProfitPrice = this.safeValue (params, 'takeProfitPrice');
+            const isTakeProfitOrder = takeProfitPrice !== undefined;
+            const isStopOrder = isStopLossOrder || isTakeProfitOrder;
+            if (isStopOrder) {
+                request['triggerBy'] = 'LastPrice';
+                const stopPx = isStopLossOrder ? stopLossPrice : takeProfitPrice;
+                const preciseStopPrice = this.priceToPrecision (symbol, stopPx);
+                request['triggerPrice'] = preciseStopPrice;
+                const delta = this.numberToString (market['precision']['price']);
+                request['basePrice'] = isStopLossOrder ? Precise.stringSub (preciseStopPrice, delta) : Precise.stringAdd (preciseStopPrice, delta);
+            }
+        }
+        const clientOrderId = this.safeString (params, 'clientOrderId');
+        if (clientOrderId !== undefined) {
+            request['orderLinkId'] = clientOrderId;
+        } else if (market['option']) {
+            // mandatory field for options
+            request['orderLinkId'] = this.uuid16 ();
+        }
+        params = this.omit (params, [ 'stopPrice', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'postOnly', 'clientOrderId' ]);
+        const response = await this.privatePostUnifiedV3PrivateOrderCreate (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "orderId": "e10b0716-7c91-4091-b98a-1fa0f401c7d5",
+        //             "orderLinkId": "test0000003"
+        //         },
+        //         "retExtInfo": null,
+        //         "time": 1664441344238
+        //     }
+        //
+        const order = this.safeValue (response, 'result', {});
+        return this.parseOrder (order);
+    }
+
     async createUsdcOrder (symbol, type, side, amount, price = undefined, params = {}) {
         await this.loadMarkets ();
         const market = this.market (symbol);
@@ -3209,18 +4023,133 @@ module.exports = class bybit extends Exchange {
         }
     }
 
-    async cancelOrder (id, symbol = undefined, params = {}) {
-        /**
-         * @method
-         * @name bybit#cancelOrder
-         * @description cancels an open order
-         * @param {string} id order id
-         * @param {string} symbol unified symbol of the market the order was made in
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
-         */
+    async cancelSpotOrder (id, symbol = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            // 'order_link_id': 'string', // one of order_id, stop_order_id or order_link_id is required
+            // 'orderId': id
+        };
+        if (id !== undefined) { // The user can also use argument params["order_link_id"]
+            request['orderId'] = id;
+        }
+        const response = await this.privateDeleteSpotV1Order (this.extend (request, params));
+        //
+        //    {
+        //        "ret_code":0,
+        //        "ret_msg":"",
+        //        "ext_code":null,
+        //        "ext_info":null,
+        //        "result":{
+        //           "accountId":"24478790",
+        //           "symbol":"LTCUSDT",
+        //           "orderLinkId":"1652192399682",
+        //           "orderId":"1153067855569315072",
+        //           "transactTime":"1652192399866",
+        //           "price":"50",
+        //           "origQty":"0.2",
+        //           "executedQty":"0",
+        //           "status":"NEW",
+        //           "timeInForce":"GTC",
+        //           "type":"LIMIT",
+        //           "side":"BUY"
+        //        }
+        //    }
+        //
+        const result = this.safeValue (response, 'result', {});
+        return this.parseOrder (result, market);
+    }
+
+    async cancelUnifiedMarginOrder (id, symbol = undefined, params = {}) {
         if (symbol === undefined) {
-            throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
+            throw new ArgumentsRequired (this.id + ' cancelUnifiedMarginOrder() requires a symbol argument');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+            // 'orderLinkId': 'string',
+            // 'orderId': id,
+            // conditional orders
+            // 'orderFilter': '',
+            // 'category': '',
+        };
+        const orderType = this.safeStringLower (params, 'orderType');
+        const isStop = this.safeValue (params, 'stop', false);
+        const isConditional = isStop || (orderType === 'stop') || (orderType === 'conditional');
+        params = this.omit (params, [ 'orderType', 'stop' ]);
+        request['orderFilter'] = isConditional ? 'StopOrder' : 'Order';
+        if (id !== undefined) { // The user can also use argument params["orderLinkId"]
+            request['orderId'] = id;
+        }
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        } else {
+            throw new NotSupported (this.id + ' cancelUnifiedMarginOrder() does not allow inverse market orders for ' + symbol + ' markets');
+        }
+        const response = await this.privatePostUnifiedV3PrivateOrderCancel (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "orderId": "42c86d66331e41998d12c2440ce90c1a",
+        //             "orderLinkId": "e80d558e-ed"
+        //         }
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        return this.parseOrder (result, market);
+    }
+
+    async cancelUSDCOrder (id, symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelUSDCOrder() requires a symbol argument');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+            // 'orderLinkId': 'string', // one of order_id, stop_order_id or order_link_id is required
+            // 'orderId': id,
+        };
+        const orderType = this.safeStringLower (params, 'orderType');
+        const isStop = this.safeValue (params, 'stop', false);
+        const isConditional = isStop || (orderType === 'stop') || (orderType === 'conditional');
+        params = this.omit (params, [ 'orderType', 'stop' ]);
+        let method = undefined;
+        if (id !== undefined) { // The user can also use argument params["order_link_id"]
+            request['orderId'] = id;
+        }
+        if (market['option']) {
+            method = 'privatePostOptionUsdcOpenapiPrivateV1CancelOrder';
+        } else {
+            method = 'privatePostPerpetualUsdcOpenapiPrivateV1CancelOrder';
+            request['orderFilter'] = isConditional ? 'StopOrder' : 'Order';
+        }
+        const response = await this[method] (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "outRequestId": "",
+        //             "symbol": "BTC-13MAY22-40000-C",
+        //             "orderId": "8c65df91-91fc-461d-9b14-786379ef138c",
+        //             "orderLinkId": ""
+        //         },
+        //         "retExtMap": {}
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        return this.parseOrder (result, market);
+    }
+
+    async cancelDerivativesOrder (id, symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelDerivativesOrder() requires a symbol argument');
         }
         await this.loadMarkets ();
         const market = this.market (symbol);
@@ -3231,31 +4160,13 @@ module.exports = class bybit extends Exchange {
             // 'order_id': id, // one of order_id or order_link_id is required for regular orders
             // conditional orders ---------------------------------------------
             // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders
-            // spot orders
-            // 'orderId': id
         };
         const orderType = this.safeStringLower (params, 'orderType');
         const isStop = this.safeValue (params, 'stop', false);
         const isConditional = isStop || (orderType === 'stop') || (orderType === 'conditional');
         params = this.omit (params, [ 'orderType', 'stop' ]);
-        const isUsdcSettled = market['settle'] === 'USDC';
         let method = undefined;
-        if (market['spot']) {
-            method = 'privateDeleteSpotV1Order';
-            if (id !== undefined) { // The user can also use argument params["order_link_id"]
-                request['orderId'] = id;
-            }
-        } else if (isUsdcSettled) {
-            if (id !== undefined) { // The user can also use argument params["order_link_id"]
-                request['orderId'] = id;
-            }
-            if (market['option']) {
-                method = 'privatePostOptionUsdcOpenapiPrivateV1CancelOrder';
-            } else {
-                method = 'privatePostPerpetualUsdcOpenapiPrivateV1CancelOrder';
-                request['orderFilter'] = isConditional ? 'StopOrder' : 'Order';
-            }
-        } else if (market['linear']) {
+        if (market['linear']) {
             // linear futures and linear swaps
             method = isConditional ? 'privatePostPrivateLinearStopOrderCancel' : 'privatePostPrivateLinearOrderCancel';
         } else if (market['swap']) {
@@ -3265,7 +4176,7 @@ module.exports = class bybit extends Exchange {
             // inverse futures
             method = isConditional ? 'privatePostFuturesPrivateStopOrderCancel' : 'privatePostFuturesPrivateOrderCancel';
         }
-        if (market['contract'] && !isUsdcSettled && (id !== undefined)) { // id === undefined check because the user can also use argument params["order_link_id"]
+        if (market['contract'] && (id !== undefined)) { // id === undefined check because the user can also use argument params["order_link_id"]
             if (!isConditional) {
                 request['order_id'] = id;
             } else {
@@ -3273,28 +4184,7 @@ module.exports = class bybit extends Exchange {
             }
         }
         const response = await this[method] (this.extend (request, params));
-        // spot order
-        //    {
-        //        "ret_code":0,
-        //        "ret_msg":"",
-        //        "ext_code":null,
-        //        "ext_info":null,
-        //        "result":{
-        //           "accountId":"24478790",
-        //           "symbol":"LTCUSDT",
-        //           "orderLinkId":"1652192399682",
-        //           "orderId":"1153067855569315072",
-        //           "transactTime":"1652192399866",
-        //           "price":"50",
-        //           "origQty":"0.2",
-        //           "executedQty":"0",
-        //           "status":"NEW",
-        //           "timeInForce":"GTC",
-        //           "type":"LIMIT",
-        //           "side":"BUY"
-        //        }
-        //    }
-        // linear
+        //
         //    {
         //        "ret_code":0,
         //        "ret_msg":"OK",
@@ -3308,50 +4198,180 @@ module.exports = class bybit extends Exchange {
         //        "rate_limit_reset_ms":1652192814876,
         //        "rate_limit":100
         //     }
+        //
         const result = this.safeValue (response, 'result', {});
         return this.parseOrder (result, market);
     }
 
-    async cancelAllOrders (symbol = undefined, params = {}) {
+    async cancelOrder (id, symbol = undefined, params = {}) {
         /**
          * @method
-         * @name bybit#cancelAllOrders
-         * @description cancel all open orders
-         * @param {string|undefined} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
+         * @name bybit#cancelOrder
+         * @description cancels an open order
+         * @param {string} id order id
+         * @param {string} symbol unified symbol of the market the order was made in
          * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
+         * @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
          */
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const isUsdcSettled = market['settle'] === 'USDC';
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (market['spot']) {
+            return this.cancelSpotOrder (id, symbol, params);
+        } else if (enableUnifiedMargin) {
+            return this.cancelUnifiedMarginOrder (id, symbol, params);
+        } else if (isUsdcSettled) {
+            return this.cancelUSDCOrder (id, symbol, params);
+        }
+        return this.cancelDerivativesOrder (id, symbol, params);
+    }
+
+    async cancelAllSpotOrders (symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelAllSpotOrders() requires a symbol argument');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        const response = await this.privateDeleteSpotOrderBatchCancel (this.extend (request, params));
+        //
+        //    {
+        //        "ret_code": 0,
+        //        "ret_msg": "",
+        //        "ext_code": null,
+        //        "ext_info": null,
+        //        "result": {
+        //            "success": true
+        //        }
+        //    }
+        //
+        const result = this.safeValue (response, 'result', []);
+        if (!Array.isArray (result)) {
+            return response;
+        }
+        return this.parseOrders (result, market);
+    }
+
+    async cancelAllUnifiedMarginOrders (symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelAllUnifiedMarginOrders() requires a symbol argument');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        const orderType = this.safeStringLower (params, 'orderType');
+        const isStop = this.safeValue (params, 'stop', false);
+        const isConditional = isStop || (orderType === 'stop') || (orderType === 'conditional');
+        params = this.omit (params, [ 'stop', 'orderType' ]);
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        } else {
+            throw new NotSupported (this.id + ' cancelAllUnifiedMarginOrders() does not allow inverse market orders for ' + symbol + ' markets');
+        }
+        if (isConditional) {
+            request['orderFilter'] = 'StopOrder';
+        }
+        const response = await this.privatePostUnifiedV3PrivateOrderCancelAll (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "list": [{
+        //                     "category": "option",
+        //                     "symbol": "BTC-24JUN22-45000-P",
+        //                     "orderId": "bd5f3b34-d64d-4b60-8188-438fbea4c552",
+        //                     "orderLinkId": "ac4e3b34-d64d-4b60-8188-438fbea4c552",
+        //                 }, {
+        //                     "category": "option",
+        //                     "symbol": "BTC-24JUN22-45000-P",
+        //                     "orderId": "4ddd727a-2af8-430e-a293-42895e594d18",
+        //                     "orderLinkId": "5cee727a-2af8-430e-a293-42895e594d18",
+        //                 }
+        //             ]
+        //         },
+        //         "retExtInfo": {
+        //             "list": [{
+        //                 "code": 0,
+        //                 "msg": "OK"
+        //             }, {
+        //                 "code": 0,
+        //                 "msg": "OK"
+        //             }]
+        //         },
+        //         "time": 1657200736570
+        //     }
+        //
+        const result = this.safeValue (response, 'result', []);
+        const orders = this.safeValue (result, 'list');
+        if (!Array.isArray (orders)) {
+            return response;
+        }
+        return this.parseOrders (orders, market);
+    }
+
+    async cancelAllUSDCOrders (symbol = undefined, params = {}) {
         await this.loadMarkets ();
         let market = undefined;
-        let isUsdcSettled = undefined;
         if (symbol !== undefined) {
             market = this.market (symbol);
-            isUsdcSettled = market['settle'] === 'USDC';
-        } else {
-            let settle = this.safeString (this.options, 'defaultSettle');
-            settle = this.safeString2 (params, 'settle', 'defaultSettle', settle);
-            params = this.omit (params, [ 'settle', 'defaultSettle' ]);
-            isUsdcSettled = (settle === 'USDC');
         }
         let type = undefined;
-        [ type, params ] = this.handleMarketTypeAndParams ('cancelAllOrders', market, params);
-        if (!isUsdcSettled && symbol === undefined) {
-            throw new ArgumentsRequired (this.id + ' cancelAllOrders() requires a symbol argument for ' + type + ' markets');
+        [ type, params ] = this.handleMarketTypeAndParams ('cancelAllUSDCOrders', market, params);
+        let method = undefined;
+        method = (type === 'option') ? 'privatePostOptionUsdcOpenapiPrivateV1CancelAll' : 'privatePostPerpetualUsdcOpenapiPrivateV1CancelAll';
+        const response = await this[method] (params);
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "retExtMap": {},
+        //         "result": [
+        //             {
+        //                 "outRequestId": "cancelAll-290119-1652176443114-0",
+        //                 "symbol": "BTC-13MAY22-40000-C",
+        //                 "orderId": "fa6cd740-56ed-477d-9385-90ccbfee49ca",
+        //                 "orderLinkId": "",
+        //                 "errorCode": 0,
+        //                 "errorDesc": ""
+        //             }
+        //         ]
+        //     }
+        //
+        const result = this.safeValue (response, 'result', []);
+        if (!Array.isArray (result)) {
+            return response;
         }
-        const request = {};
-        if (!isUsdcSettled) {
-            request['symbol'] = market['id'];
+        return this.parseOrders (result, market);
+    }
+
+    async cancelAllDerivativesOrders (symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelAllDerivativesOrders() requires a symbol argument');
         }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('cancelAllDerivativesOrders', market, params);
+        const request = {
+            'symbol': market['id'],
+        };
         const orderType = this.safeStringLower (params, 'orderType');
         const isStop = this.safeValue (params, 'stop', false);
         const isConditional = isStop || (orderType === 'stop') || (orderType === 'conditional');
         params = this.omit (params, [ 'stop', 'orderType' ]);
         let method = undefined;
-        if (type === 'spot') {
-            method = 'privateDeleteSpotOrderBatchCancel';
-        } else if (isUsdcSettled) {
-            method = (type === 'option') ? 'privatePostOptionUsdcOpenapiPrivateV1CancelAll' : 'privatePostPerpetualUsdcOpenapiPrivateV1CancelAll';
-        } else if (type === 'future') {
+        if (type === 'future') {
             method = isConditional ? 'privatePostFuturesPrivateStopOrderCancelAll' : 'privatePostFuturesPrivateOrderCancelAll';
         } else if (market['linear']) {
             // linear swap
@@ -3361,17 +4381,6 @@ module.exports = class bybit extends Exchange {
             method = isConditional ? 'privatePostV2PrivateStopOrderCancelAll' : 'privatePostV2PrivateOrderCancelAll';
         }
         const response = await this[method] (this.extend (request, params));
-        // spot
-        //    {
-        //        "ret_code": 0,
-        //        "ret_msg": "",
-        //        "ext_code": null,
-        //        "ext_info": null,
-        //        "result": {
-        //            "success": true
-        //        }
-        //    }
-        //
         // linear swap
         //   {
         //       "ret_code":0,
@@ -3431,39 +4440,134 @@ module.exports = class bybit extends Exchange {
         return this.parseOrders (result, market);
     }
 
-    async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+    async cancelAllOrders (symbol = undefined, params = {}) {
         /**
          * @method
-         * @name bybit#fetchOrders
-         * @description fetches information on multiple orders made by the user
-         * @param {string} symbol unified market symbol of the market orders were made in
-         * @param {int|undefined} since the earliest time in ms to fetch orders for
-         * @param {int|undefined} limit the maximum number of  orde structures to retrieve
+         * @name bybit#cancelAllOrders
+         * @description cancel all open orders
+         * @param {string|undefined} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
          * @param {object} params extra parameters specific to the bybit api endpoint
          * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
          */
+        await this.loadMarkets ();
+        let market = undefined;
+        let isUsdcSettled = undefined;
+        if (symbol !== undefined) {
+            market = this.market (symbol);
+            isUsdcSettled = market['settle'] === 'USDC';
+        } else {
+            let settle = this.safeString (this.options, 'defaultSettle');
+            settle = this.safeString2 (params, 'settle', 'defaultSettle', settle);
+            params = this.omit (params, [ 'settle', 'defaultSettle' ]);
+            isUsdcSettled = (settle === 'USDC');
+        }
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('cancelAllOrders', market, params);
+        if (!isUsdcSettled && symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' cancelAllOrders() requires a symbol argument for ' + type + ' markets');
+        }
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (type === 'spot') {
+            return this.cancelAllSpotOrders (symbol, params);
+        } else if (enableUnifiedMargin) {
+            return this.cancelAllUnifiedMarginOrders (symbol, params);
+        } else if (isUsdcSettled) {
+            return this.cancelAllUSDCOrders (symbol, params);
+        }
+        return this.cancelAllDerivativesOrders (symbol, params);
+    }
+
+    async fetchUnifiedMarginOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
         if (symbol === undefined) {
-            throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument');
+            throw new ArgumentsRequired (this.id + ' fetchUnifiedMarginOrders() requires a symbol argument');
         }
         await this.loadMarkets ();
         const market = this.market (symbol);
-        if (market['spot'] || (market['settle'] === 'USDC')) {
-            throw new NotSupported (this.id + ' fetchOrders() does not support ' + market['type'] + ' markets or USDC markets, use exchange.fetchOpenOrders () and exchange.fetchClosedOrders () instead');
-        }
-        let method = undefined;
+        const request = {
+            'symbol': market['id'],
+            // 'category': string, Type of derivatives product: linear or option.
+            // 'baseCoin': string, Base coin. When category=option. If not passed, BTC by default; when category=linear, if BTC passed, BTCPERP & BTCUSDT returned.
+            // 'orderId': string, Order ID
+            // 'orderLinkId': string, Unique user-set order ID
+            // 'orderStatus': string, Query list of orders in designated states. If this parameter is not passed, the orders in all states shall be enquired by default. This parameter supports multi-state inquiry. States should be separated with English commas.
+            // 'orderFilter': string, Conditional order or active order
+            // 'direction': string, prev: prev, next: next.
+            // 'limit': number, Data quantity per page: Max data value per page is 50, and default value at 20.
+            // 'cursor': string, API pass-through. accountType + category + cursor +. If inconsistent, the following should be returned: The account type does not match the service inquiry.
+        };
         const isStop = this.safeValue (params, 'stop', false);
         const orderType = this.safeStringLower (params, 'orderType');
         const stopOrderId = this.safeString (params, 'stop_order_id'); // might want to filter by id
         const isConditionalOrder = isStop || (stopOrderId !== undefined) || (orderType === 'stop' || orderType === 'conditional');
         params = this.omit (params, [ 'orderType', 'stop', 'orderType' ]);
-        if (market['linear']) {
-            method = isConditionalOrder ? 'privateGetPrivateLinearStopOrderList' : 'privateGetPrivateLinearOrderList';
-        } else if (market['future']) {
-            method = isConditionalOrder ? 'privateGetFuturesPrivateStopOrderList' : 'privateGetFuturesPrivateOrderList';
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
         } else {
-            // inverse swap
-            method = isConditionalOrder ? 'privateGetV2PrivateStopOrderList' : 'privateGetV2PrivateOrderList';
+            throw new NotSupported (this.id + ' fetchUnifiedMarginOrders() does not allow inverse market orders for ' + symbol + ' markets');
+        }
+        if (isConditionalOrder) {
+            request['orderFilter'] = 'StopOrder';
+        }
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const response = await this.privateGetUnifiedV3PrivateOrderList (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "Success",
+        //         "result": {
+        //         "nextPageCursor": "7d17d359-4e38-4d3a-9a31-29791ef2dfd7%3A1657711949928%2C7d17d359-4e38-4d3a-9a31-29791ef2dfd7%3A1657711949928",
+        //         "category": "linear",
+        //         "list": [
+        //             {
+        //                 "symbol": "ETHUSDT",
+        //                 "orderType": "Market",
+        //                 "orderLinkId": "",
+        //                 "orderId": "7d17d359-4e38-4d3a-9a31-29791ef2dfd7",
+        //                 "stopOrderType": "UNKNOWN",
+        //                 "orderStatus": "Filled",
+        //                 "takeProfit": "",
+        //                 "cumExecValue": "536.92500000",
+        //                 "blockTradeId": "",
+        //                 "rejectReason": "EC_NoError",
+        //                 "price": "1127.10000000",
+        //                 "createdTime": 1657711949928,
+        //                 "tpTriggerBy": "UNKNOWN",
+        //                 "timeInForce": "ImmediateOrCancel",
+        //                 "basePrice": "",
+        //                 "leavesValue": "0.00000000",
+        //                 "updatedTime": 1657711949945,
+        //                 "side": "Buy",
+        //                 "triggerPrice": "",
+        //                 "cumExecFee": "0.32215500",
+        //                 "slTriggerBy": "UNKNOWN",
+        //                 "leavesQty": "0.0000",
+        //                 "closeOnTrigger": false,
+        //                 "cumExecQty": "0.5000",
+        //                 "reduceOnly": false,
+        //                 "qty": "0.5000",
+        //                 "stopLoss": "",
+        //                 "triggerBy": "UNKNOWN",
+        //                 "orderIM": ""
+        //             }]
+        //         },
+        //         "time": 1657713451741
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        const data = this.safeValue (result, 'list', []);
+        return this.parseOrders (data, market, since, limit);
+    }
+
+    async fetchDerivativesOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' fetchDerivativesOrders() requires a symbol argument');
         }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
         const request = {
             'symbol': market['id'],
             // 'order_id': 'string'
@@ -3477,6 +4581,20 @@ module.exports = class bybit extends Exchange {
             // 'stop_order_id': 'string',
             // 'stop_order_status': 'Untriggered',
         };
+        let method = undefined;
+        const isStop = this.safeValue (params, 'stop', false);
+        const orderType = this.safeStringLower (params, 'orderType');
+        const stopOrderId = this.safeString (params, 'stop_order_id'); // might want to filter by id
+        const isConditionalOrder = isStop || (stopOrderId !== undefined) || (orderType === 'stop' || orderType === 'conditional');
+        params = this.omit (params, [ 'orderType', 'stop', 'orderType' ]);
+        if (market['linear']) {
+            method = isConditionalOrder ? 'privateGetPrivateLinearStopOrderList' : 'privateGetPrivateLinearOrderList';
+        } else if (market['future']) {
+            method = isConditionalOrder ? 'privateGetFuturesPrivateStopOrderList' : 'privateGetFuturesPrivateOrderList';
+        } else {
+            // inverse swap
+            method = isConditionalOrder ? 'privateGetV2PrivateStopOrderList' : 'privateGetV2PrivateOrderList';
+        }
         if (limit !== undefined) {
             request['limit'] = limit;
         }
@@ -3572,6 +4690,150 @@ module.exports = class bybit extends Exchange {
         return this.parseOrders (data, market, since, limit);
     }
 
+    async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchOrders
+         * @description fetches information on multiple orders made by the user
+         * @param {string} symbol unified market symbol of the market orders were made in
+         * @param {int|undefined} since the earliest time in ms to fetch orders for
+         * @param {int|undefined} limit the maximum number of  orde structures to retrieve
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
+         */
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        if (market['spot']) {
+            throw new NotSupported (this.id + ' fetchOrders() does not support ' + market['type'] + ' markets, use exchange.fetchOpenOrders () and exchange.fetchClosedOrders () instead');
+        }
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            return this.fetchUnifiedMarginOrders (symbol, since, limit, params);
+        } else if (market['settle'] === 'USDC') {
+            throw new NotSupported (this.id + ' fetchOrders() does not support ' + market['type'] + ' USDC markets, use exchange.fetchOpenOrders () and exchange.fetchClosedOrders () instead');
+        }
+        return this.fetchDerivativesOrders (symbol, since, limit, params);
+    }
+
+    async fetchSpotClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        let market = undefined;
+        if (symbol !== undefined) {
+            market = this.market (symbol);
+        }
+        const request = {};
+        if (symbol !== undefined) {
+            request['symbol'] = market['id'];
+        }
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        if (since !== undefined) {
+            request['startTime'] = since;
+        }
+        const orders = await this.privateGetSpotV1HistoryOrders (this.extend (request, params));
+        const result = this.safeValue (orders, 'result', []);
+        //
+        //     {
+        //         "ret_code": 0,
+        //         "ret_msg": "",
+        //         "ext_code": null,
+        //         "ext_info": null,
+        //         "result": [
+        //             {
+        //                 "accountId": "10054",
+        //                 "exchangeId": "301",
+        //                 "symbol": "ETHUSDT",
+        //                 "symbolName": "ETHUSDT",
+        //                 "orderLinkId": "1620615771764",
+        //                 "orderId": "888183901021893120",
+        //                 "price": "5000",
+        //                 "origQty": "1",
+        //                 "executedQty": "0",
+        //                 "cummulativeQuoteQty": "0",
+        //                 "avgPrice": "0",
+        //                 "status": "CANCELED",
+        //                 "timeInForce": "GTC",
+        //                 "type": "LIMIT",
+        //                 "side": "BUY",
+        //                 "stopPrice": "0.0",
+        //                 "icebergQty": "0.0",
+        //                 "time": "1620615771836",
+        //                 "updateTime": "1620617056334",
+        //                 "isWorking": true
+        //             }
+        //         ]
+        //     }
+        //
+        return this.parseOrders (result, market, since, limit);
+    }
+
+    async fetchUSDCClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const request = {};
+        let market = undefined;
+        if (symbol !== undefined) {
+            market = this.market (symbol);
+            request['symbol'] = market['id'];
+        }
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('fetchUSDCClosedOrders', market, params);
+        request['category'] = (type === 'swap') ? 'perpetual' : 'option';
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const response = await this.privatePostOptionUsdcOpenapiPrivateV1QueryOrderHistory (this.extend (request, params));
+        //
+        //     {
+        //         "result": {
+        //         "cursor": "cc27c6ff-a4ec-4739-96bc-6d2b266606d4%3A1640843817698%2Ccc27c6ff-a4ec-4739-96bc-6d2b266606d4%3A1640843817698",
+        //             "resultTotalSize": 1,
+        //             "dataList": [
+        //             {
+        //             "symbol": "BTC-31DEC21-18000-P",
+        //             "orderType": "Limit",
+        //             "orderLinkId": "test2021122417000221",
+        //             "orderId": "cc27c6ff-a4ec-4739-96bc-6d2b266606d4",
+        //             "cancelType": "UNKNOWN",
+        //             "stopOrderType": "UNKNOWN",
+        //             "orderStatus": "Filled",
+        //             "takeProfit": "",
+        //             "createdAt": "1640843817698",
+        //             "orderPnl": "0.0000",
+        //             "price": "1.0",
+        //             "tpTriggerBy": "",
+        //             "timeInForce": "GoodTillCancel",
+        //             "updatedAt": "1640843817698",
+        //             "basePrice": "",
+        //             "realisedPnl": "0.0000",
+        //             "side": "Sell",
+        //             "triggerPrice": "",
+        //             "cumExecFee": "0.0010",
+        //             "leavesQty": "0.000",
+        //             "cashFlow": "0.0100",
+        //             "slTriggerBy": "",
+        //             "iv": "5.2820",
+        //             "closeOnTrigger": "",
+        //             "cumExecQty": "0.010",
+        //             "reduceOnly": 0,
+        //             "qty": "0.010",
+        //             "stopLoss": "",
+        //             "triggerBy": "",
+        //             "orderIM": "0.0000"
+        //             }
+        //         ]
+        //         },
+        //         "retCode": 0,
+        //         "retMsg": "Success."
+        //     }
+        //
+        const result = this.safeValue (response, 'dataList', []);
+        return this.parseOrders (result, market, since, limit);
+    }
+
     async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
         /**
          * @method
@@ -3597,6 +4859,9 @@ module.exports = class bybit extends Exchange {
         }
         let type = undefined;
         [ type, params ] = this.handleMarketTypeAndParams ('fetchClosedOrders', market, params);
+        if (type === 'spot') {
+            return await this.fetchSpotClosedOrders (symbol, since, limit, params);
+        }
         if ((type === 'swap' || type === 'future') && !isUsdcSettled) {
             if (symbol === undefined) {
                 throw new ArgumentsRequired (this.id + ' fetchClosedOrders requires a symbol argument for ' + symbol + ' markets');
@@ -3625,86 +4890,164 @@ module.exports = class bybit extends Exchange {
             const closeStatus = defaultStatuses.join (',');
             const status = this.safeString2 (params, 'order_status', 'status', closeStatus);
             params = this.omit (params, [ 'order_status', 'status' ]);
-            params['order_status'] = status;
+            const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+            if (enableUnifiedMargin) {
+                params['orderStatus'] = status;
+            } else {
+                params['order_status'] = status;
+            }
             return await this.fetchOrders (symbol, since, limit, params);
         }
+        return this.fetchUSDCClosedOrders (symbol, since, limit, params);
+    }
+
+    async fetchSpotOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
         const request = {};
-        let method = undefined;
-        if (type === 'spot') {
-            method = 'privateGetSpotV1HistoryOrders';
-        } else {
-            // usdc
-            method = 'privatePostOptionUsdcOpenapiPrivateV1QueryOrderHistory';
-            request['category'] = (type === 'swap') ? 'perpetual' : 'option';
+        let market = undefined;
+        if (symbol !== undefined) {
+            market = this.market (symbol);
+            request['symbol'] = symbol;
         }
-        const orders = await this[method] (this.extend (request, params));
-        let result = this.safeValue (orders, 'result', []);
-        if (!Array.isArray (result)) {
-            result = this.safeValue (result, 'dataList', []);
+        if (limit !== undefined) {
+            request['limit'] = limit;
         }
+        const response = await this.privateGetSpotV1OpenOrders (this.extend (request, params));
+        //
+        //     {
+        //         "ret_code": 0,
+        //         "ret_msg": "",
+        //         "ext_code": null,
+        //         "ext_info": null,
+        //         "result": [
+        //             {
+        //                 "accountId": "10054",
+        //                 "exchangeId": "301",
+        //                 "symbol": "ETHUSDT",
+        //                 "symbolName": "ETHUSDT",
+        //                 "orderLinkId": "162080709527252",
+        //                 "orderId": "889788838461927936",
+        //                 "price": "20000",
+        //                 "origQty": "10",
+        //                 "executedQty": "0",
+        //                 "cummulativeQuoteQty": "0",
+        //                 "avgPrice": "0",
+        //                 "status": "NEW",
+        //                 "timeInForce": "GTC",
+        //                 "type": "LIMIT",
+        //                 "side": "BUY",
+        //                 "stopPrice": "0.0",
+        //                 "icebergQty": "0.0",
+        //                 "time": "1620807095287",
+        //                 "updateTime": "1620807095307",
+        //                 "isWorking": true
+        //             }
+        //         ]
+        //     }
+        //
+        const result = this.safeValue (response, 'response', []);
         return this.parseOrders (result, market, since, limit);
     }
 
-    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchOpenOrders
-         * @description fetch all unfilled currently open orders
-         * @param {string|undefined} symbol unified market symbol
-         * @param {int|undefined} since the earliest time in ms to fetch open orders for
-         * @param {int|undefined} limit the maximum number of  open orders structures to retrieve
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
-         */
+    async fetchUnifiedMarginOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
         await this.loadMarkets ();
+        const request = {};
         let market = undefined;
-        let isUsdcSettled = undefined;
         if (symbol !== undefined) {
             market = this.market (symbol);
-            isUsdcSettled = market['settle'] === 'USDC';
+            request['symbol'] = market['id'];
+        }
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('fetchUnifiedMarginOpenOrders', market, params);
+        const isStop = this.safeValue (params, 'stop', false);
+        const isConditional = isStop || (type === 'stop') || (type === 'conditional');
+        params = this.omit (params, [ 'stop' ]);
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
         } else {
-            let settle = this.safeString (this.options, 'defaultSettle');
-            settle = this.safeString2 (params, 'settle', 'defaultSettle', settle);
-            params = this.omit (params, [ 'settle', 'defaultSettle' ]);
-            isUsdcSettled = settle === 'USDC';
+            throw new NotSupported (this.id + ' fetchUnifiedMarginOpenOrders() does not allow inverse market orders for ' + symbol + ' markets');
+        }
+        if (isConditional) {
+            request['orderFilter'] = 'StopOrder';
+        }
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const response = await this.privateGetUnifiedV3PrivateOrderUnfilledOrders (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "Success",
+        //         "result": {
+        //             "nextPageCursor": "135ccc0d-8136-4e1b-8af3-07b11ee158d1%3A1665565610526%2C135ccc0d-8136-4e1b-8af3-07b11ee158d1%3A1665565610526",
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "symbol": "ETHUSDT",
+        //                     "orderType": "Limit",
+        //                     "orderLinkId": "test0000005",
+        //                     "orderId": "135ccc0d-8136-4e1b-8af3-07b11ee158d1",
+        //                     "stopOrderType": "UNKNOWN",
+        //                     "orderStatus": "New",
+        //                     "takeProfit": "",
+        //                     "cumExecValue": "0.00000000",
+        //                     "blockTradeId": "",
+        //                     "price": "700.00000000",
+        //                     "createdTime": 1665565610526,
+        //                     "tpTriggerBy": "UNKNOWN",
+        //                     "timeInForce": "GoodTillCancel",
+        //                     "basePrice": "",
+        //                     "updatedTime": 1665565610533,
+        //                     "side": "Buy",
+        //                     "triggerPrice": "",
+        //                     "cumExecFee": "0.00000000",
+        //                     "slTriggerBy": "UNKNOWN",
+        //                     "leavesQty": "0.1000",
+        //                     "closeOnTrigger": false,
+        //                     "cumExecQty": "0.00000000",
+        //                     "reduceOnly": false,
+        //                     "qty": "0.1000",
+        //                     "stopLoss": "",
+        //                     "triggerBy": "UNKNOWN",
+        //                     "orderIM": "0.00000000"
+        //                 }
+        //             ]
+        //         },
+        //         "retExtInfo": null,
+        //         "time": 1665565614320
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        const orders = this.safeValue (result, 'list', []);
+        return this.parseOrders (orders, market, since, limit);
+    }
+
+    async fetchDerivativesOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' fetchDerivativesOpenOrders() requires a symbol argument for ' + symbol + ' markets');
         }
-        let type = undefined;
-        [ type, params ] = this.handleMarketTypeAndParams ('fetchOpenOrders', market, params);
+        await this.loadMarkets ();
+        const market = this.market (symbol);
         const request = {};
         let method = undefined;
-        if ((type === 'swap' || type === 'future') && !isUsdcSettled) {
-            if (symbol === undefined) {
-                throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument for ' + symbol + ' markets');
-            }
-            request['symbol'] = market['id'];
-            const type = this.safeStringLower (params, 'orderType');
-            const isStop = this.safeValue (params, 'stop', false);
-            const isConditional = isStop || (type === 'stop') || (type === 'conditional');
-            params = this.omit (params, [ 'stop', 'orderType' ]);
-            if (market['future']) {
-                method = isConditional ? 'privateGetFuturesPrivateStopOrder' : 'privateGetFuturesPrivateOrder';
-            } else if (market['linear']) {
-                method = isConditional ? 'privateGetPrivateLinearStopOrderSearch' : 'privateGetPrivateLinearOrderSearch';
-            } else {
-                // inverse swap
-                method = isConditional ? 'privateGetV2PrivateStopOrder' : 'privateGetV2PrivateOrder';
-            }
-        } else if (type === 'spot') {
-            method = 'privateGetSpotV1OpenOrders';
+        const type = this.safeStringLower (params, 'orderType');
+        const isStop = this.safeValue (params, 'stop', false);
+        const isConditional = isStop || (type === 'stop') || (type === 'conditional');
+        params = this.omit (params, [ 'stop', 'orderType' ]);
+        if (market['future']) {
+            method = isConditional ? 'privateGetFuturesPrivateStopOrder' : 'privateGetFuturesPrivateOrder';
+        } else if (market['linear']) {
+            method = isConditional ? 'privateGetPrivateLinearStopOrderSearch' : 'privateGetPrivateLinearOrderSearch';
         } else {
-            // usdc
-            method = 'privatePostOptionUsdcOpenapiPrivateV1QueryActiveOrders';
-            request['category'] = (type === 'swap') ? 'perpetual' : 'option';
+            // inverse swap
+            method = isConditional ? 'privateGetV2PrivateStopOrder' : 'privateGetV2PrivateOrder';
         }
+        request['symbol'] = market['id'];
         const orders = await this[method] (this.extend (request, params));
         let result = this.safeValue (orders, 'result', []);
-        if (!Array.isArray (result)) {
-            const dataList = this.safeValue (result, 'dataList');
-            if (dataList === undefined) {
-                return this.parseOrder (result, market);
-            }
-            result = dataList;
-        }
+        //
         // {
         //     "ret_code":0,
         //     "ret_msg":"",
@@ -3735,9 +5078,97 @@ module.exports = class bybit extends Exchange {
         //        }
         //     ]
         //  }
+        //
+        if (!Array.isArray (result)) {
+            const dataList = this.safeValue2 (result, 'dataList', 'list');
+            if (dataList === undefined) {
+                return this.parseOrder (result, market);
+            }
+            result = dataList;
+        }
         return this.parseOrders (result, market, since, limit);
     }
 
+    async fetchUSDCOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const request = {};
+        let market = undefined;
+        if (symbol !== undefined) {
+            market = this.market (symbol);
+            request['symbol'] = market['id'];
+        }
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('fetchUSDCOpenOrders', market, params);
+        request['category'] = (type === 'swap') ? 'perpetual' : 'option';
+        const response = await this.privatePostOptionUsdcOpenapiPrivateV1QueryActiveOrders (this.extend (request, params));
+        const result = this.safeValue (response, 'result', {});
+        const orders = this.safeValue (result, 'dataList', []);
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "resultTotalSize": 1,
+        //             "cursor": "id%3D1662019818569%23df31e03b-fc00-4b4c-bd1c-b97fd72b5c5c",
+        //             "dataList": [
+        //                 {
+        //                     "orderId": "df31e03b-fc00-4b4c-bd1c-b97fd72b5c5c",
+        //                     "orderLinkId": "",
+        //                     "symbol": "BTC-2SEP22-18000-C",
+        //                     "orderStatus": "New",
+        //                     "orderPrice": "500",
+        //                     "side": "Buy",
+        //                     "remainingQty": "0.1",
+        //                     "orderType": "Limit",
+        //                     "qty": "0.1",
+        //                     "iv": "0.0000",
+        //                     "cancelType": "",
+        //                     "updateTimestamp": "1662019818579"
+        //                 }
+        //             ]
+        //         }
+        //     }
+        //
+        return this.parseOrders (orders, market, since, limit);
+    }
+
+    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchOpenOrders
+         * @description fetch all unfilled currently open orders
+         * @param {string|undefined} symbol unified market symbol
+         * @param {int|undefined} since the earliest time in ms to fetch open orders for
+         * @param {int|undefined} limit the maximum number of  open orders structures to retrieve
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
+         */
+        await this.loadMarkets ();
+        let market = undefined;
+        let isUsdcSettled = undefined;
+        if (symbol !== undefined) {
+            market = this.market (symbol);
+            isUsdcSettled = market['settle'] === 'USDC';
+        } else {
+            let settle = this.safeString (this.options, 'defaultSettle');
+            settle = this.safeString2 (params, 'settle', 'defaultSettle', settle);
+            params = this.omit (params, [ 'settle', 'defaultSettle' ]);
+            isUsdcSettled = settle === 'USDC';
+        }
+        let type = undefined;
+        [ type, params ] = this.handleMarketTypeAndParams ('fetchOpenOrders', market, params);
+        if (type === 'spot') {
+            return await this.fetchSpotOpenOrders (symbol, since, limit, params);
+        }
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            return await this.fetchUnifiedMarginOpenOrders (symbol, since, limit, params);
+        } else if ((type === 'swap' || type === 'future') && !isUsdcSettled) {
+            return await this.fetchDerivativesOpenOrders (symbol, since, limit, params);
+        }
+        return await this.fetchUSDCOpenOrders (symbol, since, limit, params);
+    }
+
     async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
         /**
          * @method
@@ -4434,51 +5865,269 @@ module.exports = class bybit extends Exchange {
         return this.parseTransaction (result, currency);
     }
 
-    async fetchPositions (symbols = undefined, params = {}) {
+    async fetchPosition (symbol = undefined, params = {}) {
         /**
          * @method
-         * @name bybit#fetchPositions
-         * @description fetch all open positions
-         * @param {[string]|undefined} symbols list of unified market symbols
+         * @name bybit#fetchPosition
+         * @description fetch data on a single open contract trade position
+         * @param {string} symbol unified market symbol of the market the position is held in, default is undefined
          * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
+         * @returns {object} a [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
          */
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' fetchPosition() requires a symbol argument');
+        }
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (!enableUnifiedMargin) {
+            throw new NotSupported (this.id + ' fetchPosition() only support unified margin account');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        } else {
+            throw new NotSupported (this.id + ' fetchPosition() does not allow inverse market orders for ' + symbol + ' markets');
+        }
+        const response = await this.privateGetUnifiedV3PrivatePositionList (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "Success",
+        //         "result": {
+        //             "nextPageCursor": "0%3A1657711949945%2C0%3A1657711949945",
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "symbol": "ETHUSDT",
+        //                     "leverage": "10",
+        //                     "updatedTime": 1657711949945,
+        //                     "side": "Buy",
+        //                     "positionValue": "536.92500000",
+        //                     "takeProfit": "",
+        //                     "tpslMode": "Full",
+        //                     "riskId": 11,
+        //                     "trailingStop": "",
+        //                     "entryPrice": "1073.85000000",
+        //                     "unrealisedPnl": "",
+        //                     "markPrice": "1080.65000000",
+        //                     "size": "0.5000",
+        //                     "positionStatus": "normal",
+        //                     "stopLoss": "",
+        //                     "cumRealisedPnl": "-0.32215500",
+        //                     "positionMM": "2.97456450",
+        //                     "createdTime": 1657711949928,
+        //                     "positionIdx": 0,
+        //                     "positionIM": "53.98243950"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657713693182
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        const positions = this.safeValue (result, 'list', []);
+        const timestamp = this.safeInteger (response, 'time');
+        const first = this.safeValue (positions, 0);
+        const position = this.parsePosition (first);
+        return this.extend (position, {
+            'timestamp': timestamp,
+            'datetime': this.iso8601 (timestamp),
+        });
+    }
+
+    async fetchUnifiedMarginPositions (symbols = undefined, params = {}) {
         await this.loadMarkets ();
         symbols = this.marketSymbols (symbols);
         const request = {};
         let market = undefined;
         let type = undefined;
         let isLinear = undefined;
-        let isUsdcSettled = undefined;
         if (Array.isArray (symbols)) {
             const length = symbols.length;
             if (length !== 1) {
-                throw new ArgumentsRequired (this.id + ' fetchPositions() takes an array with exactly one symbol');
+                throw new ArgumentsRequired (this.id + ' fetchUnifiedMarginPositions() takes an array with exactly one symbol');
             }
             const symbol = this.safeString (symbols, 0);
             market = this.market (symbol);
             type = market['type'];
             isLinear = market['linear'];
-            isUsdcSettled = market['settle'] === 'USDC';
             request['symbol'] = market['id'];
         } else {
             // market undefined
-            [ type, params ] = this.handleMarketTypeAndParams ('fetchPositions', undefined, params);
-            const options = this.safeValue (this.options, 'fetchPositions', {});
+            [ type, params ] = this.handleMarketTypeAndParams ('fetchUnifiedMarginPositions', undefined, params);
+            const options = this.safeValue (this.options, 'fetchUnifiedMarginPositions', {});
+            const defaultSubType = this.safeString (this.options, 'defaultSubType', 'linear');
+            let subType = this.safeString (options, 'subType', defaultSubType);
+            subType = this.safeString (params, 'subType', subType);
+            isLinear = (subType === 'linear');
+        }
+        params = this.omit (params, [ 'subType' ]);
+        if (type === 'option') {
+            request['category'] = 'option';
+        } else if (isLinear) {
+            request['category'] = 'linear';
+        } else {
+            throw new NotSupported (this.id + ' fetchUnifiedMarginPositions() does not allow inverse market');
+        }
+        const response = await this.privateGetUnifiedV3PrivatePositionList (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "Success",
+        //         "result": {
+        //             "nextPageCursor": "0%3A1657711949945%2C0%3A1657711949945",
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "symbol": "ETHUSDT",
+        //                     "leverage": "10",
+        //                     "updatedTime": 1657711949945,
+        //                     "side": "Buy",
+        //                     "positionValue": "536.92500000",
+        //                     "takeProfit": "",
+        //                     "tpslMode": "Full",
+        //                     "riskId": 11,
+        //                     "trailingStop": "",
+        //                     "entryPrice": "1073.85000000",
+        //                     "unrealisedPnl": "",
+        //                     "markPrice": "1080.65000000",
+        //                     "size": "0.5000",
+        //                     "positionStatus": "normal",
+        //                     "stopLoss": "",
+        //                     "cumRealisedPnl": "-0.32215500",
+        //                     "positionMM": "2.97456450",
+        //                     "createdTime": 1657711949928,
+        //                     "positionIdx": 0,
+        //                     "positionIM": "53.98243950"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657713693182
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        const positions = this.safeValue (result, 'list', []);
+        const results = [];
+        for (let i = 0; i < positions.length; i++) {
+            let rawPosition = positions[i];
+            if (('data' in rawPosition) && ('is_valid' in rawPosition)) {
+                // futures only
+                rawPosition = this.safeValue (rawPosition, 'data');
+            }
+            results.push (this.parsePosition (rawPosition, market));
+        }
+        return this.filterByArray (results, 'symbol', symbols, false);
+    }
+
+    async fetchUSDCPositions (symbols = undefined, params = {}) {
+        await this.loadMarkets ();
+        symbols = this.marketSymbols (symbols);
+        const request = {};
+        let market = undefined;
+        let type = undefined;
+        if (Array.isArray (symbols)) {
+            const length = symbols.length;
+            if (length !== 1) {
+                throw new ArgumentsRequired (this.id + ' fetchUSDCPositions() takes an array with exactly one symbol');
+            }
+            const symbol = this.safeString (symbols, 0);
+            market = this.market (symbol);
+            type = market['type'];
+            request['symbol'] = market['id'];
+        } else {
+            [ type, params ] = this.handleMarketTypeAndParams ('fetchUSDCPositions', undefined, params);
+        }
+        request['category'] = (type === 'option') ? 'OPTION' : 'PERPETUAL';
+        const response = await this.privatePostOptionUsdcOpenapiPrivateV1QueryPosition (this.extend (request, params));
+        //
+        //     {
+        //         "result": {
+        //             "cursor": "BTC-31DEC21-24000-P%3A1640834421431%2CBTC-31DEC21-24000-P%3A1640834421431",
+        //             "resultTotalSize": 1,
+        //             "dataList": [
+        //                 {
+        //                 "symbol": "BTC-31DEC21-24000-P",
+        //                 "leverage": "",
+        //                 "occClosingFee": "",
+        //                 "liqPrice": "",
+        //                 "positionValue": "",
+        //                 "takeProfit": "",
+        //                 "riskId": "",
+        //                 "trailingStop": "",
+        //                 "unrealisedPnl": "",
+        //                 "createdAt": "1640834421431",
+        //                 "markPrice": "0.00",
+        //                 "cumRealisedPnl": "",
+        //                 "positionMM": "359.5271",
+        //                 "positionIM": "467.0633",
+        //                 "updatedAt": "1640834421431",
+        //                 "tpSLMode": "",
+        //                 "side": "Sell",
+        //                 "bustPrice": "",
+        //                 "deleverageIndicator": 0,
+        //                 "entryPrice": "1.4",
+        //                 "size": "-0.100",
+        //                 "sessionRPL": "",
+        //                 "positionStatus": "",
+        //                 "sessionUPL": "",
+        //                 "stopLoss": "",
+        //                 "orderMargin": "",
+        //                 "sessionAvgPrice": "1.5"
+        //                 }
+        //             ]
+        //         },
+        //         "retCode": 0,
+        //         "retMsg": "Success."
+        //     }
+        //
+        const result = this.safeValue (response, 'result', {});
+        const positions = this.safeValue (result, 'dataList', []);
+        const results = [];
+        for (let i = 0; i < positions.length; i++) {
+            let rawPosition = positions[i];
+            if (('data' in rawPosition) && ('is_valid' in rawPosition)) {
+                // futures only
+                rawPosition = this.safeValue (rawPosition, 'data');
+            }
+            results.push (this.parsePosition (rawPosition, market));
+        }
+        return this.filterByArray (results, 'symbol', symbols, false);
+    }
+
+    async fetchDerivativesPositions (symbols = undefined, params = {}) {
+        await this.loadMarkets ();
+        symbols = this.marketSymbols (symbols);
+        const request = {};
+        let market = undefined;
+        let type = undefined;
+        let isLinear = undefined;
+        if (Array.isArray (symbols)) {
+            const length = symbols.length;
+            if (length !== 1) {
+                throw new ArgumentsRequired (this.id + ' fetchDerivativesPositions() takes an array with exactly one symbol');
+            }
+            const symbol = this.safeString (symbols, 0);
+            market = this.market (symbol);
+            type = market['type'];
+            isLinear = market['linear'];
+            request['symbol'] = market['id'];
+        } else {
+            // market undefined
+            [ type, params ] = this.handleMarketTypeAndParams ('fetchDerivativesPositions', undefined, params);
+            const options = this.safeValue (this.options, 'fetchDerivativesPositions', {});
             const defaultSubType = this.safeString (this.options, 'defaultSubType', 'linear');
             let subType = this.safeString (options, 'subType', defaultSubType);
             subType = this.safeString (params, 'subType', subType);
             isLinear = (subType === 'linear');
-            let defaultSettle = this.safeString (this.options, 'defaultSettle');
-            defaultSettle = this.safeString2 (params, 'settle', 'defaultSettle', defaultSettle);
-            isUsdcSettled = (defaultSettle === 'USDC');
         }
-        params = this.omit (params, [ 'settle', 'defaultSettle', 'subType' ]);
+        params = this.omit (params, [ 'subType' ]);
         let method = undefined;
-        if (isUsdcSettled) {
-            method = 'privatePostOptionUsdcOpenapiPrivateV1QueryPosition';
-            request['category'] = (type === 'option') ? 'OPTION' : 'PERPETUAL';
-        } else if (type === 'future') {
+        if (type === 'future') {
             method = 'privateGetFuturesPrivatePositionList';
         } else if (isLinear) {
             method = 'privateGetPrivateLinearPositionList';
@@ -4503,23 +6152,64 @@ module.exports = class bybit extends Exchange {
         // usdc contracts
         if ('dataList' in result) {
             result = this.safeValue (result, 'dataList', []);
+        } else if ('list' in result) {
+            result = this.safeValue (result, 'list', []);
         }
         let positions = undefined;
         if (!Array.isArray (result)) {
             positions = [ result ];
         } else {
-            positions = result;
+            positions = result;
+        }
+        const results = [];
+        for (let i = 0; i < positions.length; i++) {
+            let rawPosition = positions[i];
+            if (('data' in rawPosition) && ('is_valid' in rawPosition)) {
+                // futures only
+                rawPosition = this.safeValue (rawPosition, 'data');
+            }
+            results.push (this.parsePosition (rawPosition, market));
+        }
+        return this.filterByArray (results, 'symbol', symbols, false);
+    }
+
+    async fetchPositions (symbols = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchPositions
+         * @description fetch all open positions
+         * @param {[string]|undefined} symbols list of unified market symbols
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
+         */
+        await this.loadMarkets ();
+        symbols = this.marketSymbols (symbols);
+        const request = {};
+        let market = undefined;
+        let isUsdcSettled = undefined;
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (Array.isArray (symbols)) {
+            const length = symbols.length;
+            if (length !== 1) {
+                throw new ArgumentsRequired (this.id + ' fetchPositions() takes an array with exactly one symbol');
+            }
+            const symbol = this.safeString (symbols, 0);
+            market = this.market (symbol);
+            isUsdcSettled = market['settle'] === 'USDC';
+            request['symbol'] = market['id'];
+        } else {
+            // market undefined
+            let defaultSettle = this.safeString (this.options, 'defaultSettle');
+            defaultSettle = this.safeString2 (params, 'settle', 'defaultSettle', defaultSettle);
+            isUsdcSettled = (defaultSettle === 'USDC');
         }
-        const results = [];
-        for (let i = 0; i < positions.length; i++) {
-            let rawPosition = positions[i];
-            if (('data' in rawPosition) && ('is_valid' in rawPosition)) {
-                // futures only
-                rawPosition = this.safeValue (rawPosition, 'data');
-            }
-            results.push (this.parsePosition (rawPosition, market));
+        params = this.omit (params, [ 'settle', 'defaultSettle' ]);
+        if (enableUnifiedMargin) {
+            return await this.fetchUnifiedMarginPositions (symbols, params);
+        } else if (isUsdcSettled) {
+            return await this.fetchUSDCPositions (symbols, params);
         }
-        return this.filterByArray (results, 'symbol', symbols, false);
+        return await this.fetchDerivativesPositions (symbols, params);
     }
 
     parsePosition (position, market = undefined) {
@@ -4750,6 +6440,87 @@ module.exports = class bybit extends Exchange {
         return response;
     }
 
+    async setUnifiedMarginLeverage (leverage, symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' setUnifiedMarginLeverage() requires a symbol argument');
+        }
+        if ((leverage < 1) || (leverage > 100)) {
+            throw new BadRequest (this.id + ' setUnifiedMarginLeverage() leverage should be between 1 and 100');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (market['option']) {
+            request['category'] = 'option';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
+        } else {
+            throw new NotSupported (this.id + ' setUnifiedMarginLeverage() leverage didn\'t support inverse market in unified margin');
+        }
+        leverage = leverage.toString ();
+        const buyLeverage = this.safeNumber2 (params, 'buy_leverage', 'buyLeverage');
+        const sellLeverage = this.safeNumber2 (params, 'sell_leverage', 'sellLeverage');
+        if (buyLeverage === undefined || sellLeverage === undefined) {
+            request['buyLeverage'] = leverage;
+            request['sellLeverage'] = leverage;
+        }
+        return await this.privatePostUnifiedV3PrivatePositionSetLeverage (this.extend (request, params));
+    }
+
+    async setUSDCLeverage (leverage, symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' setUSDCLeverage() requires a symbol argument');
+        }
+        if ((leverage < 1) || (leverage > 100)) {
+            throw new BadRequest (this.id + ' setUSDCLeverage() leverage should be between 1 and 100');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        leverage = leverage.toString ();
+        request['leverage'] = leverage;
+        return await this.privatePostPerpetualUsdcOpenapiPrivateV1PositionLeverageSave (this.extend (request, params));
+    }
+
+    async setDerivativesLeverage (leverage, symbol = undefined, params = {}) {
+        if (symbol === undefined) {
+            throw new ArgumentsRequired (this.id + ' setDerivativesLeverage() requires a symbol argument');
+        }
+        if ((leverage < 1) || (leverage > 100)) {
+            throw new BadRequest (this.id + ' setDerivativesLeverage() leverage should be between 1 and 100');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        let method = undefined;
+        const request = {
+            'symbol': market['id'],
+        };
+        if (market['future']) {
+            method = 'privatePostFuturesPrivatePositionLeverageSave';
+        } else if (market['linear']) {
+            method = 'privatePostPrivateLinearPositionSetLeverage';
+        } else {
+            // inverse swaps
+            method = 'privatePostV2PrivatePositionLeverageSave';
+        }
+        leverage = parseInt (leverage);
+        const buyLeverage = this.safeNumber2 (params, 'buy_leverage', 'buyLeverage');
+        const sellLeverage = this.safeNumber2 (params, 'sell_leverage', 'sellLeverage');
+        if (buyLeverage !== undefined && sellLeverage !== undefined) {
+            if ((buyLeverage < 1) || (buyLeverage > 100) || (sellLeverage < 1) || (sellLeverage > 100)) {
+                throw new BadRequest (this.id + ' setDerivativesLeverage() leverage should be between 1 and 100');
+            }
+        } else {
+            request['buy_leverage'] = leverage;
+            request['sell_leverage'] = leverage;
+        }
+        return await this[method] (this.extend (request, params));
+    }
+
     async setLeverage (leverage, symbol = undefined, params = {}) {
         /**
          * @method
@@ -4768,42 +6539,14 @@ module.exports = class bybit extends Exchange {
         // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
         // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
         const isUsdcSettled = market['settle'] === 'USDC';
-        let method = undefined;
-        if (isUsdcSettled) {
-            method = 'privatePostPerpetualUsdcOpenapiPrivateV1PositionLeverageSave';
-        } else if (market['future']) {
-            method = 'privatePostFuturesPrivatePositionLeverageSave';
-        } else if (market['linear']) {
-            method = 'privatePostPrivateLinearPositionSetLeverage';
-        } else {
-            // inverse swaps
-            method = 'privatePostV2PrivatePositionLeverageSave';
-        }
-        const request = {
-            'symbol': market['id'],
-        };
-        leverage = isUsdcSettled ? leverage.toString () : parseInt (leverage);
-        const isLinearSwap = market['swap'] && market['linear'];
-        const requiresBuyAndSellLeverage = !isUsdcSettled && (isLinearSwap || market['future']);
-        if (requiresBuyAndSellLeverage) {
-            const buyLeverage = this.safeNumber (params, 'buy_leverage');
-            const sellLeverage = this.safeNumber (params, 'sell_leverage');
-            if (buyLeverage !== undefined && sellLeverage !== undefined) {
-                if ((buyLeverage < 1) || (buyLeverage > 100) || (sellLeverage < 1) || (sellLeverage > 100)) {
-                    throw new BadRequest (this.id + ' setLeverage() leverage should be between 1 and 100');
-                }
-            } else {
-                request['buy_leverage'] = leverage;
-                request['sell_leverage'] = leverage;
-            }
-        } else {
-            // requires leverage
-            request['leverage'] = leverage;
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            return await this.setUnifiedMarginLeverage (leverage, symbol, params);
         }
-        if ((leverage < 1) || (leverage > 100)) {
-            throw new BadRequest (this.id + ' setLeverage() leverage should be between 1 and 100');
+        if (isUsdcSettled) {
+            return await this.setUSDCLeverage (leverage, symbol, params);
         }
-        return await this[method] (this.extend (request, params));
+        return await this.setDerivativesLeverage (leverage, symbol, params);
     }
 
     async setPositionMode (hedged, symbol = undefined, params = {}) {
@@ -4857,23 +6600,49 @@ module.exports = class bybit extends Exchange {
         return response;
     }
 
-    async fetchOpenInterestHistory (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchOpenInterestHistory
-         * @description Gets the total amount of unsettled contracts. The total number of contracts held in open positions
-         * @see https://bybit-exchange.github.io/docs/derivativesV3/contract/#t-dv_marketopeninterest
-         * @param {string} symbol Unified market symbol
-         * @param {string} timeframe "5m", 15m, 30m, 1h, 4h, 1d
-         * @param {int|undefined} since Start timestamp in milliseconds
-         * @param {int|undefined} limit The number of open interest structures to return. Max 200, default 50
-         * @param {object} params Exchange specific parameters
-         * @param {string|undefined} params.category "linear" or "inverse"
-         * @returns An array of open interest structures
-         */
-        if (timeframe === '1m') {
-            throw new BadRequest (this.id + ' fetchOpenInterestHistory() cannot use the 1m timeframe');
+    async fetchUnifiedMarginOpenInterestHistory (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        request['interval'] = timeframe;
+        if (market['inverse']) {
+            request['category'] = 'inverse';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
         }
+        const response = await this.publicGetDerivativesV3PublicOpenInterest (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "symbol": "BTCUSDT",
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "openInterest": "15350.60700000",
+        //                     "timestamp": "1657641600000"
+        //                 },
+        //                 {
+        //                     "openInterest": "15605.74100000",
+        //                     "timestamp": "1657638000000"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657797822839
+        //     }
+        //
+        const result = this.safeValue (response, 'result');
+        const openInterests = this.safeValue (result, 'list');
+        return this.parseOpenInterests (openInterests, market, since, limit);
+    }
+
+    async fetchDerivativesOpenInterestHistory (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
         await this.loadMarkets ();
         let market = this.market (symbol);
         const subType = market['linear'] ? 'linear' : 'inverse';
@@ -4971,6 +6740,39 @@ module.exports = class bybit extends Exchange {
         return this.parseOpenInterest (data[0], market);
     }
 
+    async fetchOpenInterestHistory (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchOpenInterestHistory
+         * @description Gets the total amount of unsettled contracts. In other words, the total number of contracts held in open positions
+         * @param {string} symbol Unified market symbol
+         * @param {string} timeframe "5m", 15m, 30m, 1h, 4h, 1d
+         * @param {int} since Not used by Bybit
+         * @param {int} limit The number of open interest structures to return. Max 200, default 50
+         * @param {object} params Exchange specific parameters
+         * @returns An array of open interest structures
+         */
+        if (timeframe === '1m') {
+            throw new BadRequest (this.id + 'fetchOpenInterestHistory cannot use the 1m timeframe');
+        }
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        if (market['spot'] || market['option']) {
+            throw new BadRequest (this.id + ' fetchOpenInterestHistory() symbol does not support market ' + symbol);
+        }
+        const request = {
+            'symbol': market['id'],
+        };
+        if (limit !== undefined) {
+            request['limit'] = limit;
+        }
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            return await this.fetchUnifiedMarginOpenInterestHistory (symbol, timeframe, since, limit, params);
+        }
+        return await this.fetchDerivativesOpenInterestHistory (symbol, timeframe, since, limit, params);
+    }
+
     parseOpenInterest (interest, market = undefined) {
         //
         //    {
@@ -4979,7 +6781,7 @@ module.exports = class bybit extends Exchange {
         //    }
         //
         const timestamp = this.safeInteger (interest, 'timestamp');
-        const value = this.safeNumber (interest, 'openInterest');
+        const value = this.safeNumber2 (interest, 'open_interest', 'openInterest');
         return {
             'symbol': this.safeSymbol (market['id']),
             'baseVolume': value,  // deprecated
@@ -5426,7 +7228,11 @@ module.exports = class bybit extends Exchange {
                     }
                 } else {
                     authFull = auth_base + queryEncoded;
-                    url += '?' + this.urlencode (query);
+                    if (path === 'unified/v3/private/order/list') {
+                        url += '?' + this.rawencode (query);
+                    } else {
+                        url += '?' + this.urlencode (query);
+                    }
                 }
                 const signature = this.hmac (this.encode (authFull), this.encode (this.secret));
                 headers['X-BAPI-SIGN'] = signature;
@@ -5506,28 +7312,99 @@ module.exports = class bybit extends Exchange {
         }
     }
 
-    async fetchMarketLeverageTiers (symbol, params = {}) {
-        /**
-         * @method
-         * @name bybit#fetchMarketLeverageTiers
-         * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes for a single market
-         * @param {string} symbol unified market symbol
-         * @param {object} params extra parameters specific to the bybit api endpoint
-         * @returns {object} a [leverage tiers structure]{@link https://docs.ccxt.com/en/latest/manual.html#leverage-tiers-structure}
-         */
+    async fetchUnifiedMarginMarketLeverageTiers (symbol, params = {}) {
         await this.loadMarkets ();
-        const request = {};
-        let market = undefined;
-        market = this.market (symbol);
-        if (market['spot'] || market['option']) {
-            throw new BadRequest (this.id + ' fetchMarketLeverageTiers() symbol does not support market ' + symbol);
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        if (market['inverse']) {
+            request['category'] = 'inverse';
+        } else if (market['linear']) {
+            request['category'] = 'linear';
         }
-        request['symbol'] = market['id'];
-        const isUsdcSettled = market['settle'] === 'USDC';
+        const response = await this.publicGetDerivativesV3PublicRiskLimitList (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "OK",
+        //         "result": {
+        //             "category": "linear",
+        //             "list": [
+        //                 {
+        //                     "id": 1,
+        //                     "symbol": "BTCUSDT",
+        //                     "limit": "2000000",
+        //                     "maintainMargin": "0.005",
+        //                     "initialMargin": "0.01",
+        //                     "section": [
+        //                         "1",
+        //                         "3",
+        //                         "5",
+        //                         "10",
+        //                         "25",
+        //                         "50",
+        //                         "80"
+        //                     ],
+        //                     "isLowestRisk": 1,
+        //                     "maxLeverage": "100.00"
+        //                 }
+        //             ]
+        //         },
+        //         "time": 1657797260220
+        //     }
+        //
+        const result = this.safeValue (response, 'result');
+        const tiers = this.safeValue (result, 'list');
+        return this.parseMarketLeverageTiers (tiers, market);
+    }
+
+    async fetchUSDCMarketLeverageTiers (symbol, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
+        const response = await this.publicGetPerpetualUsdcOpenapiPublicV1RiskLimitList (this.extend (request, params));
+        //
+        //     {
+        //         "retCode": 0,
+        //         "retMsg": "",
+        //         "result": [
+        //             {
+        //                 "riskId": "10001",
+        //                 "symbol": "BTCPERP",
+        //                 "limit": "1000000",
+        //                 "startingMargin": "0.0100",
+        //                 "maintainMargin": "0.0050",
+        //                 "isLowestRisk": true,
+        //                 "section": [
+        //                     "1",
+        //                     "2",
+        //                     "3",
+        //                     "5",
+        //                     "10",
+        //                     "25",
+        //                     "50",
+        //                     "100"
+        //                 ],
+        //                 "maxLeverage": "100.00"
+        //             }
+        //         ]
+        //     }
+        //
+        const result = this.safeValue (response, 'result');
+        return this.parseMarketLeverageTiers (result, market);
+    }
+
+    async fetchDerivativesMarketLeverageTiers (symbol, params = {}) {
+        await this.loadMarkets ();
+        const market = this.market (symbol);
+        const request = {
+            'symbol': market['id'],
+        };
         let method = undefined;
-        if (isUsdcSettled) {
-            method = 'publicGetPerpetualUsdcOpenapiPublicV1RiskLimitList';
-        } else if (market['linear']) {
+        if (market['linear']) {
             method = 'publicGetPublicLinearRiskLimit';
         } else {
             method = 'publicGetV2PublicRiskLimitList';
@@ -5593,6 +7470,34 @@ module.exports = class bybit extends Exchange {
         return this.parseMarketLeverageTiers (result, market);
     }
 
+    async fetchMarketLeverageTiers (symbol, params = {}) {
+        /**
+         * @method
+         * @name bybit#fetchMarketLeverageTiers
+         * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes for a single market
+         * @param {string} symbol unified market symbol
+         * @param {object} params extra parameters specific to the bybit api endpoint
+         * @returns {object} a [leverage tiers structure]{@link https://docs.ccxt.com/en/latest/manual.html#leverage-tiers-structure}
+         */
+        await this.loadMarkets ();
+        const request = {};
+        let market = undefined;
+        market = this.market (symbol);
+        if (market['spot'] || market['option']) {
+            throw new BadRequest (this.id + ' fetchMarketLeverageTiers() symbol does not support market ' + symbol);
+        }
+        request['symbol'] = market['id'];
+        const isUsdcSettled = market['settle'] === 'USDC';
+        const enableUnifiedMargin = this.safeValue (this.options, 'enableUnifiedMargin');
+        if (enableUnifiedMargin) {
+            return await this.fetchUnifiedMarginMarketLeverageTiers (symbol, params);
+        }
+        if (isUsdcSettled) {
+            return await this.fetchUSDCMarketLeverageTiers (symbol, params);
+        }
+        return await this.fetchDerivativesMarketLeverageTiers (symbol, params);
+    }
+
     parseMarketLeverageTiers (info, market) {
         //
         //    Linear
@@ -5660,6 +7565,29 @@ module.exports = class bybit extends Exchange {
         //        "maxLeverage":"100.00"
         //    }
         //
+        // Unified Margin
+        //
+        //     [
+        //         {
+        //             "id": 1,
+        //             "symbol": "BTCUSDT",
+        //             "limit": "2000000",
+        //             "maintainMargin": "0.005",
+        //             "initialMargin": "0.01",
+        //             "section": [
+        //                 "1",
+        //                 "3",
+        //                 "5",
+        //                 "10",
+        //                 "25",
+        //                 "50",
+        //                 "80"
+        //             ],
+        //             "isLowestRisk": 1,
+        //             "maxLeverage": "100.00"
+        //         }
+        //     ]
+        //
         let minNotional = 0;
         const tiers = [];
         for (let i = 0; i < info.length; i++) {


Code review comments:
diff_hunk: @@ -1627,74 +1804,147 @@ module.exports = class bybit extends Exchange {
         if (limit !== undefined) {
             request['limit'] = limit; // max 200, default 200
         }
-        let method = undefined;
-        let intervalKey = 'interval';
-        let sinceKey = 'from';
-        const isUsdcSettled = market['settle'] === 'USDC';
-        if (market['spot']) {
-            method = 'publicGetSpotQuoteV1Kline';
-        } else if (market['contract'] && !isUsdcSettled) {
-            if (market['linear']) {
-                // linear swaps/futures
-                const methods = {
-                    'mark': 'publicGetPublicLinearMarkPriceKline',
-                    'index': 'publicGetPublicLinearIndexPriceKline',
-                    'premiumIndex': 'publicGetPublicLinearPremiumIndexKline',
-                };
-                method = this.safeValue (methods, price, 'publicGetPublicLinearKline');
-            } else {
-                // inverse swaps/ futures
-                const methods = {
-                    'mark': 'publicGetV2PublicMarkPriceKline',
-                    'index': 'publicGetV2PublicIndexPriceKline',
-                    'premiumIndex': 'publicGetV2PublicPremiumPriceKline',
-                };
-                method = this.safeValue (methods, price, 'publicGetV2PublicKlineList');
-            }
+        request['interval'] = timeframe;
+        request['from'] = sinceTimestamp;
+        const response = await this.publicGetSpotQuoteV1Kline (params);
+        //
+        //     {
+        //         "ret_code": "0",
+        //         "ret_msg": null,
+        //         "result": [
+        //             [
+        //                 1651837620000,
+        //                 "35831.5",
+        //                 "35831.5",
+        //                 "35801.93",
+        //                 "35817.11",
+        //                 "1.23453",
+        //                 0,
+        //                 "44213.97591627",
+        //                 24,
+        //                 "0",
+        //                 "0"
+        //             ]
+        //         ],
+        //         "ext_code": null,
+        //         "ext_info": null
+        //     }
+        //
+        const ohlcvs = this.safeValue (response, 'result');
+        return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+    }
+
+    async fetchUnifiedMarginOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
path: js/bybit.js
text: @user1:
@author we don't need UnifiedMargin methods for public data they're the same