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
32.79k stars 7.5k forks source link

How to do multiple private calls on multiple symbols ? #13136

Closed Kinzowa closed 2 years ago

Kinzowa commented 2 years ago

Hello,

I'm trying to implement async loops in order to do multiple parallels private calls (fetchOrder, fetchBalance, createOrder, cancelOrder) with multiple accounts and with multiple symbols of Binance (fetchOrderBook). All accounts trade the 3 symbols in spot and and 3 symbols in futures markets of the fapi endpoint.

I have read the Python examples and it's really helpful for what I try to achieve, especially this, this and this . However I don't think this case is covered so I try to figure out what is the best approach to do that.

Question

The first question that come to my mind is do I need a common fetchOrderBook call for all account or should I duplicate this call ? Having a common call seems the best approcah but how to implement ? It's a bit tricky to do at my level because it means the loops for parallels private calls (this) must be inside the loops fetchOrderBook. What do you think ?

Up to now this is my code, it works perfectly with 3 symbols in spot and 3 symbols in futures.

Thank you,

import os
import sys
from asyncio import gather, get_event_loop

import ccxt.async_support as ccxt  # noqa: E402

root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(root + '/python')

import nest_asyncio
nest_asyncio.apply()

print('CCXT Version:', ccxt.__version__)

async def symbol_loop(exchange, wallet, symbol):
    print('Starting the', exchange.id, wallet, 'symbol loop with', symbol)
    while True:
        try:
            orderbook = await exchange.fetch_order_book(symbol)
            now = exchange.milliseconds()
            print(exchange.iso8601(now), wallet, exchange.id, symbol, orderbook['asks'][0], orderbook['bids'][0])
            time.sleep(2)

        except Exception as e:
            print(str(e))
            # raise e  # uncomment to break all loops in case of an error in any one of them
            break  # you can break just this one loop if it fails

async def exchange_loop(asyncio_loop, k, v):

    exid, wallet = k.split("_")
    symbols = v

    print('Starting the', exid, 'exchange loop with', wallet, symbols)

    exchange = getattr(ccxt, exid)({
        'enableRateLimit': True,
        'asyncio_loop': asyncio_loop,
    })
    exchange.options['defaultType'] = wallet
    loops = [symbol_loop(exchange, wallet, symbol) for symbol in symbols]

    await gather(*loops)
    await exchange.close()

async def main(asyncio_loop):
    markets = dict(
        binance_spot=['BTC/USDT', 'ETH/USDT', BNB/USDT'],
        binance_future=['BTC/USDT', 'ETH/USDT', BNB/USDT']
    )
    loops = [exchange_loop(asyncio_loop, k, v) for k, v in markets.items()]
    await gather(*loops)

asyncio_loop = get_event_loop()
asyncio.create_task(main(asyncio_loop))
samgermain commented 2 years ago

Right now you'll have to create 2 separate exchange instances

spot = ccxt.binance({...})
future = ccxt.binance({..., "defaultType": "future"})

In a future version of CCXT binance will return all the spot and swap markets together in loadMarkets (like how FTX does), and the swap/future symbols will use the unified naming convention

Kinzowa commented 2 years ago

Right now you'll have to create 2 separate exchange instances

spot = ccxt.binance({...})
future = ccxt.binance({..., "defaultType": "future"})

In a future version of CCXT binance will return all the spot and swap markets together in loadMarkets (like how FTX does), and the swap/future symbols will use the unified naming convention

In fact I already create two exchange instances in the exchange_loop() function above, one for spot and the other for future. But the tricky point is how to add exchange class for users inside the loop ?

sc0Vu commented 2 years ago

Do you mean calling different private methods with different user?

ttodua commented 2 years ago

@Kinzowa To add a comment to already existing replies above, what you ask is a basic programming question, rather than ccxt-specific. When you instantiate the new class, you hold it in variable. For every user, you should instantiate the classes with their API keys individually and store/hold them separately from each other (if you want to use private methods). however, one shared class which you will use for orderbook, can be created separately, then store the values in global variable, and then use those values inside all other user-specific instances asynchronously. Remember, all public information (orderbook, prices, etc...) do not need to be fetched individually in each instance, instead you fetch them in one shared instance and then use the values across all instances.

Let us know if you don't understand what I say or if you have any further issues with CCXT.