Uniswap v3 untuk Quant: Kecairan Tertumpu dan Matematik Tick dari Prinsip Asas
Kedudukan LP di Uniswap v3 sebenarnya adalah pesanan julat buku pesanan had (limit-order-book) yang menyamar. Depositkan kecairan antara dua harga dan anda telah berjanji untuk membeli aset semasa harga turun melalui julat anda dan menjualnya semasa harga naik — persis apa yang dilakukan oleh satu grid pesanan had yang menunggu (resting limit orders) pada CLOB. Tetapi kontrak tidak menyimpan harga, kuantiti, atau buku pesanan. Ia menyimpan tiga nombor: punca kuasa dua harga dalam titik tetap Q64.96, indeks tick integer, dan nilai kecairan agregat . Jika anda mahu menaakul kedudukan v3 sebagaimana anda menaakul sebut harga dalam model pembuatan pasaran — inventori, harga isian, pemilihan lawan — anda perlu dapat menterjemah antara primitif on-chain tersebut dengan konsep dagangan yang diwakilinya. Artikel ini membina terjemahan itu dari prinsip asas, mengikuti kertas putih Uniswap v3 (Adams, Zinsmeister, Salem, Keefer, Robinson, 2021) serta kontrak terasnya, dan berakhir di tempat setiap perbincangan LP yang serius kini bermula: loss-versus-rebalancing.
Dari x·y = k kepada rizab maya
Uniswap v2 ialah pembuat pasaran produk-tetap (constant-product): satu pool memegang rizab token0 dan token1 serta menguatkuasakan
pada setiap swap. Harga marginal token0 dalam unit token1 ialah , dan kecairan tersebar secara seragam sepanjang keseluruhan paksi harga . Itu amat tidak cekap dari segi modal: pasangan stablecoin yang berdagang antara 0.999 dan 1.001 mengekalkan lebih 99% modalnya pada harga yang tidak akan pernah tercetak.
Langkah v3 ialah membenarkan setiap LP menghadkan modal mereka kepada satu julat . Di dalam julat, kedudukan mesti berkelakuan persis seperti pool v2 — lengkung bonding sama, harga marginal sama — tetapi hanya menggunakan rizab yang diperlukan untuk meliputi julat tersebut. Kertas putih memformalkan ini dengan rizab maya: kedudukan bertindak seolah-olah ia memegang rizab bergaya v2 yang terletak pada lengkung , manakala rizab sebenar ialah rizab maya tolak apa yang kedudukan akan pegang pada sempadan julat:
Ini adalah persamaan 2.2 kertas putih, dan ia adalah persamaan tunggal paling penting dalam v3. Lengkung terjemahan ini menyentuh paksi: pada rizab sebenar menjadi sifar (kedudukan 100% token1), dan pada rizab sebenar menjadi sifar (100% token0). Di luar julat, kedudukan menjadi lengai — sekadar bag tetap satu token, tidak memperoleh apa-apa.

Parameter , dipanggil kecairan (liquidity), ialah invarian yang menggantikan . Ia ditakrifkan sebagai , dan mempunyai tafsiran bersih yang dinyatakan secara eksplisit oleh kertas putih: kecairan ialah "rizab maya bagi setiap unit punca kuasa dua harga". Pada mana-mana harga di dalam julat, rizab maya ialah
Mengapa pemboleh ubah keadaan ialah √P
Teras v3 tidak menjejaki harga. Ia menjejaki , disimpan sebagai sqrtPriceX96, satu nombor titik tetap Q64.96 tanpa tanda:
di mana ialah harga mentah: unit asas token1 bagi setiap unit asas token0, termasuk perpuluhan (lebih lanjut mengenai ini di bawah). Sebab punca kuasa dua digunakan bukanlah untuk penjimatan gas, tetapi kerana algebra. Bezakan identiti rizab maya dan anda akan memperoleh dua persamaan swap asas, dilaksanakan dalam pustaka SqrtPriceMath:
Kedua-dua delta token adalah linear terhadap punca kuasa dua harga (atau salingannya), dengan sebagai pemalar kadaran. Satu swap dalam satu tick oleh itu tidak memerlukan songsangan lengkung, tiada lelaran Newton — hanya satu pendaraban untuk menggerakkan , kemudian dua pendaraban untuk mengira amaun. Apabila satu swap cukup besar untuk menolak harga merentasi satu tick yang diaktifkan, pool tersebut melintasinya, menambah atau menolak kecairan bersih yang dirujuk di situ (liquidityNet), dan meneruskan dengan agregat yang baharu. Secara global, pool tersebut ialah satu AMM produk-tetap sekeping-demi-sekeping (piecewise-constant-product): tetap antara tick yang diaktifkan, melonjak pada tick.
Bagi seorang pembuat pasaran, inilah model mental yang betul: profil agregat pool adalah setara DEX kepada kedalaman buku pesanan (order-book depth). Jika kedalaman CLOB disebut dalam unit bagi setiap tahap harga, kedalaman AMM ialah bagi setiap tick — dan penukarannya adalah persis identiti di atas.
Tick: satu grid harga bersela-log
Julat tidak boleh bermula dan berakhir pada harga sewenang-wenangnya; ia mesti menyesuaikan diri pada tick. Tick sepadan dengan harga
jadi setiap tick berjarak satu mata asas (basis point) daripada jirannya — bukan dalam terma mutlak, tetapi terma relatif. Sela-log ini disengajakan: grid tambahan tetap akan menjadi terlalu kasar untuk token yang berdagang pada $0.0001 dan terlalu halus pada $100{,}000, manakala grid geometri memberikan resolusi 1 bp yang seragam pada setiap skala harga. Pustaka TickMath menukar kedua-dua arah — getSqrtRatioAtTick dan getTickAtSqrtRatio — menggunakan gerak bit atas pemalar yang dikira lebih awal berbanding memanggil fungsi eksponen. Indeks tick dibatasi oleh MIN_TICK = -887272 dan MAX_TICK = 887272, yang meliputi julat harga : cukup luas untuk mana-mana pasangan token yang boleh wujud dalam aritmetik uint256.
Bukan setiap tick boleh digunakan. Setiap tier fi mengenakan sela tick (tick spacing), dan kedudukan hanya boleh menggunakan tick yang boleh dibahagi olehnya:
| Tier fi | Sela tick | Lebar julat minimum | Penggunaan tipikal |
|---|---|---|---|
| 0.01% | 1 | ~1 bp | stabil/stabil |
| 0.05% | 10 | ~10 bp | pasangan stabil, ETH/stabil |
| 0.30% | 60 | ~60 bp | major |
| 1.00% | 200 | ~2% | eksotik / meruap |
Tier 0.05%/0.30%/1% dilancarkan pada pelancaran Mei 2021; tier 0.01% ditambah melalui undian tadbir urus pada November 2021. Sela yang lebih kasar pada pool berfi tinggi mengekalkan bilangan tick yang berpotensi dilintasi tetap rendah dan kos gas swap terbatas.
Satu perangkap perpuluhan yang mengenai setiap orang sekali: harga mentah on-chain ialah token1 bagi setiap token0 dalam unit asas. Dalam pool USDC/WETH mainnet, token0 ialah USDC (6 perpuluhan) dan token1 ialah WETH (18 perpuluhan), jadi harga manusia $3{,}000 bagi setiap ETH sepadan dengan harga mentah WETH-wei bagi setiap unit USDC, yang terletak pada tick
dengan . Jika papan pemuka pemantauan anda menunjukkan tick berhampiran 196k untuk USDC/WETH, kini anda tahu sebabnya — dan bahawa harga manusia ialah disongsangkan mengikut keperluan.
Amaun token daripada (L, julat harga): formula tepat
Hasil teras bahagian ini: diberi satu kedudukan dengan kecairan pada dan harga semasa , apakah yang dipegangnya? Mengintegrasikan persamaan swap merentasi julat memberikan tiga kes:
Harga di bawah julat () — kedudukan adalah 100% token0:
Harga di atas julat () — kedudukan adalah 100% token1:
Harga dalam julat ():
Ini adalah persis apa yang dikira oleh SqrtPriceMath.getAmount0Delta dan getAmount1Delta (dengan pembundaran terarah — kontrak sentiasa membundarkan menentang pengguna, satu perincian yang penting jika anda mereplikakan ini dalam pengesan-belakang (backtester) dan tertanya-tanya tentang percanggahan pada tahap wei).
from math import sqrt
def position_amounts(L: float, pa: float, pb: float, P: float):
"""Token amounts held by a v3 position (float model; core uses Q96 ints)."""
sa, sb, sp = sqrt(pa), sqrt(pb), sqrt(P)
if P <= pa:
return L * (1/sa - 1/sb), 0.0
if P >= pb:
return 0.0, L * (sb - sa)
return L * (1/sp - 1/sb), L * (sp - sa)
Contoh diselesaikan: ETH/USDC, julat [2500, 3500]
Anggap ETH berdagang pada USDC dan anda mahu mendeposit 1 ETH ke dalam julat . Punca kuasa dua: , , .
Kaki ETH menetapkan :
Kaki USDC kemudian mengikut:
Jadi mencetak kedudukan ini memerlukan 1 ETH + 3,523.69 USDC, nilai keseluruhan $6,523.69, dan perhatikan kaki-kaki tersebut tidak 50/50 — pembahagiannya bergantung pada di mana terletak dalam julat (satu julat asimetri adalah cara tepat untuk menyatakan pandangan berarah, atau meletakkan satu "pesanan julat" tulen dengan satu token sahaja).
Kini lalui harga ke sempadan:
- Pada kedudukan telah bertukar sepenuhnya kepada ETH: ETH, bernilai $5,716.68. Anda membeli 1.2867 ETH semasa harga turun pada purata wajaran-kecairan sebanyak 3523.69 / 1.2867 \approx \2{,}739$.
- Pada ia telah bertukar sepenuhnya kepada USDC: USDC. Anda menjual ETH anda semasa harga naik pada purata $3,240.
Itulah bacaan pesanan-julat yang menjadi konkrit: kedudukan tersebut adalah satu tangga bida dari 3000 turun ke 2500 dan tawaran dari 3000 naik ke 3500, dengan saiz bagi setiap tick berkadar dengan . Dan tumpuan itulah yang anda dibayar untuk: satu kedudukan bergaya v2 julat-penuh dengan modal $6,523.69 yang sama akan mempunyai — kedudukan tertumpu tersebut menyebut 12.4× lebih kedalaman bagi setiap tick, dan (semasa berada dalam julat) memperoleh fi pada kadar 12.4× bagi setiap dolar modal.
Perakaunan fi: feeGrowthGlobal dan feeGrowthInside
Fi v3 tidak berkompaun ke dalam kedudukan (satu pemecahan yang disengajakan daripada v2, di mana fi dilaburkan semula ke dalam ). Ia terakru secara berasingan, bagi setiap token, dan perakaunan tersebut merupakan satu bijak-mestika pembukuan O(1) kecil yang wajar difahami kerana setiap saluran analitik LP melaksanakan semula ini.
Pool tersebut mengekalkan dua pengakumulasi global, feeGrowthGlobal0X128 dan feeGrowthGlobal1X128: fi kumulatif bagi setiap unit kecairan sejak permulaan pool, dalam titik tetap Q128.128. Pada setiap swap, amaun fi (diambil daripada token input) dibahagikan dengan dalam-julat semasa dan ditambah kepada pengakumulasi tersebut. Ini adalah mekanisme di sebalik peraturan kardinal ekonomi v3: fi hanya terakru kepada kecairan yang berada dalam julat pada saat swap tersebut. Kedudukan luar-julat bukan sekadar inventori lengai — ia memperoleh tepat sifar semasa tidak aktif.
Untuk mengagihkan hirisan pertumbuhan global yang betul kepada satu julat terhingga, setiap tick yang diaktifkan menyimpan feeGrowthOutside0/1X128 — pertumbuhan fi yang berlaku pada sisi lain tick tersebut berbanding harga semasa (nilai ini bertukar tafsiran setiap kali tick tersebut dilintasi, dan itulah yang menjadikan skema ini O(1)). Kemudian bagi satu kedudukan pada dengan tick semasa :
Setiap kedudukan menyimpan satu snapshot feeGrowthInsideLast, dan fi yang belum dikumpul adalah sekadar
dikemas kini secara lengai apabila kedudukan tersebut disentuh. Dua akibat praktikal. Pertama, delta feeGrowthInside adalah satu-satunya cara jujur untuk mengukur pendapatan fi sesuatu kedudukan — mengambil sampel jumlah dagangan peringkat pool dan mempro-rata mengikut kongsi TVL anda akan tersilap setiap kali harga mengembara di sekitar sempadan julat anda. Kedua, kerana fi terletak sebagai tokensOwed dan bukannya berkompaun, pulangan LP terealisasi mempunyai satu terma seretan-tunai (cash-drag) yang v2 tidak ada; kubah pengkompaunan-automatik wujud tepat untuk mengarbitrajkan ini (tolak fi mereka sendiri).

Bayaran: satu straddle pendek yang anda dibayar untuk pegang (mungkin)
Di dalam julat, nilai kedudukan sebagai fungsi harga ialah
Cekung terhadap — terma itulah keseluruhan cerita. Di luar julat ia menjadi linear: cerun di bawah (anda panjang satu bag ETH tetap), cerun 0 di atas (anda rata dalam USDC). Jalankan contoh diselesaikan kita merentasi julat dan bandingkan dengan sekadar memegang token yang didepositkan:
| (USDC/ETH) | Nilai LP | Nilai HODL | Percanggahan |
|---|---|---|---|
| 2500 | 5,716.68 | 6,023.69 | −307.02 |
| 2750 | 6,200.4 | 6,273.69 | −73.3 |
| 3000 | 6,523.69 | 6,523.69 | 0 |
| 3250 | 6,706.3 | 6,773.69 | −67.4 |
| 3500 | 6,764.06 | 7,023.69 | −259.63 |
LP tersebut mengungguli kurang berbanding HODL dalam kedua-dua arah dan hanya menyamainya pada harga percetakan. Naik yang berplafon, penyertaan turun yang diperkuat, nilai relatif maksimum pada strike... inilah bayaran satu straddle pendek (lebih tepat, sebaik sahaja ekor linear dinetkan terhadap penanda aras HODL, satu kedudukan pendek dalam satu jalur opsyen yang di-strike merentasi ). Aliran fi ialah premiumnya. Menumpukan julat bermakna memilih strike yang lebih ketat: lebih banyak premium bagi setiap unit masa semasa dalam julat, percanggahan yang lebih pantas dan lebih dalam apabila harga bergerak. Setiap LP v3 ialah seorang peniaga volatiliti-pendek, sama ada mereka memilih untuk menjadi begitu atau tidak — saudara on-chain kepada trade-off risiko-inventori yang diformalkan oleh Avellaneda–Stoikov bagi pembuat pasaran buku pesanan, dengan lebar julat memainkan peranan spread yang disebut.

