Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#27239·ccxt

Luno Exchange `watch_order_book` not handling trade updates

Author: badokunCreated Nov 5, 2025Updated Sep 15, 2026
Labelsbugenhancementsuggestion

Operating System

MacOs

Programming Language

Python

CCXT Version

4.5.14

Description

When streaming market data for Luno Exchange, the documentation states that:

"Reduce the outstanding volume of an Order in the Order Book (maker_order_id) and append a Trade to the Trades List."

However the current implementation does not reduce the outstanding volume.

Below is the fix to address this.

python
    def handle_trades(self, client: Client, message, subscription):
        #
        #     {
        #         "sequence": "110980825",
        #         "trade_updates": [],
        #         "create_update": {
        #             "order_id": "BXHSYXAUMH8C2RW",
        #             "type": "ASK",
        #             "price": "24081.09000000",
        #             "volume": "0.07780000"
        #         },
        #         "delete_update": null,
        #         "status_update": null,
        #         "timestamp": 1660598775360
        #     }
        #
        rawTrades = self.safe_value(message, 'trade_updates', [])
        length = len(rawTrades)
        if length == 0:
            return
        symbol = subscription['symbol']
        market = self.market(symbol)
        messageHash = 'trades:' + symbol
        stored = self.safe_value(self.trades, symbol)
        if stored is None:
            limit = self.safe_integer(self.options, 'tradesLimit', 10000)
            stored = ArrayCache(limit)
            self.trades[symbol] = stored
        for i in range(0, len(rawTrades)):
            rawTrade = rawTrades[i]
            trade = self.parse_trade(rawTrade, market)
            stored.append(trade)
        self.trades[symbol] = stored
        client.resolve(self.trades[symbol], messageHash)

        # FIX: Update orderbook volumes based on trades
        if length > 0 and symbol in self.orderbooks:
            orderbook = self.orderbooks[symbol]

            for trade in rawTrades:
                maker_order_id = self.safe_string(trade, 'maker_order_id')
                base_volume = self.safe_string(trade, 'base')  # Amount traded

                if maker_order_id and base_volume:
                    # Reduce volume in both bids and asks (we don't know which side)
                    # The storeArray method with volume=0 will delete if volume becomes 0
                    self._reduce_order_volume(orderbook['bids'], maker_order_id, base_volume)
                    self._reduce_order_volume(orderbook['asks'], maker_order_id, base_volume)

    def _reduce_order_volume(self, order_side, order_id: str, traded_volume: str):
        """
        Reduce the volume of an order in the orderbook after a trade.

        Args:
            order_side: The bids or asks side of the orderbook
            order_id: The maker order ID that was traded
            traded_volume: The volume that was traded (as string)
        """
        # Find the order by ID
        for i in range(len(order_side)):
            order = order_side[i]
            if len(order) >= 3 and order[2] == order_id:
                # Found the order: [price, volume, id]
                current_volume = decimal.Decimal(str(order[1]))
                trade_volume = decimal.Decimal(traded_volume)
                new_volume = current_volume - trade_volume

                if new_volume <= 0:
                    # Order fully filled - delete it
                    order_side.storeArray([order[0], 0, order_id])
                else:
                    # Order partially filled - update volume
                    order_side.storeArray([order[0], float(new_volume), order_id])

                break  # Found and updated, exit loop

Source: ccxt/ccxt

View original on GitHubView discussion on GitHub