ccxt / ccxt

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading API with support for more than 100 bitcoin/altcoin exchanges
https://docs.ccxt.com
MIT License
33k stars 7.54k forks source link

trade details for future bug? #13544

Open leastchaos opened 2 years ago

leastchaos commented 2 years ago

It seems that there is some issue for future trade detail for some exchange as cost != price * amount and the trade details seems off.

kucoinfutures: price:29580.89, amount: 745 <- this seems very off, cost: 22037.76305 okx: 'price': 29474.0, 'amount': 10.0, 'cost': 2947.4 huobi: 'price': 29277.4, 'amount': 2364.0, <-- i think this got multiplied by 1000, 'cost': 69211.7736, mexc: 'price': 29444.5, 'amount': 319.0, 'cost': 939.27955 aax: 'price': 29717.53, 'amount': 1.0, 'cost': 29.71753, delta: 'price': 29420.0, 'amount': 100.0, 'cost': 3.3990482664853e-06,

import asyncio
import ccxt.async_support as ccxt
excluded_exchange =[
    "bequant", #access denied
    "buda", #access denied
    "tidebit",
    "xena",
    "vcc"
]

async def check_trade_details(exchange_id: str):
    try:
        exchange = getattr(ccxt, exchange_id)({"defaultType": "swap"})
        trades = await exchange.fetch_trades('BTC/USDT:USDT')
        for trade in trades:
            if abs(trade["cost"] - trade["amount"] * trade["price"]) > 0.01:

                print("XXXXX",exchange_id, trade)
            else:
                print(exchange_id, "ok")
            break
    except Exception as err:
        # print(err)
        return
    finally:
        await exchange.close()

async def main():
    tasks = []
    for exchange_id in ccxt.exchanges:
        if exchange_id in excluded_exchange:
            continue
        tasks.append(asyncio.create_task(check_trade_details(exchange_id)))
    await asyncio.gather(*tasks)
if __name__ == "__main__":
    asyncio.run(main())
