We’ve completed the major portion of our simulation code, and wanted to share some results and go over interpretation. We’ve attempted to develop metrics that capture the major advantages and risks of adjusting the A & fee parameters, and would love to hear your feedback/suggestions. Code: https://github.com/nagakingg/CurveSim
The code takes price and volume time series as inputs and simulates optimal arbitrageurs trading against a Curve pool over time. Here, we’ve used volume-weighted averaged prices across major CEXs and DEXs for the last 2 months at 30 minute intervals. 30 minute data provided approximately the same results as 5 minute data.
At each timestamp, the arbitrageur determines the set of trades (up to 1 trade per pair) that minimizes the squared error between the external market price and the resultant pool price after their trade. Following the StableSwap white paper, trade sizes are limited by the market volume for each coin pair at each time point. To approximate realistic market conditions, we initiate the pool with the current (actual) pool size, and use the “vol_mult” argument to limit trade volume based on the expected proportion of market volume that goes through Curve (e.g., monthly pool volume / monthly price feed volume). For each simulation, the pool begins fully balanced.
Metrics and Results
To illustrate the metrics used, it is best to look at some results and describe them. We present results for 3pool and explain the metrics below, focusing first only on the A parameter, with fees fixed at 0.04%.
Fig. 1, summary results:
Fig. 2, detailed results:
Annualized returns are estimated using the mean log returns (i.e., ln(pool_value(t)) - ln(pool_value(t-1)), in dollars, for each time stamp), which are then annualized and exponentiated to give an estimate of the annual exponential trend. Notably, results tend to be in a similar range, but slightly lower, than actual returns, which makes sense given that the simulations don’t include “random” non-arbitrage trades.
Cost of .05% Slippage
Increasing A generally decreases slippage, but carries the risk of increasing slippage if the pool gets “stuck” in an off-balance state where the bonding curve rapidly steepens. To estimate slippage risk, we calculated the cost (proportion of pool) required for a trade to produce .05% slippage at each time point (Fig. 2, “slippage cost”). Higher values indicate that the pool is more resistant to slippage. In Figure 1, we show the median and minimum of each time series to summarize the time series for this metric.
To produce a summary metric for pool balance, we use 1 - sum(abs(xp/sum(xp) - 1/n))/(2*(n-1)/n), where xp is a vector of the pools holdings for each type of coin, and n is the number of coins. This is essentially one minus the summed absolute deviation from perfect balance, scaled so that perfect balance is 1 and complete imbalance (all coins held in one currency) is 0. Time series are given in Figure 2, and the medians and minimums of those time series are shown in Figure 1.
To examine how changing A affects volatility in the pool’s holdings, we estimated the extent to which changing A “scales” the log returns. Typically, under the assumptions of geometric Brownian motion (e.g., in Black-Scholes), volatility is estimated using the standard deviation of the log returns. However, as previously observed in other assets, we found that the returns and log-returns distributions were more long-tailed than Gaussian.
Here, to avoid making any assumptions about the noise distribution of the log returns, we exploit the fact that variations in the pool value – and therefore the log returns – are highly correlated with variations in the value of a portfolio just “holding” the original coin balance (see Fig. 2, middle and lower left). We therefore characterize the volatility by simply examining how the log-returns “scale” relative to simply holding. To calculate this, we estimate the slope of the log returns when holding versus the log returns of the pool (see Fig. 2, lower left). We use scipy.stats.siegelslopes for a non-parametric estimate based on median slopes.
For each time-point, we recorded the sum of the absolute differences between the pool’s exchange rate and the external market price for each coin pair (after each arbitrage trade). This allows us to (a) verify that the arbitrage is working properly, and (b) to identify cases where the arbitrageurs don’t have enough capital (i.e., there is not enough volume) to fully arbitrage out price differences. Figure 1 shows the median of the summed absolute error over time. Figure 2 (lower right) shows histograms for each A value. We note that some price error is unavoidable because trading one pair influences pricing for all other pairs including one of the same coins, so perfect arbitrage is often not possible.
Incorporating Fees as an Additional Variable
We performed the same analyses but with fees as an additional variable.
Discussion of Results
Interestingly, our results suggest that, in the case of 3pool, raising A generally increases profits with few directly observable negative side effects. Raising A to even quite high values (>1000) did not radically reduce the pool’s balance or generate additional susceptibility to slippage. Also, interestingly, increasing A reduced volatility in the pool’s value (in USD), presumably because larger arbitrage trades offset volatility produced by short-term variability in individual coin prices.
However, this interpretation should be hedged by the fact that the potential risks of pool imbalance are not fully captured by our simulations. First, pool imbalance increases potential risk/inconvenience to LPs who may want/need to withdraw in a particular currency at an arbitrary time. Second, if arbitrage capital dries up, it is possible that the pool can stay in a prolonged state of imbalance, increasing the risk of intermittent entry into high-slippage regions (the “shoulders”) of the bonding curve. Third, because the simulations only include arbitrage trades, they only indirectly assess the risk of random non-strategic trades creating more volatility or slippage. These risks are somewhat mitigated in the case of 3pool, because the pool is very large and consists of very popular (high float) coins, but should probably always be considered for each pool.
Our sense is that, because there are known risks of imbalance which increase with higher A, but whose magnitude may be underestimated by the simulations, it is sensible to identify a “point of diminishing returns,” where the annualized profit is approaching its maximum, but increasing it more would only bring modest gains. In these simulations, such a point appears to be in the range of A = 727 to 1448. Here, the positive effects of increased A on both annualized returns and (minimum) slippage cost begin to saturate, indicating there is probably little gain to raising A above these values. Moreover, the pool balance is reasonable at these values, given the rough criteria that balance <.5 is very bad, and >.75 is desirable. The balance time series are indicative here as well: for these A values, the balance shifts around quite “smoothly” with somewhat attenuated “shocks” in balance.
Finally, fees appear to be optimal at their current setting of .04%, or potentially .03%. We note that the simulations do not include gas fees, which may influence trader behavior with respect to fees.
We thank michwill and jiecut for their helpful comments on interpretation.
- We are currently working on extending the simulator to meta-pools
- We are developing a webpage which will show these graphs for each pool, updating nightly
- Results for BUSD and SETH pools will be posted in the comments below
- We used data from nomics.com paid API. Code available on GitHub. We will add code so users can also try out CoinGecko API in the near future