Nama tradisional bagi jurang dalam jadual tersebut ialah kerugian tidak-kekal (divergence), tetapi IL-berbanding-HODL ialah satu penanda aras yang cacat: ia mencampur-adukkan kerugian yang anda tanggung sebagai penyedia kecairan dengan risiko pasaran yang anda akan tanggung sebaliknya. Dekomposisi yang lebih tajam datang daripada Milionis, Moallemi, Roughgarden, dan Zhang (2022), "Automated Market Making and Loss-Versus-Rebalancing" (arXiv:2208.06046). Bandingkan LP bukan terhadap HODL tetapi terhadap satu portfolio pengimbangan semula yang memegang, pada setiap saat, kuantiti token yang sama seperti pool tersebut — tetapi berdagang pada harga pasaran luaran tanpa geseran dan bukannya menentang para arbitraj. Perbezaannya ialah LVR ("lever"): komponen P&L LP yang merupakan pemilihan lawan tulen, dibayar kepada para arbitraj yang mengutip sebut harga basi AMM selepas setiap pergerakan harga. Di bawah harga geometrik-Brownian dengan volatiliti , LVR terakru pada kadar seketika
— satu "formula Black–Scholes untuk AMM", seperti yang dinyatakan oleh penulisnya, dengan ialah kedalaman marginal pool pada harga semasa. Bagi pool produk-tetap julat-penuh, ini runtuh kepada nilai pool bagi setiap unit masa yang terkenal itu: pada volatiliti harian 5%, kira-kira 3.1 bp pool tersebut berdarah kepada para arbitraj setiap hari, ada fi atau tiada fi. Penumpuan menggandakan — contoh kedalaman 12.4× kita di atas juga merupakan sebuah mesin LVR ~12.4× semasa berada dalam julat. Fi mesti mengatasi pendarahan itu supaya kedudukan tersebut +EV, dan LVR (tidak seperti "IL") ialah satu kos berjalan yang boleh dilindung-nilai dan boleh diramal, dan itulah yang menjadikannya unit perakaunan yang betul. Kiraan keuntungan penuh — APR fi berbanding LVR berbanding volatiliti terealisasi, bila LPing mengatasi opsyen pendek yang dilindung-nilai delta — adalah subjek kajian mendalam kerugian tidak-kekal dan LVR yang akan datang, dan mekanik lindung nilai mendapat rawatannya sendiri dalam strategi LP v3 dan lindung nilai.
Satu lagi kos berada satu lapisan lebih dalam: kerana sebut harga AMM hanya dikemas kini apabila seseorang berdagang, setiap kedudukan LP juga terdedah kepada permainan mempool yang dimainkan di sekitar dagangan tersebut — serangan sandwic terhadap penswap yang membayar fi anda, dan bundel arbitraj yang merealisasikan LVR anda blok demi blok. Ekosistem itu dipetakan dalam artikel MEV dan serangan sandwic.
Membaca keadaan pool on-chain
Semua yang di atas boleh diperhatikan daripada tiga panggilan murah terhadap kontrak pool.
slot0() membungkus keadaan panas ke dalam satu slot storan: sqrtPriceX96, tick semasa, indeks pemerhatian orakel, dan bendera fi-protokol/kunci. liquidity() mengembalikan agregat dalam-julat semasa — perhatikan ini bukan TVL; ia ialah parameter kedalaman yang aktif pada tick semasa dan ia melonjak secara tidak selanjar apabila harga melintasi satu tick yang diaktifkan. ticks(int24) mengembalikan keadaan bagi setiap tick: liquidityGross (jumlah yang merujuk kepada tick tersebut), liquidityNet (nilai bertanda yang ditambah semasa melintasi dari kiri ke kanan), dan pengakumulasi feeGrowthOutside. Melelar liquidityNet merentasi tick yang diaktifkan (tickBitmap memberitahu anda tick mana yang wujud tanpa perlu mengimbas kesemua 1.7 juta) membina semula profil kedalaman penuh — snapshot buku pesanan anda.
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(RPC_URL))
pool = w3.eth.contract(address=POOL, abi=POOL_ABI) # USDC/WETH 0.05%
sqrt_price_x96, tick, *_ = pool.functions.slot0().call()
L = pool.functions.liquidity().call()
raw_price = (sqrt_price_x96 / 2**96) ** 2 # token1/token0, base units
eth_usdc = 1 / (raw_price * 10**(18 - 6)) # human USDC per ETH
depth_1tick = L * (1.0001**0.5 - 1) * (sqrt_price_x96 / 2**96)
Kedudukan itu sendiri wujud di dua tempat. Pool teras mengunci kunci kedudukan mengikut (owner, tickLower, tickUpper) — satu slot agregat bagi setiap triple pemilik-julat. Pengguna runcit dan kebanyakan dana sebaliknya mencetak melalui NonfungiblePositionManager periferi (mainnet: 0xC36442b4a4522E871399CD717aBDD847Ab11FE88), yang membungkus setiap kedudukan dalam satu NFT ERC-721 dan mendedahkan positions(tokenId) yang mengembalikan tuple penuh: token, tier fi, julat, , feeGrowthInsideLast, dan tokensOwed. Untuk pemantauan portfolio, satu panggilan itu ditambah feeGrowthInside semasa pool tersebut (dikira semula daripada ticks() seperti dalam bahagian sebelumnya) memberikan anda nilai mark-to-market dan fi terakru tanpa menyentuh sebarang pengindeks — walaupun untuk apa-apa yang bersifat sejarah anda akan memerlukan main semula peristiwa-swap atau satu subgraph, kerana pertumbuhan fi bergantung-laluan dan rantaian tersebut hanya menyimpan pengakumulasi semasa.
Dua perincian operasi yang wajar diinternalisasi sebelum menggunakan modal. Pertama, sela tick mengkuantumkan ruang strategi anda: pada tier 0.05% anda boleh meletakkan julat selebar 10-bp dan menjalankan sesuatu yang hampir menyerupai pesanan had tulen (cetak tepat di atas/bawah spot, kutip fi, bakar selepas ia dilintasi — kertas putih secara eksplisit merangka kes penggunaan "pesanan julat" ini), manakala pada tier 1% julat minimum anda ialah ~2% lebar dan analogi LOB menjadi kasar. Kedua, satu pesanan julat ialah satu pesanan had tanpa keutamaan pembatalan: jika harga melintasi julat anda dan kembali semula, anda pusing-balik inventori tersebut dan memberi balik kelebihan tersebut (sambil mengekalkan fi). Julat pasif ialah sebut harga yang tidak boleh anda tarik balik — dan itulah tepatnya sebab soalan kekerapan pengimbangan-semula, dan lensa LVR untuk menjawabnya, amat penting.
Ke mana ini membawa anda
Susunan v3, dimampatkan: harga ialah tick pada satu grid geometrik-1.0001; kedalaman ialah , boleh ditukar kepada amaun token dengan tidak lebih daripada perbezaan punca kuasa dua; fi ialah satu pengakumulasi bagi setiap- yang anda bezakan merentasi sempadan julat anda; dan kedudukan yang terhasil ialah satu pesanan julat volatiliti-pendek yang kos berjalannya mempunyai nama, formula, dan nombor arXiv. Dengan primitif ini di tangan, soalan yang menarik menjadi kuantitatif: seberapa lebar, berapa kerap untuk mengimbang semula, dan sama ada fi mengatasi LVR bagi sesuatu pool dan rejim tertentu — yang mana tepat di situlah siri ini akan menuju seterusnya.
Rujukan
- Adams, H., Zinsmeister, N., Salem, M., Keefer, R., Robinson, D. (2021). Uniswap v3 Core (kertas putih).
- Pustaka teras Uniswap v3:
TickMath.sol,SqrtPriceMath.sol,Position.sol,Tick.sol. - Milionis, J., Moallemi, C., Roughgarden, T., Zhang, A. L. (2022). Automated Market Making and Loss-Versus-Rebalancing. arXiv:2208.06046.
Pengarang
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.