Skip to content

Poloniex: _trade emits quote notional as amount, puts trade id in exchange field, drops batched trades #1113

Description

@mercurise-project

Version: 2.4.1 (code unchanged on current master)

Poloniex._trade (poloniex.py#L55-L82) has three problems, all visible against the sample message in its own docstring:

{
    'channel': 'trades',
    'data': [{
        'symbol': 'BTC_USDT',
        'amount': '364.89973',
        'quantity': '0.017',
        'takerSide': 'sell',
        'createTime': 1661120814818,
        'price': '21464.69',
        'id': '60183607',
        'ts': 1661120814823
    }]
}

1. Trade.amount is set to quote notional, not base quantity

The handler emits the raw amount field as Trade.amount. But in Poloniex's trades channel, amount is the quote-currency notional and quantity is the base-unit size. In the docstring sample itself: 21464.69 × 0.017 = 364.89973 — i.e. amount == price × quantity exactly. I also verified this live: across received messages, amount / (price × quantity) == 1.0 with no deviation.

Every other exchange adapter populates Trade.amount with base units, so Poloniex trades come out inflated by a factor of ~price (a 0.017 BTC trade is reported as 364.9 "BTC"). It should be Decimal(entry['quantity']).

2. Trade id is passed as the exchange positional

Trade.__init__ is (exchange, symbol, side, amount, price, timestamp, id=None, type=None, raw=None), but the handler passes msg['data'][0]['id'] as the first positional:

t = Trade(
    msg['data'][0]['id'],          # <- lands in Trade.exchange
    self.exchange_symbol_to_std_symbol(msg['data'][0]['symbol']),
    ...
)

Result: Trade.exchange is '60183607' instead of 'POLONIEX', and Trade.id is None. The first argument should be self.id, with id=str(entry['id']) passed as the keyword.

3. Only data[0] is parsed; the rest of a batch is dropped

data is a list and Poloniex does deliver multiple trades per message, but the handler only reads msg['data'][0], silently discarding the others.

Suggested fix

async def _trade(self, msg: dict, timestamp: float):
    for entry in msg['data']:
        t = Trade(
            self.id,
            self.exchange_symbol_to_std_symbol(entry['symbol']),
            SELL if entry['takerSide'] == 'sell' else BUY,
            Decimal(entry['quantity']),
            Decimal(entry['price']),
            self.timestamp_normalize(entry['ts']),
            id=str(entry['id']),
            raw=msg
        )
        await self.callback(TRADES, t, timestamp)

Happy to open a PR if that helps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions