pythonpoloniex

Function returning different result despite the same inputs in Python


Here is my function that uses the Poloniex Exchange API. It gets a dict of asks (tuples of price and amount) and then calculates the total amount of BTC that would be obtained using a given spend.

But running the function several times returns different amounts despite the dict of asks and spend remaining the same. This problem should be replicable by printing "asks" (defined below) and the function result several times.

def findBuyAmount(spend):
    #getOrderBook
    URL = "https://poloniex.com/public?command=returnOrderBook&currencyPair=USDT_BTC&depth=20"
    #request the bids and asks (returns nested dict)
    r_ab = requests.get(url = URL) 
    # extracting data in json format -> returns a dict in this case! 
    ab_data = r_ab.json() 
    asks = ab_data.get('asks',[])
    #convert strings into decimals
    asks=[[float(elem[0]), elem[1]] for elem in asks]
    amount=0
    for elem in asks: #each elem is a tuple of price and amount
        if spend > 0:
            if elem[1]*elem[0] > spend: #check if the ask exceeds volume of our spend
                amount = amount+((elem[1]/elem[0])*spend) #BTC that would be obtained using our spend at this price
                spend = 0 #spend has been used entirely, leading to a loop break

            if elem[1]*elem[0] < spend: #check if the spend exceeds the current ask
                amount = amount + elem[1] #BTC that would be obtained using some of our spend at this price
                spend = spend - elem[1]*elem[0] #remainder

        else:
            break
    return amount

If the first ask in the asks dict was [51508.93591717, 0.62723766] and spend was 1000, I would expect amount to equal (0.62723766/51508.93591717) * 1000 but I get all kinds of varied outputs instead. How can I fix this?


Solution

  • You get all kinds of varied outputs because you're fetching new data every time you run the function. Split the fetch and the calculation into separate functions so you can test them independently. You can also make the logic much clearer by naming your variables properly:

    import requests
    
    def get_asks(url="https://poloniex.com/public?command=returnOrderBook&currencyPair=USDT_BTC&depth=20"):
        response = requests.get(url=url)
        ab_data = response.json()
        asks = ab_data.get('asks', [])
        #convert strings into decimals
        return [(float(price), qty) for price, qty in asks]
    
    def find_buy_amount(spend, asks):
        amount = 0
        for price, qty in asks:
            if spend > 0:
                ask_value = price * qty
                if ask_value >= spend:
                    amount += spend / price 
                    spend = 0
                else:
                    amount += qty
                    spend -= ask_value    
            else:
                break
        return amount
    
    asks = get_asks()
    print("Asks:", asks)
    print("Buy: ", find_buy_amount(1000, asks))
    

    Your math was wrong for when the ask value exceeds remaining spend; the quantity on the order book doesn't matter at that point, so the amount you can buy is just spend / price.

    With the functions split up, you can also run find_buy_amount any number of times with the same order book and see that the result is, in fact, always the same.