Python Uniswap Subgraph - Constant product formula

Viewed 154

I'm trying to calculate the price impact on trades and am getting strange results.

I am using uniswap v2 subgraph to get current data for WETH/USDC.

def loadUni2():
    query = """

{
    pairs (
    first: 10
    orderBy: volumeUSD
    orderDirection:desc
  
  ){
    id
    reserve0
    token0Price
    token0 {
      id
      symbol
      decimals
    }
    token1Price
    reserve1
    token1{
      id
      symbol
      decimals
    } 
  }
}

"""

I then save the results of this query into individual variables and do the same math for the "constant product formula" that uniswap says it uses for its pools

pair = pairs[0]


#sort dataframe by lowest price 
low = pair.sort_values(by='token0Price', ascending=True)

quoteReserve = low['reserve0'].values[0]   #USDC Tokens in pair verified by checking info.uniswap.org
baseReserve = low['reserve1'].values[0]    #WETH tokens in pair verified by checking info.uniswap.org
token0Price = low['token0Price'].values[0] 
token1Price = low['token1Price'].values[0]

#Buy Low
amount = 1   # purchase amount in USD
constant = quoteReserve * baseReserve

newReserve = (quoteReserve + amount)

output = constant / newReserve

wethPurchaseAmount = baseReserve - output

pricePerToken = amount / wethPurchaseAmount

if (newReserve * output) == constant:
  check = True

print(f'Token0Price before trade : {token0Price}')
print(f'Token1Price before trade: {token1Price}')
print(f'Quote Reserves: {quoteReserve}')
print(f'Base Reserves: {baseReserve}')
print(f'Constant: {constant}')
print(f'New Reserve: {newReserve}')
print(f'Output: {output}')
print(f'WETH Purchased Amount: {wethPurchaseAmount}')
print(f'Price paid Per Token : {pricePerToken}')
print(check)

Since my amount is only $1 the price paid per token should match the token0Price. But my results look like:


Token0Price : 1942.4506384054528
Token1Price: 0.0005148135969215
Quote Reserves: 121784650.548786
Base Reserves: 105869.64875708237
Constant: 12893298177603.992
New Reserve: 121784651.548786
Output: 105869.64788776389
WETH Purchased Amount: 0.0008693184790899977
Price Per Token: 1150.3264040203076
True

I'm either missing something or somehow my math is wrong? Any suggestions/ideas would be greatly appreciated.

Here's the link for where I found an example of the Constant Product Formula

Also, the only imports I have are 'requests' and 'pandas' Running it in a google collab notebook.

I apologize in advance if this is hard to read, I'm completely new to this.

2 Answers

In your calculations you're forgetting to account for the 0.3% fee associated with each swap. When using a fee, the constant in the Constant Product Formula will actually change and so won't be accurate when calculating output reserves. Confusing isn't it? I explained why the K-value changes in my answer here.

Instead, I've found this formalization of the Constant Product Formula to be useful. Essentially to get an output amount in WETH given an input amount in USDC, the formula would be:

equation

Then, usdcOutputReserve = usdcReserve - usdcInput, and wethOutputReserve = wethReserve - wethOutput. With these output reserves you can calculate the new token prices and therefore price impact of the previous trade.

Let me know if this answers your question.

You can find example price impact calculations in Python here:

def estimate_buy_price(
    uniswap: UniswapV2Deployment,
    base_token: Contract,
    quote_token: Contract,
    quantity: int,
    *,
    fee: int = 30,
    slippage: float = 0,
    intermediate_token: Optional[Contract] = None,
) -> int:
    """Estimate how much we are going to need to pay when doing buy.
    Calls the on-chain contract to get the current liquidity and estimates the
    the price based on it.
    Example:
    .. code-block:: python
        # Estimate how much ETH we will receive for 500 USDC.
        # In this case the pool ETH price is $1700 so this should be below ~1/4 of ETH
        amount_eth = estimate_buy_price(
            uniswap_v2,
            weth,
            usdc,
            1*10**18,
        )
        assert amount_eth / 1e18 == pytest.approx(0.28488156127668085)
    :param uniswap: Uniswap v2 deployment
    :param base_token: Base token of the trading pair
    :param quote_token: Quote token of the trading pair
    :param quantity: How much of the base token we want to buy
    :param fee: Trading fee express in bps, default = 30 bps (0.3%)
    :param slippage: Slippage express in bps
    :return: Expected base token to receive
    """
    fee_helper = UniswapV2FeeCalculator(uniswap)
    if intermediate_token:
        path = [quote_token.address, intermediate_token.address, base_token.address]
    else:
        path = [quote_token.address, base_token.address]
    return fee_helper.get_amount_in(quantity, path, fee=fee, slippage=slippage)

See the link for longer, full, source code.

If you are using Jupyter notebooks, you might be also interested the example notebooks here.

Related