Part 2: Minswap Dynamic Fees
This article is Part 2 of a 2 part series on Dynamic Fees, authored in its entirety by two Minswap community members: Marco and Elder Millennial. Dynamic fees are fees that change with respect to an indicator, and will be adjustable using an LP weighted vote. It is highly recommended to check out Part 1 that describes the idea of dynamic fees, why they are useful, and previous approaches to dynamic fees. This article describes the ideas used for the implementation that will be used in Minswap V2. However, this feature is still being worked on and will be available after launch.
One innovative aspect of this work was the approach to understanding how fee parameters impact liquidity provider gains. We used the Steelswap DEX aggregator created by Elder Millennial to simulate the behavior of a perfect trader, and tried to maximize liquidity provider gains under the assumption that a perfect trader will always take the trade split that maximizes token returns. Thus, setting a fee too high reduces volume and thus liquidity gains, so the goal is to set the fees as high as possible without penalizing volume. Using this framework, we created a number of simulations to demonstrate how changing the static and dynamic fees impact liquidity provider gains.
Introduction
In Minswap V2, there will be two components of the total fee charged to traders: base fee and volatility fee. The base fee is the standard fee used by most decentralized exchanges (DEXs) that is a percentage of the order size. The volatility fee will be the focus of the article.
Base fee will vary with pool type. Stable pools may have a 0.05% base fee. Other pools may have a 0.3% or 1% base fee or something else. Base fee is configurable by agreement of liquidity providers. This is true about fixed fees as well. You could choose to have a fixed fee that is different from the current 0.3% fixed fee. Details around how liquidity providers adjust fees will be released at a later time by Minswap Labs.
Volatility fee will be based on a parameterized formula using an exponentially weighted normalized price volatility captured from unevenly spaced swap data.
Size fee would have been based on the calculated impermanent loss (IL) due to the size of a swap and how much it impacts the pool’s price. However, as you will see later, we decided not to pursue a size fee at this time.
The below formula is one suggested approach based on research by Marco and Elder Millennial. Minswap V2 allows us to implement this formula, or other, more complex ones as well. It will all be managed by Liquidity Providers themselves.
Volatility Fee
In a perfect world we would have deep options markets on all tokens and would be able to use the Implied Volatility (the market price of volatility) of each token. However, we do not have that luxury. So we will have to use historical data. We want most recent swaps and price movements to impact the volatility fee more than swaps and price movements from months ago.
Luckily, using an exponentially weighted scheme does exactly that. We can set the decay factor to have a short half-life/center of mass so the most recent data is much more impactful than data more in the past. Half-life and center of mass could be loosely explained as the time period where over half of the weight of the calculation is at that moment or before. For example, say you had 30 days of price data and used a center of mass of 7 days. That would roughly mean that 50% of the exponentially weighted standard deviation (or exponentially weighted mean) is explained by the previous week, and the other 50% is explained by days 8 to 30. The shorter the half-life or center of mass, the more weight you put on most recent observations.
The below formula accounts for the fact that the prices are not evenly spaced in time, so the price and price squared are adjusted for that fact plus the decay factor includes the delta between the current and previous observations.
We found that we could simplify the calculation of using price returns by instead using the idea of price volatility divided by the mean of the price. This we call normalized price volatility (some call it coefficient of variation) and it was highly correlated to other models we tried to test that tended to be more complex and ultimately unnecessary.
Where
Once we get the exponentially weighted normalized price volatility, we plug that into our volatility fee formula.
Where
We need to optimize these functions on 3 parameters: decay (or half-life), volatility scale, base fee in addition to choosing an update frequency.
The process will globally choose an update frequency such as every hour. So every 1 hour, we will calculate the new price of the pool. We will use that new price relative to the old price, along with the time difference to update the exponentially weighted price and price squared. After getting the new updated exponentially weighted normalized price volatility, we will use that as an input to the volatility fee and update the volatility fee. That volatility fee will be used for the next 1 hour until the update occurs again.
Here is an example of the fees for ADA/DJED. We set the halflife to 20 minutes, vol_scalar to 100 and base fee to 100. Then we plot what the total fee (base plus volatility) looks like using historical data.
And here is SNEK, using the same parameters but a different back test period.
Size Fee
We found that using just price volatility as an input was correlated to using IL as an input. Price volatility recaptures a good amount of the IL through the volatility fee. Therefore, for this iteration of the formula, we didn’t contemplate including a size fee.
Total Dynamic Fee
After we calculate the volatility fee, we can calculate the total fee.
We then limit the total fee to min(calculated total fee, 20%).
Parameter Setting and Testing
We looked at 2 dimensions of tokens: high versus low liquidity concentration on Minswap versus other DEXes; and high versus low volume of the token.
We gathered all of the swap history across multiple dexes and then assumed all swaps went through the swap splitting algorithm to maximize their received tokens (which would account for high dynamic fees on Minswap and swap less or not at all through Minswap).
Our objective function was to maximize the LP gain.
This gain measures the growth of an LP position over time, since all fees are kept inside the LP (except for the DAO fee Minswap DAO takes). If we can maximize the gain, we would be balancing two offsetting factors: the desire for LPs to charge higher fees, and the desire for traders to want lower fees. We want to maximize LP profitability while not deterring traders from trading through Minswap. This is why we decided to assume all traders go through a DEX aggregator. Traders are trying to maximize the amount of tokens they receive, after slippage and fees. For these simulations, the Steelswap swap splitting engine created by Elder Millennial was used. A simple grid search algorithm was used to find the optimal set of fees parameters that maximized LP returns.
We then ran through all of the swap history for the below pairs using different combinations of parameters: base fee, volatility scalar, decay. We captured the total gain for 3 different months using all combinations of parameters. Then we ranked the top 20 by gain. You can see the parameter ranges and gain ranges in the 3 tables in Appendix A. Each table is a different month that was back tested and shows different optimized parameterizations per pool based on the month. The months were chosen so there was a low volatile month, high volatile month with meme prices skyrocketing, and something in the middle.
What we found was that the parameterization can be quite different per pool. Likely it makes sense to run this type of analysis for key pools, and likely rerun over time to re-optimize the parameters.
Note that the data is in Appendix A.
Also an additional note on backtesting. This assumes all swaps occur regardless of the fee. The swaps will just choose the best DEX for the swapper. It’s important to note that pools with high concentration on Minswap will likely show extremely high optimized fees. This is because even with the high fee, the slippage on other DEXs could be higher. So, as with all back tests, please take the results with a grain of salt. We assumed all swaps occur. But in reality some swaps would likely not occur if the fees are too high because a trader might not make a trade, especially for dynamic fees that will mean revert over time. Additionally, we don’t actually apply the trades. Meaning we calculate what the ideal trade would be, but we don’t actually execute it, in the simulations. The significance of this is that we don’t change the liquidity of the pools. Remember that history is just one of many paths.
Static Fees Optimized
Appendix B shows the optimized static fee for each pool using the same logic used for dynamic fees. It’s extremely interesting and intuitive to see that all of the optimized static fees are much higher than the 30 (30=0.3%) currently charged by the DEX. These static fees tend to be over 1% for most of the pools tested. It’s important to note that the optimized fee is not only different per pool, but also different per month.
In addition, all of the gain measurements with the optimized fee are higher than the baseline 0.3% gain fee. So we can state that our optimized fee performed better in the backtest.
Technical Implementation
Dynamic Fees are a novel and exciting innovation, but it is important to note that the adoption of dynamic fees on a pool in Minswap V2 will only be decided on by liquidity providers. Whether they’re implemented or not and how they’re implemented will have to be voted on by LPs on an LP voting dashboard. We are still finalizing the logic around the voting and how the dashboard will function. But we have a clear idea of how Dynamic Fees can be implemented by LPs.
In each each Liquidity Pool, there will be a flag that the Pool Dynamic Fee Updater can enable or disable. If it’s enabled, the batcher can decide (based on the formula) the volatility fee for each time it executes a batch transaction. The volatility fee will be calculated on the off-chain code. The Dynamic Fee flag is a part of Pool parameters. LP Holders of each Pool decide whether they need Volatile Fee or not.
Here are some of the roles involved in the Dynamic Fee process:
- Batcher: processes the orders and add the Vol Fee for a pool if the Vol Fee is turned on by Pool Dynamic Fee Updater.
- Pool Fee Updater: can update the base fee of the liquidity pool. This will be LPs through the voting dashboard.
- Pool Dynamic Fee Updater: who can enable Volatility Fee of the Liquidity Pool. This will be LPs through the voting dashboard.
Conclusion
Dynamic fees are an extremely useful tool and our formulation of them is unique across crypto, inspired by traditional market makers. The key is to limit the amount of parameters needed to be optimized but also to balance the function so it’s not too simple. We think dynamic fees will be key to increasing LP profitability while also not being too punitive on traders across the ecosystem. The future likely will lead to more traders using DEX aggregators so we need to balance LP profitability with attractive all in fees for traders. This may mean lower base fees and higher volatility fees over time, as the elasticity of trading is high during periods of low volatility and low during periods of high volatility (people want to take profits and cut losses regardless of fees when volatility is high).
The key will be finding ways to optimize the parameters to balance this trade off, and adjusting pool parameters over time. If LPs agree to change a pool fee, the fee can change. We would argue it will make sense to test these fee changes out in the wild, and likely will require LPs to change over time, especially as the competitive landscape evolves.
Teams looking to deploy POL and control a majority of their LP tokens should contact Minswap to help optimize their LP fees. Our research shows that the base fee of Minswap of 0.3% is too low. Our default recommendation is 0.6%-0.75% for a base fee, 15 for a volatility scalar, and 1200 for the decay. A token that has higher volatility will likely want a lower base fee and a higher volatility scalar. A token that has higher concentration on Minswap (1 DEX) will likely be able to increase the base fee.
We highly recommend teams reaching out to discuss parameterization of dynamic fees.
Appendix A
All data is in the below form. The “Min” is the 20th ranked result by gain, and the “Max” is the top result ranked by gain. The idea here is to try and show a range of parameters that were optimal per pool per month. If we just focused on the “best” parameter combination, we may be over indexing to a corner solution on a specific day in a specific state of the ecosystem. These ranges are really here to give you an idea that the optimal parameters can really differ not only per pool, but per environment.
The best way to read this is to pick a pool, like ADA-DJED. In June with 0.3% fee, the non-annualized gain was 3.19%. This means if you zap 10,000 ADA into the ADA-DJED pool, you would end with a total value of 10,319 ADA (assuming the price at the end of the month was the same as the beginning). We could more than double the gain to over 7% by turning on dynamic fees with the following parameters: base fee between 1.03% and 1.11%, vol_scalar between 10 and 14, and decay between 2220 and 2700 seconds (30 to 45 minutes). In September we could increase the gain by 50% by setting base fee between 0.73% and 0.77%, vol_scalar between 13 and 21 and the decay time between 120 and 200 seconds (2 to 5 minutes). The gain and parameter settings for December were somewhere in between June and September.
The above example shows how different the parameters on just 1 pool can be based on a different trading environment. This is why we would recommend LPs potentially outsourcing these decisions to experts. Or at least getting some consultation on parameter settings from us.
Inside the graphic, the data meaning is below
[Base_fee low — Base_fee high], [vol_scale low — vol_scale high], [decay low — decay high] | [gain low — gain high].
June
September
December
Appendix B
All data is in the below form. The “Min” is the 20th ranked result by gain, and the “Max” is the top result ranked by gain.
[Base_fee low — Base_fee high] | [gain low — gain high].