Calculating Value, Impermanent Loss and Slippage for Balancer Pools
Edit: slippage in this post should be understood as price impact. The confusion around these two terms is discussed here.
If you had a chance to read Balancer's whitepaper it may have been daunting to follow all the maths involved. Fortunately, most of the complicated partial derivatives and proofs are not necessary for understanding and using the protocol. A simple invariant, which we call the Value Function, ensures all the interesting self-balancing properties that Balancer pools have:
where Bi and wi are the token balances and weights respectively.
Value of Balancer pools
A Balancer pool can be comprised of up to 8 different ERC20 tokens, each with their own arbitrary weights. The weights represent the percentage of value that the pool should be holding in each token at any time. That percentage of value the pool holds in each token is expected to be always very close to the pool weight, so long as there are rational arbitrageurs active in the market and the pool fee is low (see how high-fee Balancer pools can act as swing traders by allowing a higher deviation of values from the defined weights).
With low fees, as soon as there is a price change in any of the tokens relative to another, arbitrageurs are incentivized to bring the pool value distribution across tokens back to that of the original pre-defined weights.
An interesting effect of having a flexible choice of weights for each token is that the pool liquidity provider can control what level of exposure they want to have to each asset. For example, if they are bullish on MKR (relative to ETH), they can opt to add liquidity to a pool with a high weight in MKR and a low weight in ETH. Or they can create one if no such pool exists. This way, when MKR goes up relative to ETH, they are going to keep most of the MKR upside.
Granted: the upside won't be the same as holding 100% MKR but it will be much better than having a 50/50 pool between MKR and ETH. The screenshot below of a recent rally of MKR shows this point in practice.
Pool value with varying prices of underlying tokens
Some key questions one can ask when providing liquidity to a Balancer pool are:
- Is there a way to generalize the calculation of how much a Balancer pool is worth after the prices of underlying tokens all changed?
- How much will a pool that holds 75% MKR and 25% ETH (like the one in the screenshot above) grow in value if MKR's price doubles and ETH stays constant?
- What is the loss of a pool if a token with 10% weight goes down by 5x?
A very simple formula offers the answer to all these questions. The value of a Balancer pool in any reference (for example USD) changes according to the price changes in that same reference (USD) of each of its underlying tokens:
is the variation in USD price of token i, and
is the weight of token i.
The long form proof for this equation can be found in this detailed article available on our website.
With this formula at hand, we can easily answer the questions we posed above. Notice that token prices that don’t change don’t affect the pool value (ΔP_usd^w = 1^w = 1), whatever the weight of those tokens. So we have:
- If MKR's price doubles, a pool with 75% MKR and 25% ETH will have a total value increase of 68.2% (=2^0.75=1.682) as opposed to 41.4% (=2^0.5=1.414) for a 50/50 pool.
- A pool that has a token with weight 10% that goes down by 5x (an 80% crash, or ΔP_usd = 0.2) will have a total value decrease of only about 15% (=0.2^0.1=0.8513).
The term impermanent loss became widespread with the very insightful articles by Pintail. If you never heard the term before, please take a read at his important article about returns on Uniswap pools.
By definition, impermanent loss (IL) describes the percentage by which a pool is worth less than what one would have if they had instead just held the tokens outside of the pool. In other words:
This formula considers a theoretical pool with 0% fee. Balancer's Value Function without fees is path independent (that is, the order of trades does not change the final state of the pool). This implies that, if the liquidity provider removes their liquidity when all the relative token prices are the same as when they added liquidity, impermanent loss will be zero: they will have exactly the same amount of tokens they've invested.
Adding fees to the equation, the final profit in USD terms by the liquidity provider will be the accumulated fees in terms of % of total pool value subtracted by the impermanent loss.
We can expand the formula for impermanent loss above using the following definition for variation of hold value for the pool:
To clarify this formula, imagine, for example, a holding basket that has a token with weight 50% and that token doubled in USD value. The total value of the holding basket will increase by 50%, or by 1.5x (=1 * 50% + 2 * 50% = 1.5). In other words, imagine initially holding $500 in token A and $500 in token B, a total of $1000. If token B doubles in value you'll then be holding $500 in token A and $1000 in token B, a total of $1500 (1.5x or 50% more, as expected).
As detailed in the article mentioned above, impermanent loss can also be written in terms of the variation in pool value and hold value:
So replacing the formulas above we get to our final expression for impermanent loss in Balancer pools:
Notice that because of the convexity of the Value Function, the impermanent loss will always be either zero or a negative number. This could lead to a confusion with a negative loss being interpreted as a gain. This is not the case: the real meaning of the IL being always negative is that there is always some impermanent loss with any relative change in token prices.
Slippage in Balancer Pools
By definition, slippage is the percentage change in the effective price paid in a trade relative to the spot price. The spot price is defined as the limit of the effective price as the amount traded tends to zero.
In Balancer pools with a fee, the spot price is defined by (notice that from here on i means the input token, i.e. the token that is being sent/sold to the pool by the trader):
The effective price of a trade is by definition the ratio of the amount the trader sold (amountIn) divided by the amount of the other token they got in return (amountOut):
Using the formula for amountOut derived in our whitepaper we can rewrite this as:
Note that, even though we are dealing with trades where the user defines the amount they want to sell (amountIn), the whole derivation below can be done for when the user defines the amount they want to buy (amountOut), as detailed in the following section.
We can define slippage as the percentage by which the effective price exceeds the spot price. It's a function of the amountIn traded (Ai) as it influences the effective price:
So if the effective price of a trade is 102 and the spot price is 100, then the slippage is 2%.
Slippage is not linear in Balancer: it grows faster with increasing amounts being traded. As an approximation though, we can linearize the slippage for small values traded. The chart below shows the effective price for increasing amounts sold in blue and the linearization of the effective price with slippage in orange (all numbers are fictitious):
This linearization is extremely useful for many algorithmic optimizations including our smart order router (SOR).
By linearizing we can rewrite the slippage as a linear function of the amount traded:
The slippage slope (SL) is simply the derivative of the slippage formula defined above at Ai = 0. This can be calculated in different ways, but the final solution is:
Practical example of slippage calculation
Let's take for example a pool which is 70% AST / 30% WETH. At the time of writing this pool has about 4.147M AST and 491 WETH:
Let's calculate the slippage that a trade of 1 WETH would cause in this pool using the formula derived above. The fee is 0.0099 (0.99%), Bi is the Balance of the token being sold to the pool (491 WETH), wi is the weight of the token being sold to the pool (0.3) and wo is the weight of the token being bought from the pool (0.7). So the linearized slippage formula for this pool would be:
The linearized slippage of a trade of WETH for AST can then be written as:
With a trade of 1 WETH, we should expect 0.14% of slippage. This is exactly what we get if we simulate this trade on balancer.exchange:
Slippage for AmountOut
For completeness's sake, let's derive the formula for the slippage given the amount bought of a token, amountOut (Ao). The formulas are very similar, we start from the same effective price formula:
But this time around we expand Ai as a function of Ao, as derived on our whitepaper:
And the slippage can be written as a function of Ao:
Solving the derivative we have:
It's interesting to notice that, as one would expect, the slippage is symmetric in a Balancer pool. That is, if one trades a small amount relative to the size of the pool, it should not matter in which direction (from token A to B or from token B to A) the trade is: the slippage in % should be the same for the same value being traded. This can be observed as the slippage slopes calculated for Ao and for Ai are the same in terms of % per value traded, they are only in different units. SLi is % per Ai traded and SLo is % per Ao traded: