DeFI Decode: Liquidity mining optimisation — Why most LP users won’t get average yield and what you need to get it

Ben Liu
8 min readDec 27, 2023

--

This article is part of the open source tool (github) I work on to help LP mining users get higher yield. This article focuses on fee income leg only, while our another article on set optimal range considers both fee income and impermanent loss. How to use the 2 work together is explained in the comment section. Let’s now move on to the topic.

Fig. yield farming credit.

First, what is LP pool average yield?

Some APPs like OKX Web3 wallet calculates such yield for you, see picture below.

In other cases like the web-page of uniswap V3 WBTC/ETH pool on Arbitrum, you can work out average yield yourself from the shown TVL and 24h fee on the left panel: 21.94m and 4.95k on screenshot day:

Average yield = 4.95k / 21.94m * 365 = 8.23%.

You may think that you will get this yield approximately. Unfortunately, this is NOT true, and most likely you get less or much less. This is because set your range without research may significantly dilute your yield income.

For example, take a deep look into the LP profile provided by users on the day. The huge amount of liquidity provided in the vertical bar to the left of current price is out of range and gets zero income. (for curiosity, the value lock there is ~7BTC or 300K USDT)

Therefore, how to set LP range such that we can get the average yield?

Summary of our method

The answer is ~5% for WBTC/ETH pool. The key driving factor is to provide proportional liquidity amount based on choice of range limit plus impact of underlying price volatility.

The exact formula is:

where:

  • d_n is range limit (down part) and up part (symmteric) can be calculated as d_n/(1-d_n)
  • w_i is the asset weightage for all existing users (TVL of user i divided by TVL of all users)
  • c_i is the coverage rate. And this rate depends on both token0/token1 price volatility and range width. (intuitively, narrow range leads to small coverage_rate)
  • Overall, the inverse of d_n is the weighted average of all other users’ d_i inverse, or harmonic mean. Such type of mean weights higher of smaller range limit, which can result (in most cases) in most people get less than the average yield.

Let’s move on to explain why/how we get this result.

Content

  • Why majority people won’t get average yield
  • How to get it (harmonic mean + range coverage rate)
  • Data results and github code
  • Comments

Why majority people won’t get average yield

Let’s use a simple example for illustration. Assume we have 3 LP users. All 3 deposit 10k USDT into the pool but with different range:

  • User1 with range [ -5%, 5%]
  • User2 with range [-10%, 10%]
  • User3 with range [-20%, 20%].

Assume this pool is stable and after some period, the pool generated total fee income of 2400 USDT (with average yield 8%). The individual user’s fee income plus their respective yield can then be worked out and given below. Out of 3, only User 1 managed to get yield (13.85%) higher than average of 8%, while the other 2 users get less than the average.

Readers can change above range and work out yield to see how many users can get average yield. You perhaps can also define the conditions that 2 users will get > average, but such case is not frequency in real life. Let’s move on the next section to find out reasons.

How to get average yield (harmonic mean + range coverage rate)

Assume currently the pool has asset TVL of A_total with derived liquidty as L_total. Now you want to deposit addtional A_n (n stands for new) asset:

  • Your pool asset % share will be A_n/A_total. however,
  • your share of fee income is decided by your liquidity % (L_n / L_total).

To get average yield, you need to set a range limit such that

Let’s workout the math

where i refers to each of existing LP users. You can see that: to get average yield, you L/A ratio needs to be the asset-% weighted L/A ratio of all other providers.

Let’s further dive into what L/A is. Denote range as [-d, +u] where u = d/(1-d) (meaning we use symmetric range). In such case, both token0 and token1 are of value A/2. Then when price drop from current price p to p*(1-d_n), it will deplete fully the A/2 token1 we have provided, i.e.,

and due to

We get the important connection between L/A ratio and d_n:

This leads to the first key result of this article: To get average yield, your d_n needs to be the harmonic mean of asset_% weighted 1/d of all other people:

Note that above equation only works when price didn’t move much. In real case, price may move out of range for some user i, meaning A_i / A_total should be scale down based on range width. Hence, we further add in the coverage_rate weight (denoted as c_i) to get final result:

A few more explanation:

  • In case other people provide narrower range, you also need to narrow down to get average return.
  • You can also have d value less than the harmonic mean, so as to get above average yield (only when the market price didn’t move much)
  • With narrower d, you will suffer more from two sources when price move: higher impermanent loss, plus lower fee when price move out of your range. (details can be found in our article on set optimal range)

Data results and github code

This section gives the number results from our code in Github.

Based on the formula, two sets of data are needed:

  • All other users’ range limit and amount of asset they deposit into that range.
  • Pool price volatility and coverage rate against each of the range limit.

On getting approximate asset locked at each range

You can get it bin by bin by moving your curser and note down the asset locked. For simplisity, we only grab a few point and use linear interpolation to work out for bins in between.

In our specific example, the liquidity chart visually looks like a triangle at centre, plus a slowly going down line toward both end. we get asset at 3 position: the position at middle (highest asset), the inflection point (where slope change), and final end point (where liquidity ends): from pool web page on the day we got 2BTC at middle, 0.66BTC at range down value = -0.05, and ending liquidity of 0.29BTC at -0.20. The result are given in chart below. noted that the out of range one is ignored (since it gets 0 income).

On getting coverage rate

This value depends on 2 factors:

  • Historical price data (and its volatility). we use 1 year daily price data from coingecko.
  • Period for coverage_rate estimate. we use 1 month, which means: with the range you set, counting from today, how many days the accumulative price move will stay within above range within a month.

The estimated 1-month coverage_rate for WBTC/ETH is shown below:

  • the 1-month price change never exceed -20% in past 1 year.
  • -8% range can cover 90% of 1 month price move.
  • coverage rate reduce significantly when range is -6% or narrower.

Now combine two factors above, we get the weightage w_i * c_i in chart below.

  • the original line (asset weightage only) follows closely with asset provided at each range, while
  • The blue line dips down with small range due to increased of chances that price can move outside such range.

With above weightage, you can work out d_u. you can run the code use

poetry install

poetry run python main_avg_yld.py

Comments

Note that, even after setting the correct range limit, the final yield at end still depends on external factors like trading volume. but the work here give you a better chance to getting it.

The connection between this article and article on set optimal range is that this article only focus on the gain side while the setting of optimal range requires balance between gain and loss. A suggested way to use these 2 tools are:

  • use this tool to know the “range” needed for a fair share of return.
  • use the other tool to find out whether the corresponding imp loss suits your risk appetite.
  • then choose your range in the informed way.

Also, both of these two works are based on monthly investment horizon. There may have a chance of leverage narrower range + rebalance to get higher yield. This is next stage of tool I am working for.

The End. Keep it up! If you work in similar areas, can msg me as well for progress together.

— By BitBlock Technology.

--

--