XXXXX kucoinfutures {'info': {'sequence': 75846815, 'side': 'buy', 'size': 40, 'price': '29453.0000000000', 'takerOrderId': '629a1ff9a9fbf8000181bbc2', 'makerOrderId': '629a1ff8aff5340001003f8c', 'tradeId': '629a1ff93c7feb35233555dc', 'ts': 1654267897744739373}, 'id': '629a1ff93c7feb35233555dc', 'order': None, 'timestamp': None, 'datetime': None, 'symbol': 'BTC/USDT:USDT', 'type': None, 'takerOrMaker': None, 'side': 'buy', 'price': 29453.0, 'amount': 40.0, 'cost': 1178.12, 'fee': None, 'fees': []}
bitmex ok
bybit ok
XXXXX okex5 {'info': {'instId': 'BTC-USDT-SWAP', 'side': 'sell', 'sz': '13', 'px': '29463.4', 'tradeId': '311889230', 'ts': '1654267931269'}, 'timestamp': 1654267931269, 'datetime': '2022-06-03T14:52:11.269Z', 'symbol': 'BTC/USDT:USDT', 'id': '311889230', 'order': None, 'type': None, 'takerOrMaker': None, 'side': 'sell', 'price': 29463.4, 'amount': 13.0, 'cost': 3830.242, 'fee': None, 'fees': []}
XXXXX okex {'info': {'instId': 'BTC-USDT-SWAP', 'side': 'sell', 'sz': '2', 'px': '29463.3', 'tradeId': '311889231', 'ts': '1654267931269'}, 'timestamp': 1654267931269, 'datetime': '2022-06-03T14:52:11.269Z', 'symbol': 'BTC/USDT:USDT', 'id': '311889231', 'order': None, 'type': None, 'takerOrMaker': None, 'side': 'sell', 'price': 29463.3, 'amount': 2.0, 'cost': 589.266, 'fee': None, 'fees': []}
XXXXX okx {'info': {'instId': 'BTC-USDT-SWAP', 'side': 'sell', 'sz': '2', 'px': '29463.3', 'tradeId': '311889231', 'ts': '1654267931269'}, 'timestamp': 1654267931269, 'datetime': '2022-06-03T14:52:11.269Z', 'symbol': 'BTC/USDT:USDT', 'id': '311889231', 'order': None, 'type': None, 'takerOrMaker': None, 'side': 'sell', 'price': 29463.3, 'amount': 2.0, 'cost': 589.266, 'fee': None, 'fees': []}
XXXXX aax {'info': {'i': 'T2X8tNEKCS', 'p': '29717.53000000', 'q': '1.000000', 's': 'long', 't': '1654259923220'}, 'id': 'T2X8tNEKCS', 'timestamp': 1654259923220, 'datetime': '2022-06-03T12:38:43.220Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'order': None, 'takerOrMaker': None, 'price': 29717.53, 'amount': 1.0, 'cost': 29.71753, 'fee': None, 'fees': []}
XXXXX delta {'id': None, 'order': None, 'timestamp': 1654267759000, 'datetime': '2022-06-03T14:49:19.000Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'price': 29420.0, 'amount': 100.0, 'cost': 3.3990482664853e-06, 'takerOrMaker': None, 'fee': None, 'info': {'buyer_role': 'taker', 'price': '29420', 'seller_role': 'maker', 'size': '100', 'symbol': 'BTCUSDT', 'timestamp': '1654267759000000'}, 'fees': []}
bitget ok
XXXXX huobipro {'id': '1089324468160000', 'info': {'amount': '2', 'direction': 'sell', 'id': '1089324468160000', 'price': '29365.4', 'quantity': '0.002', 'trade_turnover': '58.7308', 'ts': '1654267407438'}, 'order': None, 'timestamp': 1654267407438, 'datetime': '2022-06-03T14:43:27.438Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'sell', 'takerOrMaker': None, 'price': 29365.4, 'amount': 2.0, 'cost': 58.7308, 'fee': None, 'fees': []}
ascendex ok
XXXXX huobi {'id': '1089324468160000', 'info': {'amount': '2', 'direction': 'sell', 'id': '1089324468160000', 'price': '29365.4', 'quantity': '0.002', 'trade_turnover': '58.7308', 'ts': '1654267407438'}, 'order': None, 'timestamp': 1654267407438, 'datetime': '2022-06-03T14:43:27.438Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'sell', 'takerOrMaker': None, 'price': 29365.4, 'amount': 2.0, 'cost': 58.7308, 'fee': None, 'fees': []}
hitbtc3 ok
XXXXX mexc3 {'id': '1654267902537-BTC_USDT-1-48-29447-taker', 'order': None, 'timestamp': 1654267902537, 'datetime': '2022-06-03T14:51:42.537Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': '1', 'takerOrMaker': 'taker', 'price': 29447.0, 'amount': 48.0, 'cost': 141.3456, 'fee': None, 'info': {'p': '29447', 'v': '48', 'T': '1', 'O': '3', 'M': '1', 't': '1654267902537'}, 'fees': []}
samgermain commented 2 years ago

Make sure that you are also considering contractSize, ADA/USDT:USDT has a contract size of 10, which means 1 ADA/USDT:USDT contract is worth 10 ADA, but the price is given as an ADA price,

So with

price = 0.56437 amount = 30 contractSize = 10

then

cost = price amount contractSize = 0.56437 30 10 = 169.311

leastchaos commented 2 years ago

I see, thank you. I now see a mismatch on delta exchange

async def check_trade_details(exchange_id: str, symbol: str = 'BTC/USDT:USDT'):
    try:
        exchange: ccxt.Exchange = getattr(ccxt, exchange_id)()
        await exchange.load_markets()
        market = exchange.market(symbol)
        contract_size = market["contractSize"] if market["contract"] else 1
        print(exchange.id, contract_size)
        trades = await exchange.fetch_trades(symbol)
        for trade in trades:
            if abs(trade["cost"] - trade["amount"] * trade["price"] * contract_size) > 0.01:
                print("XXXXX",exchange_id, trade)
                break
        else:
            print(exchange_id, "ok")
    except Exception as err:
        # print(err)
        return
    finally:
        await exchange.close()

async def main():
    tasks = []
    for exchange_id in ccxt.exchanges:
        if exchange_id in excluded_exchange:
            continue
        tasks.append(asyncio.create_task(check_trade_details(exchange_id)))
    await asyncio.gather(*tasks)
if __name__ == "__main__":
    asyncio.run(main())

contractSize = 0.001 XXXXX delta {'id': None, 'order': None, 'timestamp': 1654323172000, 'datetime': '2022-06-04T06:12:52.000Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'price': 29695.5, 'amount': 26.0, 'cost': 8.75553535047386e-07, 'takerOrMaker': None, 'fee': None, 'info': {'buyer_role': 'taker', 'price': '29695.5', 'seller_role': 'maker', 'size': '26', 'symbol': 'BTCUSDT', 'timestamp': '1654323172000000'}, 'fees': []}

frosty00 commented 2 years ago

@leastchaos will look into it

leastchaos commented 2 years ago

Hi, another issue, kucoinfutures info has 'ts' but timestamp is None {'info': {'sequence': 75930996, 'side': 'sell', 'size': 1, 'price': '29680.0000000000', 'takerOrderId': '629b133b736fa70001cce3b8', 'makerOrderId': '629b12f85aa6170001a04ed0', 'tradeId': '629b133b3c7feb3523e5a948', **'ts': 1654330171668368997},** 'id': '629b133b3c7feb3523e5a948', 'order': None, **'timestamp': None,** 'datetime': None, 'symbol': 'BTC/USDT:USDT', 'type': None, 'takerOrMaker': None, 'side': 'sell', 'price': 29680.0, 'amount': 1.0, 'cost': 29.68, 'fee': None, 'fees': []}

kroitor commented 2 years ago

@leastchaos the ts issue should be fixed in the most recent version of CCXT, please, let us know if you still have difficulties with it.

samgermain commented 2 years ago

I see, thank you. I now see a mismatch on delta exchange

async def check_trade_details(exchange_id: str, symbol: str = 'BTC/USDT:USDT'):
    try:
        exchange: ccxt.Exchange = getattr(ccxt, exchange_id)()
        await exchange.load_markets()
        market = exchange.market(symbol)
        contract_size = market["contractSize"] if market["contract"] else 1
        print(exchange.id, contract_size)
        trades = await exchange.fetch_trades(symbol)
        for trade in trades:
            if abs(trade["cost"] - trade["amount"] * trade["price"] * contract_size) > 0.01:
                print("XXXXX",exchange_id, trade)
                break
        else:
            print(exchange_id, "ok")
    except Exception as err:
        # print(err)
        return
    finally:
        await exchange.close()

async def main():
    tasks = []
    for exchange_id in ccxt.exchanges:
        if exchange_id in excluded_exchange:
            continue
        tasks.append(asyncio.create_task(check_trade_details(exchange_id)))
    await asyncio.gather(*tasks)
if __name__ == "__main__":
    asyncio.run(main())

contractSize = 0.001 XXXXX delta {'id': None, 'order': None, 'timestamp': 1654323172000, 'datetime': '2022-06-04T06:12:52.000Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'price': 29695.5, 'amount': 26.0, 'cost': 8.75553535047386e-07, 'takerOrMaker': None, 'fee': None, 'info': {'buyer_role': 'taker', 'price': '29695.5', 'seller_role': 'maker', 'size': '26', 'symbol': 'BTCUSDT', 'timestamp': '1654323172000000'}, 'fees': []}

Can you explain what you mean by a mismatch? What are you expecting and what are you getting instead?

leastchaos commented 2 years ago

contractSize = 0.001 <- obtain from markets["contractSize"] after load_markets() taking the trade result shown previously

XXXXX delta {'id': None, 'order': None, 'timestamp': 1654323172000, 'datetime': '2022-06-04T06:12:52.000Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'price': 29695.5, 'amount': 26.0, 'cost': 8.75553535047386e-07, 'takerOrMaker': None, 'fee': None, 'info': {'buyer_role': 'taker', 'price': '29695.5', 'seller_role': 'maker', 'size': '26', 'symbol': 'BTCUSDT', 'timestamp': '1654323172000000'}, 'fees': []}

cost = 8.755 e-07

price = 29695.5 contract_size = 0.001 amount = 26

expected cost = price contract_size amount = 29695.5 0.001 26 = 77.103 trade cost = 8.755e-07 trade cost != expected cost

samgermain commented 2 years ago

contractSize is only used in determining the amount, not the cost, this is something all the exchanges do and it wasn't decided by CCXT

If the contractSize of an AXS/USDT:USDT contract is 0.1, meaning you would want to order 6 AXS/USDT:USDT contracts to be ordering an amount equal to 0.6 AXS on kucoinfutures.

The contractSize does not apply to price, when the price of AXS/USDT:USDT is 12.929, that is referring to a price of 12.929 per AXS, not per contract, so if you want 6 AXS/USDT:USDT contracts (0.6 AXS), this order would cost you 12.929 * 0.6 = 7.7574 USDT

leastchaos commented 2 years ago

Make sure that you are also considering contractSize, ADA/USDT:USDT has a contract size of 10, which means 1 ADA/USDT:USDT contract is worth 10 ADA, but the price is given as an ADA price,

So with

price = 0.56437 amount = 30 contractSize = 10

then

cost = price amount contractSize = 0.56437 30 10 = 169.311

I am following this formula you replied earlier and this is correct for rest of the exchanges i think except delta.

samgermain commented 2 years ago

Make sure that you are also considering contractSize, ADA/USDT:USDT has a contract size of 10, which means 1 ADA/USDT:USDT contract is worth 10 ADA, but the price is given as an ADA price, So with price = 0.56437 amount = 30 contractSize = 10 then cost = price amount contractSize = 0.56437 30 10 = 169.311

I am following this formula you replied earlier and this is correct for rest of the exchanges i think except delta.

Could you provide your updated code please?

leastchaos commented 2 years ago

I see, thank you. I now see a mismatch on delta exchange

async def check_trade_details(exchange_id: str, symbol: str = 'BTC/USDT:USDT'):
    try:
        exchange: ccxt.Exchange = getattr(ccxt, exchange_id)()
        await exchange.load_markets()
        market = exchange.market(symbol)
        contract_size = market["contractSize"] if market["contract"] else 1
        print(exchange.id, contract_size)
        trades = await exchange.fetch_trades(symbol)
        for trade in trades:
            if abs(trade["cost"] - trade["amount"] * trade["price"] * contract_size) > 0.01:
                print("XXXXX",exchange_id, trade)
                break
        else:
            print(exchange_id, "ok")
    except Exception as err:
        # print(err)
        return
    finally:
        await exchange.close()

async def main():
    tasks = []
    for exchange_id in ccxt.exchanges:
        if exchange_id in excluded_exchange:
            continue
        tasks.append(asyncio.create_task(check_trade_details(exchange_id)))
    await asyncio.gather(*tasks)
if __name__ == "__main__":
    asyncio.run(main())

contractSize = 0.001 XXXXX delta {'id': None, 'order': None, 'timestamp': 1654323172000, 'datetime': '2022-06-04T06:12:52.000Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'price': 29695.5, 'amount': 26.0, 'cost': 8.75553535047386e-07, 'takerOrMaker': None, 'fee': None, 'info': {'buyer_role': 'taker', 'price': '29695.5', 'seller_role': 'maker', 'size': '26', 'symbol': 'BTCUSDT', 'timestamp': '1654323172000000'}, 'fees': []}

The result was obtained with the above code I posted previously. it only show exchange with difference

samgermain commented 1 year ago

@leastchaos Are you still having any problems?

leastchaos commented 1 year ago

@samgermain I think there is still a mismatch on delta and on latest version bingx seems not to match too. It is not a problem for me as i dont use both exchanges. just highlighting that these 2 exchanges cost does not match amount price contract_size while the rest are ok.

bingx {'id': None, 'info': {'time': '1692181501431', 'isBuyerMaker': False, 'price': '29189.0', 'qty': '0.0058', 'quoteQty': '169.30'}, 'timestamp': 1692181501431, 'datetime': '2023-08-16T10:25:01.431Z', 'symbol': 'BTC/USDT:USDT', 'order': None, 'type': None, 'side': None, 'takerOrMaker': 'taker', 'price': 29189.0, 'amount': 0.0058, 'cost': 169.3, 'fee': {'cost': None, 'currency': None, 'rate': None}, 'fees': [{'cost': None, 'currency': None, 'rate': None}]}
delta {'id': None, 'order': None, 'timestamp': 1692181424000, 'datetime': '2023-08-16T10:23:44.000Z', 'symbol': 'BTC/USDT:USDT', 'type': None, 'side': 'buy', 'price': 29192.0, 'amount': 2.0, 'cost': 6.8511921074266e-08, 'takerOrMaker': None, 'fee': None, 'info': {'buyer_role': 'taker', 'price': '29192', 'seller_role': 'maker', 'size': '2', 'symbol': 'BTCUSDT', 'timestamp': '1692181424000000'}, 'fees': []}