Uniswap v3 LP Simulator

Backtest a concentrated-liquidity position against a real pool's own swap volume
Position composition
Model & assumptions

The position maths is exact Uniswap v3. Liquidity L is solved from your USD size at the entry price, then balances follow x = L(1/√P − 1/√Pb) and y = L(√P − √Pa), clamped at the range edges. Position value, impermanent loss and final token composition are exact for the given price path.

Volume and fees are real; only the liquidity split is modelled. Candles come from GeckoTerminal for the exact pool address you enter, so the swap volume, the fee tier and the current TVL are the pool's own numbers. Two things still have to be assumed:

  • Pool volume — real, per candle, straight from the pool. Nothing is scaled or estimated.
  • Competing liquidity — no public API exposes the tick-by-tick liquidity curve, so the rest of the pool's TVL is modelled as one position spanning ±c around spot, giving L_pool = TVL / (2√P · (1 − (1+c)−1/2)). Your cut each candle is L / (L + L_pool).
  • Time in range — inside a candle the price is assumed uniformly distributed between low and high, so a candle straddling one of your bounds earns a partial fraction rather than all-or-nothing.

Fees accrue in USD and are not compounded back into the position — matching Uniswap v3, where fees sit outside the position until collected. No gas costs, no rebalancing, and no price impact from your own size.

Calibrating. One knob is left: the concentration width. Tune it by reading the pool's actual fee APR for a known range and adjusting until the simulator agrees — the setting then carries across ranges and sizes. Note that TVL is read live, so a backtest over a window where the pool's TVL was very different will be off by roughly that ratio. Over a two-week window that is usually minor.

Daily data