Repository: ccxt/ccxt (language: python)

Issue:
XT fetch_trades() returns only buy trades for all spot markets
### Operating System

Linux Mint

### Programming Languages

Python

### CCXT Version

4.4.24

### Description

All trades returned by `fetch_trades` have value 'buy' as 'side' for XT spot markets. 'takerOrMaker' on the other hand has both 'taker' and 'maker' values. For clarity it would be better to keep 'takerOrMaker' fixed (as 'taker') and let the 'side' have either 'buy' or 'sell' value. 

According to XT API documentation (https://doc.xt.com/#market5tradeRecent) 'b' value returned by the XT API means "whether is buyerMaker or not". In the other words, when 'b' is `True` it is a maker buy trade or, more intuitively, a taker sell trade. Also, in my opinion, when 'b' is `False` the trade should be considered to be a taker buy trade in the ccxt dictionary.


### Code

```
exchange = ccxt.xt()

total_trade_count = 0      
buy_trade_count = 0
sell_trade_count = 0  
maker_trade_count = 0
taker_trade_count = 0

trades = exchange.fetch_trades('BTC/USDT', limit=1000)
for trade in trades:
    total_trade_count += 1
    if trade['side'] == 'buy':
        buy_trade_count += 1
    if trade['side'] == 'sell':
        sell_trade_count += 1
    if trade['takerOrMaker'] == 'maker':
        maker_trade_count += 1
    if trade['takerOrMaker'] == 'taker':
        taker_trade_count += 1        
    
print(trades[0])
print('total trades:', total_trade_count)
print('buy trades:  ', buy_trade_count)
print('sell trades: ', sell_trade_count)   
print('maker trades:', maker_trade_count)
print('taker trades:', taker_trade_count)
print()
```
```
{'info': {'i': '420870962049751424', 't': '1730045456757', 'p': '67806.75', 'q': '0.00728', 'v': '493.63314', 'b': True}, 'id': '420870962049751424', 'timestamp': 1730045456757, 'datetime': '2024-10-27T16:10:56.757Z', 'symbol': 'BTC/USDT', 'order': None, 'type': None, 'side': 'buy', 'takerOrMaker': 'maker', 'price': 67806.75, 'amount': 0.00728, 'cost': 493.63314, 'fee': {'cost': None, 'currency': None}, 'fees': []}
total trades: 201
buy trades:   201
sell trades:  0
maker trades: 99
taker trades: 102
```


Discussion / hints:
@JovianMoon thanks for the report. I'll take a look

Fix patch:
diff --git a/ts/src/xt.ts b/ts/src/xt.ts
index 10bf424f2f4d..1bad52132e69 100644
--- a/ts/src/xt.ts
+++ b/ts/src/xt.ts
@@ -1974,6 +1974,17 @@ export default class xt extends Exchange {
         //         "b": true
         //     }
         //
+        // spot: watchTrades
+        //
+        //    {
+        //        s: 'btc_usdt',
+        //        i: '228825383103928709',
+        //        t: 1684258222702,
+        //        p: '27003.65',
+        //        q: '0.000796',
+        //        b: true
+        //    }
+        //
         // spot: watchMyTrades
         //
         //    {
@@ -1986,17 +1997,6 @@ export default class xt extends Exchange {
         //        "v": "90000"                    // volume trade amount
         //    }
         //
-        // spot: watchTrades
-        //
-        //    {
-        //        s: 'btc_usdt',
-        //        i: '228825383103928709',
-        //        t: 1684258222702,
-        //        p: '27003.65',
-        //        q: '0.000796',
-        //        b: true
-        //    }
-        //
         // swap and future: fetchTrades
         //
         //     {
@@ -2076,22 +2076,31 @@ export default class xt extends Exchange {
             marketType = hasSpotKeys ? 'spot' : 'contract';
         }
         market = this.safeMarket (marketId, market, '_', marketType);
-        const bidOrAsk = this.safeString (trade, 'm');
-        let side = this.safeStringLower (trade, 'orderSide');
-        if (bidOrAsk !== undefined) {
-            side = (bidOrAsk === 'BID') ? 'buy' : 'sell';
-        }
-        const buyerMaker = this.safeValue (trade, 'b');
-        if (buyerMaker !== undefined) {
-            side = 'buy';
-        }
-        let takerOrMaker = this.safeStringLower (trade, 'takerMaker');
-        if (buyerMaker !== undefined) {
-            takerOrMaker = buyerMaker ? 'maker' : 'taker';
-        }
-        const isMaker = this.safeBool (trade, 'isMaker');
-        if (isMaker !== undefined) {
-            takerOrMaker = isMaker ? 'maker' : 'taker';
+        let side = undefined;
+        let takerOrMaker = undefined;
+        const isBuyerMaker = this.safeBool (trade, 'b');
+        if (isBuyerMaker !== undefined) {
+            side = isBuyerMaker ? 'sell' : 'buy';
+            takerOrMaker = 'taker'; // public trades always taker
+        } else {
+            const takerMaker = this.safeStringLower (trade, 'takerMaker');
+            if (takerMaker !== undefined) {
+                takerOrMaker = takerMaker;
+            } else {
+                const isMaker = this.safeBool (trade, 'isMaker');
+                if (isMaker !== undefined) {
+                    takerOrMaker = isMaker ? 'maker' : 'taker';
+                }
+            }
+            const orderSide = this.safeStringLower (trade, 'orderSide');
+            if (orderSide !== undefined) {
+                side = orderSide;
+            } else {
+                const bidOrAsk = this.safeString (trade, 'm');
+                if (bidOrAsk !== undefined) {
+                    side = (bidOrAsk === 'BID') ? 'buy' : 'sell';
+                }
+            }
         }
         const timestamp = this.safeIntegerN (trade, [ 't', 'time', 'timestamp' ]);
         const quantity = this.safeString2 (trade, 'q', 'quantity');


Test patch:
diff --git a/ts/src/test/static/response/xt.json b/ts/src/test/static/response/xt.json
index 626461ef79a0..ac82d6364d86 100644
--- a/ts/src/test/static/response/xt.json
+++ b/ts/src/test/static/response/xt.json
@@ -403,6 +403,196 @@
           }
         ]
       }
+    ],
+    "fetchTrades": [
+      {
+        "description": "spot & limit",
+        "method": "fetchTrades",
+        "input": [
+          "BTC/USDT",
+          null,
+          5
+        ],
+        "httpResponse": {
+          "rc": "0",
+          "mc": "SUCCESS",
+          "ma": [],
+          "result": [
+            {
+              "i": "423029665070881152",
+              "t": "1730560131664",
+              "p": "69243.26",
+              "q": "0.00552",
+              "v": "382.2227952",
+              "b": false
+            },
+            {
+              "i": "423029660033522048",
+              "t": "1730560130463",
+              "p": "69243.26",
+              "q": "0.00057",
+              "v": "39.4686582",
+              "b": false
+            },
+            {
+              "i": "423029655998601600",
+              "t": "1730560129501",
+              "p": "69243.26",
+              "q": "0.00549",
+              "v": "380.1454974",
+              "b": false
+            },
+            {
+              "i": "423029650105604480",
+              "t": "1730560128096",
+              "p": "69243.26",
+              "q": "0.00501",
+              "v": "346.9087326",
+              "b": false
+            },
+            {
+              "i": "423029643818342784",
+              "t": "1730560126597",
+              "p": "69243.25",
+              "q": "0.10917",
+              "v": "7559.2856025",
+              "b": true
+            }
+          ]
+        },
+        "parsedResponse": [
+          {
+            "info": {
+              "i": "423029643818342784",
+              "t": "1730560126597",
+              "p": "69243.25",
+              "q": "0.10917",
+              "v": "7559.2856025",
+              "b": true
+            },
+            "id": "423029643818342784",
+            "timestamp": 1730560126597,
+            "datetime": "2024-11-02T15:08:46.597Z",
+            "symbol": "BTC/USDT",
+            "order": null,
+            "type": null,
+            "side": "sell",
+            "takerOrMaker": "taker",
+            "price": 69243.25,
+            "amount": 0.10917,
+            "cost": 7559.2856025,
+            "fee": {
+              "cost": null,
+              "currency": null
+            },
+            "fees": []
+          },
+          {
+            "info": {
+              "i": "423029650105604480",
+              "t": "1730560128096",
+              "p": "69243.26",
+              "q": "0.00501",
+              "v": "346.9087326",
+              "b": false
+            },
+            "id": "423029650105604480",
+            "timestamp": 1730560128096,
+            "datetime": "2024-11-02T15:08:48.096Z",
+            "symbol": "BTC/USDT",
+            "order": null,
+            "type": null,
+            "side": "buy",
+            "takerOrMaker": "taker",
+            "price": 69243.26,
+            "amount": 0.00501,
+            "cost": 346.9087326,
+            "fee": {
+              "cost": null,
+              "currency": null
+            },
+            "fees": []
+          },
+          {
+            "info": {
+              "i": "423029655998601600",
+              "t": "1730560129501",
+              "p": "69243.26",
+              "q": "0.00549",
+              "v": "380.1454974",
+              "b": false
+            },
+            "id": "423029655998601600",
+            "timestamp": 1730560129501,
+            "datetime": "2024-11-02T15:08:49.501Z",
+            "symbol": "BTC/USDT",
+            "order": null,
+            "type": null,
+            "side": "buy",
+            "takerOrMaker": "taker",
+            "price": 69243.26,
+            "amount": 0.00549,
+            "cost": 380.1454974,
+            "fee": {
+              "cost": null,
+              "currency": null
+            },
+            "fees": []
+          },
+          {
+            "info": {
+              "i": "423029660033522048",
+              "t": "1730560130463",
+              "p": "69243.26",
+              "q": "0.00057",
+              "v": "39.4686582",
+              "b": false
+            },
+            "id": "423029660033522048",
+            "timestamp": 1730560130463,
+            "datetime": "2024-11-02T15:08:50.463Z",
+            "symbol": "BTC/USDT",
+            "order": null,
+            "type": null,
+            "side": "buy",
+            "takerOrMaker": "taker",
+            "price": 69243.26,
+            "amount": 0.00057,
+            "cost": 39.4686582,
+            "fee": {
+              "cost": null,
+              "currency": null
+            },
+            "fees": []
+          },
+          {
+            "info": {
+              "i": "423029665070881152",
+              "t": "1730560131664",
+              "p": "69243.26",
+              "q": "0.00552",
+              "v": "382.2227952",
+              "b": false
+            },
+            "id": "423029665070881152",
+            "timestamp": 1730560131664,
+            "datetime": "2024-11-02T15:08:51.664Z",
+            "symbol": "BTC/USDT",
+            "order": null,
+            "type": null,
+            "side": "buy",
+            "takerOrMaker": "taker",
+            "price": 69243.26,
+            "amount": 0.00552,
+            "cost": 382.2227952,
+            "fee": {
+              "cost": null,
+              "currency": null
+            },
+            "fees": []
+          }
+        ]
+      }
     ]
   }
 }
\ No newline at end of file