Repository: ccxt/ccxt
Pull request: bybit createSpotOrder & parseLedgerEntry string math
```
% bybit createSpotOrder ADA/USDT market buy 8 0.45
2022-09-08T23:58:43.169Z
Node.js: v18.4.0
CCXT v1.93.14
(node:15269) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
bybit.createSpotOrder (ADA/USDT, market, buy, 8, 0.45)
2022-09-08T23:58:44.802Z iteration 0 passed in 294 ms

{
  info: {
    orderId: '1241057012215838464',
    orderLinkId: '1662681524707725',
    symbol: 'ADAUSDT',
    transactTime: '1662681524718',
    price: '0',
    origQty: '3.6',
    type: 'MARKET',
    side: 'BUY',
    status: 'NEW',
    timeInForce: 'GTC',
    accountId: '8929030',
    symbolName: 'ADAUSDT',
    executedQty: '0'
  },
  id: '1241057012215838464',
  clientOrderId: '1662681524707725',
  timestamp: 1662681524718,
  datetime: '2022-09-08T23:58:44.718Z',
  lastTradeTimestamp: undefined,
  symbol: 'ADA/USDT',
  type: 'market',
  timeInForce: 'GTC',
  postOnly: false,
  side: 'buy',
  price: undefined,
  stopPrice: undefined,
  amount: 3.6,
  cost: undefined,
  average: undefined,
  filled: 0,
  remaining: 3.6,
  status: 'open',
  fee: undefined,
  trades: [],
  fees: []
}
2022-09-08T23:58:44.802Z iteration 1 passed in 294 ms
```

```
% bybit fetchLedger USDT | condense
(node:15733) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
2022-09-09T00:05:43.529Z
Node.js: v18.4.0
CCXT v1.93.14
bybit.fetchLedger (USDT)
2022-09-09T00:05:46.291Z iteration 0 passed in 362 ms
      id | currency | account | referenceAccount | referenceId | status |       amount |       before |       after | fee | direction |     timestamp |                 datetime |  type
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12338986 |     USDT |  867756 |                  |             |        |   -0.0029844 |  14.98424782 | 14.98723222 |     |       out | 1659484800000 | 2022-08-03T00:00:00.000Z | trade
...
12599725 |     USDT |  867756 |                  |             |        | -13.03193144 | -12.85742797 |  0.17450347 |     |       out | 1662681600000 | 2022-09-09T00:00:00.000Z | trade
20 objects
2022-09-09T00:05:46.291Z iteration 1 passed in 362 ms
```

Problem statement:
Bybit: Incorrect cost calculation. How to calculate cost properly
- OS: MacOS Monterey 12.6
- Programming Language version: node js 16
- CCXT version: 1.93.105

I'm always getting 0.1% slippage when making market BUY order (I request order within 5ms after getting quote). It's incorrect. I want to buy EXACT amount of crypto with MARKET order. I tried just `price * amount` formula as `cost` and round it to either 6 or 8 decimals. (incorrect precision?)
But slippage is really big. On other exchanges, I don't have this issue. 
I want to buy 0.001 BTC but I always get 0.000999 BTC.
I saw you were getting this issue with Huobi and you fixed it and changed precision of cost to base currency. Is this needed?

I am OK if it is everywhere but this is happening only on ByBit exchange.

Please suggest something.

I am using createOrder function of spot market.

Hints from issue discussion:

Commit message: bybit createSpotOrder & parseLedgerEntry string math

Patch to review:
diff --git a/js/bybit.js b/js/bybit.js
index 3ca2e14189210..25c286836d16d 100644
--- a/js/bybit.js
+++ b/js/bybit.js
@@ -2729,7 +2729,10 @@ module.exports = class bybit extends Exchange {
                 if (price === undefined && cost === undefined) {
                     throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false to supply the cost in the amount argument (the exchange-specific behaviour)");
                 } else {
-                    amount = (cost !== undefined) ? cost : amount * price;
+                    const amountString = this.numberToString (amount);
+                    const priceString = this.numberToString (price);
+                    const quoteAmount = Precise.stringMul (amountString, priceString);
+                    amount = (cost !== undefined) ? cost : this.parseNumber (quoteAmount);
                 }
             }
         }
