Rangefinder, LP range and capital backtests
API docs
Two studies on replayed state: a range backtest that ranks range widths by fees minus divergence loss and gas, and a depth curve that shows how much of a pair's volume and fees added capital would capture.
Base URL https://llens.abanchev.com/api/v1. Authentication, deadlines, metering and errors are on Getting started. See the Rangefinder live demo.
Example values are illustrative. Token addresses are real Base contracts; amounts are raw integer units as decimal strings.
/api/v1/ext/market/lp-researchRange backtest
Forks a concentrated pool at a block you pin in the last 14 days, replays every swap of the horizon after it, and ranks your candidate range widths by fees minus divergence loss and gas.
- Cost
- 50 CU
- Headers
- Send your key in x-api-key.
| Body | Required | Description |
|---|---|---|
| chainId | yes | 8453 (Base) or 146 (Sonic). |
| pool | yes | A concentrated pool. |
| block | yes | The block to fork at, within the 14-day window. |
| halfWidthsBps | yes | 1 to 12 distinct range half-widths in bps. |
| horizonHours | yes | Hours after the block, at most 336. |
| capitalUsd | yes | Capital per range. |
| gasUsdPerAction | no | USD per position transaction; two are charged. |
The answer is a task id. Poll /ext/market/research-task for the ranked result.
curl -s -X POST "https://llens.abanchev.com/api/v1/ext/market/lp-research" \
-H "x-api-key: $LL_API_KEY" \
-H "content-type: application/json" \
-d '{"chainId":"8453","pool":"0xd0b53d9277642d899df5c87a3966a349a798f224","block":"52870000","halfWidthsBps":[50,100,250,500],"horizonHours":24,"capitalUsd":"250000","gasUsdPerAction":"0.05"}'{
"taskId": "3f8f6a52-6f0e-4d2b-9a43-1b2c3d4e5f60",
"status": "queued",
"cached": false,
"attachedToTaskId": null
}/api/v1/ext/market/depth-curveDepth-threshold curve
For each capital amount: the pool's share of the pair's routed volume and fees, the increase over today, and your capital's share of those fees, routed by the production router over every pool of the pair.
- Cost
- 50 CU
- Headers
- Send your key in x-api-key.
| Body | Required | Description |
|---|---|---|
| chainId | yes | 8453 (Base) or 146 (Sonic). |
| pool | yes | Pool to add capital to. |
| capitalUsd | yes | 1 to 8 distinct capital points. |
| block | no | Defaults to the previous full hour. |
| windowHours | no | Trade window, at most 336 (the default). |
| rangeHalfWidthBps | no | Concentrated pools: the added position's half-width (100 by default). |
| fullRange | no | Concentrated pools: add the position over the widest usable ticks instead of a half-width. |
| flow | no | all (default) routes every trade of the window; aggregator routes only aggregator transactions. |
curl -s -X POST "https://llens.abanchev.com/api/v1/ext/market/depth-curve" \
-H "x-api-key: $LL_API_KEY" \
-H "content-type: application/json" \
-d '{"chainId":"8453","pool":"0xcdac0d6c6c59727a65f871236188350531885c43","capitalUsd":["250000","1000000","5000000"],"windowHours":168}'{
"taskId": "3f8f6a52-6f0e-4d2b-9a43-1b2c3d4e5f60",
"status": "queued",
"cached": false,
"attachedToTaskId": null
}/api/v1/ext/market/research-taskTask status and result
Status, progress and result of this key's own range backtest or depth curve.
- Cost
- 50 CU
- Headers
- Send your key in x-api-key.
| Query | Required | Description |
|---|---|---|
| taskId | yes | The id the enqueue call returned. |
Abridged: two ranges and two method lines of each kind shown. A depth-curve result has the same envelope; see the next example.
curl -s "https://llens.abanchev.com/api/v1/ext/market/research-task?taskId=3f8f6a52-6f0e-4d2b-9a43-1b2c3d4e5f60" \
-H "x-api-key: $LL_API_KEY"{
"taskId": "3f8f6a52-6f0e-4d2b-9a43-1b2c3d4e5f60",
"taskType": "ranges",
"status": "succeeded",
"progressPct": 100,
"progressMessage": null,
"errorCode": null,
"errorMessage": null,
"result": {
"kind": "ranges",
"chainId": "8453",
"pool": "0xd0b53d9277642d899df5c87a3966a349a798f224",
"family": "UniV3",
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"decimals0": 18,
"decimals1": 6,
"tickSpacing": 10,
"pin": {
"requestedBlock": "52870000",
"forkBlock": "52869998",
"forkBlockHash": "0x2a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3f5b7d9a2c4e6f8b0d1a3c5e7f9b2d4a6c",
"forkTimestamp": "1792319755"
},
"window": {
"fromBlock": "52869999",
"toBlock": "52913199",
"fromHour": "2026-10-18T07:00:00.000Z",
"toHour": "2026-10-19T07:00:00.000Z",
"horizonHours": 24,
"replayedHours": 22,
"modelledHours": 2,
"missingHours": 0,
"swapsReplayed": 9412
},
"capitalUsd": "250000",
"prices": {
"token0Usd": "2604.18",
"token1Usd": "1",
"source": "engine-one-token-sell-reference-at-fork"
},
"feeModel": {
"swapFeeSources": {
"eventFee": 0,
"forkStaticFee": 9412,
"hourlyReplayEffectiveFee": 0,
"forkCurrentFee": 0
},
"hourlyFeeModels": [
"concentrated-replay"
],
"hoursWithoutExactFees": 0,
"protocolShare": "not-subtracted: gross swap fees, as market-stats reports them"
},
"costs": {
"strategy": "static-range-over-the-horizon",
"gasUsdPerAction": "0.05",
"actions": 2,
"lvrMethod": "divergence-loss-at-window-end"
},
"method": {
"exact": [
"price path: each journal swap's own sqrtPriceX96, replayed in block and log order; each swap starts where the previous one left the price",
"position math: TickMath.getSqrtRatioAtTick and SqrtPriceMath amount deltas (bigint, bit-identical to the engine's JSBI) with the contract's roundings"
],
"modelled": [
"the added position does not change the price path or the order flow (fixed-path, fixed-flow backtest): each swap's fee is shared L / (L + the fork's active liquidity), in replayed and M3-only hours alike",
"costs: two position transactions at the caller's gas price; divergence loss at the window end valued at the end price (LVR is not estimated separately)"
]
},
"ranges": [
{
"rank": 1,
"halfWidthBps": 250,
"tickLower": -197870,
"tickUpper": -197370,
"liquidity": "5824410211907731",
"amount0": "47200000000000000000",
"amount1": "127083441902",
"fees0": "39210440177301248",
"fees1": "104118230",
"feesUsd": "206.229718",
"replayedFeesUsd": "188.904121",
"modelledFeesUsd": "17.325597",
"swapsInRange": 9412,
"exits": 0,
"liquidityShareAtFork": "0.014211",
"divergenceLossUsd": "61.443008",
"gasUsd": "0.100000",
"netUsd": "144.686710"
},
{
"rank": 2,
"halfWidthBps": 100,
"tickLower": -197720,
"tickUpper": -197520,
"liquidity": "14420117301884210",
"amount0": "47100000000000000000",
"amount1": "127341220910",
"fees0": "62110904771230208",
"fees1": "171223904",
"feesUsd": "332.969201",
"replayedFeesUsd": "301.110442",
"modelledFeesUsd": "31.858759",
"swapsInRange": 7930,
"exits": 3,
"liquidityShareAtFork": "0.034402",
"divergenceLossUsd": "214.118702",
"gasUsd": "0.100000",
"netUsd": "118.750499"
}
]
}
}/api/v1/ext/market/research-taskA depth-curve result
The capital-0 baseline and each capital point, with the trade window and size buckets behind them.
- Cost
- 50 CU
- Headers
- Send your key in x-api-key.
curl -s "https://llens.abanchev.com/api/v1/ext/market/research-task?taskId=8c21d0e4-5b7a-4f19-b3e2-7d6a9c0f1e28" \
-H "x-api-key: $LL_API_KEY"{
"taskId": "8c21d0e4-5b7a-4f19-b3e2-7d6a9c0f1e28",
"taskType": "depth-curve",
"status": "succeeded",
"progressPct": 100,
"progressMessage": null,
"errorCode": null,
"errorMessage": null,
"result": {
"kind": "depth-curve",
"chainId": "8453",
"pool": "0xcdac0d6c6c59727a65f871236188350531885c43",
"family": "UniV2",
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"decimals0": 18,
"decimals1": 6,
"pin": {
"requestedBlock": "52912199",
"forkBlock": "52912191",
"forkBlockHash": "0x2a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3f5b7d9a2c4e6f8b0d1a3c5e7f9b2d4a6c",
"forkTimestamp": "1792319755",
"routingRule": "before-newest-pair-swap"
},
"window": {
"fromHour": "2026-10-12T13:00:00.000Z",
"toHour": "2026-10-19T13:00:00.000Z",
"windowHours": 168,
"journalHours": 24,
"hourlyRowHours": 144,
"missingHours": 0,
"trades": 284112,
"routedVolumeShare": "0.987412"
},
"prices": {
"token0Usd": "2604.18",
"token1Usd": "1",
"source": "engine-one-token-sell-reference-at-fork"
},
"rangeHalfWidthBps": 100,
"buckets": [
{
"tokenIn": "0x4200000000000000000000000000000000000006",
"tokenOut": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"amountIn": "4096000000000000000",
"trades": 18233,
"volumeIn": "74682368000000000000000"
}
],
"pairPools": [
{
"pool": "0xcdac0d6c6c59727a65f871236188350531885c43",
"dex": "Aerodrome v2",
"family": "solidly-v2",
"token0": "0x4200000000000000000000000000000000000006",
"token1": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"decimals0": 18,
"decimals1": 6,
"feeModel": {
"kind": "static",
"feeZeroToOneBps": "30",
"feeOneToZeroBps": "30",
"reason": null
},
"reserves": {
"amount0": "803311902117480263680",
"amount1": "2103418877410"
},
"inRange": [
{
"bandBps": 10,
"amount0": "401455890211304448",
"amount1": "1051446918"
},
{
"bandBps": 50,
"amount0": "2003788201117392896",
"amount1": "5251972011"
},
{
"bandBps": 100,
"amount0": "3994613190027460608",
"amount1": "10490762018"
}
],
"unavailable": null,
"fees7d": {
"fees0": "2914002711840092160",
"fees1": "7630127440",
"swaps": 3922,
"computedHours": 168,
"from": "2026-10-12T14:00:00.000Z"
}
}
],
"unavailable": null,
"baseline": {
"capitalUsd": "0",
"depth": "0",
"added": {
"amount0": "0",
"amount1": "0",
"liquidity": null,
"tickLower": null,
"tickUpper": null
},
"volumeShare": "0.021904",
"poolVolumeUsd": "6470779.003333",
"poolFeesUsd": "19412.337010",
"poolFeesPerDayUsd": "2773.191001",
"incrementalPoolFeesUsd": "0.000000",
"capitalFeeShare": "0.000000",
"capitalFeesUsd": "0.000000",
"capitalFeesPerDayUsd": "0.000000",
"unroutedBuckets": 0
},
"points": [
{
"capitalUsd": "250000",
"depth": "250000000000",
"added": {
"amount0": "48001234117201920000",
"amount1": "125000000000",
"liquidity": null,
"tickLower": null,
"tickUpper": null
},
"volumeShare": "0.024411",
"poolVolumeUsd": "7211003.048000",
"poolFeesUsd": "21633.009144",
"poolFeesPerDayUsd": "3090.429878",
"incrementalPoolFeesUsd": "2220.672134",
"capitalFeeShare": "0.056121",
"capitalFeesUsd": "1214.072401",
"capitalFeesPerDayUsd": "173.438914",
"unroutedBuckets": 0
},
{
"capitalUsd": "1000000",
"depth": "1000000000000",
"added": {
"amount0": "192004936468807680000",
"amount1": "500000000000",
"liquidity": null,
"tickLower": null,
"tickUpper": null
},
"volumeShare": "0.031870",
"poolVolumeUsd": "9414372.735000",
"poolFeesUsd": "28243.118205",
"poolFeesPerDayUsd": "4034.731172",
"incrementalPoolFeesUsd": "8830.781195",
"capitalFeeShare": "0.192047",
"capitalFeesUsd": "5424.006012",
"capitalFeesPerDayUsd": "774.858002",
"unroutedBuckets": 0
}
],
"method": {
"exact": [
"router: routeV33 over the oracle's relevant-pool selection, the pool always included, the production router",
"pool fees: the router's own leg fees"
],
"modelled": [
"one routing state for the whole window's size distribution (the trades did not all meet that state)",
"the new capital's share of the pool's fees: its share of active liquidity (concentrated) or of reserves (v2) at the routing state"
]
}
}
}