@@ -2762,27 +2765,29 @@ module.exports = class bybit extends Exchange {
             request['agentSource'] = brokerId;
         }
         const response = await this.privatePostSpotV1Order (this.extend (request, params));
+        //
         //    {
-        //        "ret_code":0,
-        //        "ret_msg":"",
-        //        "ext_code":null,
-        //        "ext_info":null,
-        //        "result":{
-        //           "accountId":"24478790",
-        //           "symbol":"ETHUSDT",
-        //           "symbolName":"ETHUSDT",
-        //           "orderLinkId":"1652266305358517",
-        //           "orderId":"1153687819821127168",
-        //           "transactTime":"1652266305365",
-        //           "price":"80",
-        //           "origQty":"0.05",
-        //           "executedQty":"0",
-        //           "status":"NEW",
-        //           "timeInForce":"GTC",
-        //           "type":"LIMIT",
-        //           "side":"BUY"
+        //        "ret_code": 0,
+        //        "ret_msg": "",
+        //        "ext_code": null,
+        //        "ext_info": null,
+        //        "result": {
+        //           "accountId": "24478790",
+        //           "symbol": "ETHUSDT",
+        //           "symbolName": "ETHUSDT",
+        //           "orderLinkId": "1652266305358517",
+        //           "orderId": "1153687819821127168",
+        //           "transactTime": "1652266305365",
+        //           "price": "80",
+        //           "origQty": "0.05",
+        //           "executedQty": "0",
+        //           "status": "NEW",
+        //           "timeInForce": "GTC",
+        //           "type": "LIMIT",
+        //           "side": "BUY"
         //        }
         //    }
+        //
         const order = this.safeValue (response, 'result', {});
         return this.parseOrder (order);
     }
@@ -4287,13 +4292,13 @@ module.exports = class bybit extends Exchange {
         //
         const currencyId = this.safeString (item, 'coin');
         const code = this.safeCurrencyCode (currencyId, currency);
-        const amount = this.safeNumber (item, 'amount');
-        const after = this.safeNumber (item, 'wallet_balance');
-        const direction = (amount < 0) ? 'out' : 'in';
+        const amount = this.safeString (item, 'amount');
+        const after = this.safeString (item, 'wallet_balance');
+        const direction = Precise.stringLt (amount, '0') ? 'out' : 'in';
         let before = undefined;
         if (after !== undefined && amount !== undefined) {
-            const difference = (direction === 'out') ? amount : -amount;
-            before = this.sum (after, difference);
+            const difference = (direction === 'out') ? amount : '-' + amount;
+            before = Precise.stringAdd (after, difference);
         }
         const timestamp = this.parse8601 (this.safeString (item, 'exec_time'));
         const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
@@ -4306,9 +4311,9 @@ module.exports = class bybit extends Exchange {
             'referenceAccount': undefined,
             'referenceId': referenceId,
             'status': undefined,
-            'amount': amount,
-            'before': before,
-            'after': after,
+            'amount': this.parseNumber (amount),
+            'before': this.parseNumber (before),
+            'after': this.parseNumber (after),
             'fee': undefined,
             'direction': direction,
             'timestamp': timestamp,


Code review comments:
diff_hunk: @@ -4287,13 +4292,13 @@ module.exports = class bybit extends Exchange {
         //
         const currencyId = this.safeString (item, 'coin');
         const code = this.safeCurrencyCode (currencyId, currency);
-        const amount = this.safeNumber (item, 'amount');
-        const after = this.safeNumber (item, 'wallet_balance');
-        const direction = (amount < 0) ? 'out' : 'in';
+        const amount = this.safeString (item, 'amount');
+        const after = this.safeString (item, 'wallet_balance');
+        const direction = Precise.stringLt (amount, '0') ? 'out' : 'in';
         let before = undefined;
         if (after !== undefined && amount !== undefined) {
-            const difference = (direction === 'out') ? amount : -amount;
-            before = this.sum (after, difference);
+            const difference = (direction === 'out') ? amount : '-' + amount;
path: js/bybit.js
text: @user1:
Next time avoid doing this concatenation to negate a number, use `Precise.stringNeg` instead (I will fix it this time so nw)