> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Tick và vị trí

> Cách CLMM rời rạc hóa giá thành các tick, cách tick-arrays nén lưu trữ, và các quy tắc chi phối nơi một vị trí có thể tồn tại.

<Info>
  **Trang này được dịch tự động bằng AI. Phiên bản tiếng Anh là bản chính thức.**

  [Xem bản tiếng Anh →](/products/clmm/ticks-and-positions)
</Info>

## Tại sao tick tồn tại

Tính thanhtí của CLMM được tập trung vào các dải giá. Để làm cho các dải này dễ quản lý trên chuỗi, giá được lượng tử hóa thành các số nguyên **tick**, trong đó mỗi tick là một bội số hằng của cái trước:

$$
\text{price}(i) = 1.0001^{\,i}
$$

Một tick tương ứng với một bước giá 0,01%, hay khoảng 1 điểm cơ bản. Ánh xạ như sau:

| Chỉ số tick `i`      | Hệ số giá           |
| -------------------- | ------------------- |
| `0`                  | `1.0000`            |
| `100`                | `1.0100` (≈ +1.00%) |
| `-100`               | `0.9900` (≈ −0.99%) |
| `10000`              | `2.7181` (≈ e)      |
| `MAX_TICK = 443636`  | ≈ `1.84e19`         |
| `MIN_TICK = -443636` | ≈ `5.42e-20`        |

`MIN_TICK` và `MAX_TICK` được chọn sao cho `sqrt_price_x64` vừa trong một `u128` ở cả hai đầu. Mọi pool đều tuân thủ `tick_lower >= MIN_TICK` và `tick_upper <= MAX_TICK`. Trong thực tế, giao diện web sẽ giới hạn dải này một cách chặt chẽ hơn để ngăn người dùng khóa tính thanh khoản vào các tick không thể truy cập được.

## Khoảng cách tick

`AmmConfig` của một pool xác định **tick spacing** — các tick duy nhất mà một vị trí được phép sử dụng làm điểm cuối. Nếu `tick_spacing = 60`, chỉ các tick `…, −120, −60, 0, 60, 120, …` là hợp lệ. Một nỗ lực mở vị trí với điểm cuối `31` sẽ bị hoàn nguyên với `InvalidTickIndex`.

Các khoảng cách được công bố phổ biến:

| Tầng phí | `trade_fee_rate` | Tick spacing | Bước giá thô nhất trên mỗi vị trí tick |
| -------- | ---------------- | ------------ | -------------------------------------- |
| 0.01%    | `100`            | 1            | 0.01%                                  |
| 0.05%    | `500`            | 10           | 0.10%                                  |
| 0.25%    | `2500`           | 60           | 0.60%                                  |
| 1.00%    | `10000`          | 120          | 1.21%                                  |

Khoảng cách càng lớn, càng ít mảng tick cần khởi tạo, chi phí mở vị trí rộng càng thấp, và biên giá càng mờ. Các cặp biến động thường nằm ở các tầng 120-spacing; stablecoin nằm ở các tầng 1-spacing.

## Mảng tick

Pool không lưu trữ trạng thái mỗi tick trong các tài khoản riêng biệt. Thay vào đó, `TICK_ARRAY_SIZE` tick liền kề (60 trong Raydium CLMM hiện tại) được đóng gói thành một `TickArrayState` duy nhất. Tick đầu tiên của mảng là `start_tick_index` của nó, và nó bao phủ chính xác `TICK_ARRAY_SIZE * tick_spacing` đơn vị tick nguyên.

Đối với `tick_spacing = 60` và `TICK_ARRAY_SIZE = 60`:

* Mỗi mảng tick bao gồm `60 × 60 = 3600` tick nguyên.
* `start_tick_index` là bội số của 3600: `…, -7200, -3600, 0, 3600, 7200, …`.

Một điểm cuối vị trí `t = 2040` ở `tick_spacing = 60` nằm trong mảng tick có `start_tick_index = 0`. Một điểm cuối vị trí `t = 4200` nằm trong mảng có `start_tick_index = 3600`.

### Khi một mảng được tạo

Một mảng tick là lười biếng: **vị trí đầu tiên** tham chiếu bất kỳ tick nào trong nó sẽ khởi tạo mảng, trả tiền cho rent. Các swap không khởi tạo mảng tick — chúng bỏ qua các mảng chưa khởi tạo bằng cách sử dụng bitmap. Quy trình mở vị trí của SDK kiểm tra phạm vi được chọn, tính toán danh sách các mảng tick mà nó chạm vào, và thêm các hướng dẫn `init_tick_array` trong cùng một giao dịch với `OpenPosition` nếu có bất kỳ cái nào bị thiếu.

### Mảng tick không được đóng

Sau khi một mảng tick đã được khởi tạo, nó tồn tại suốt vòng đời của pool. Chương trình **không** cung cấp một cách để đóng mảng tick, thậm chí sau khi `initialized_tick_count` quay trở về không. Không có phục hồi rent cho mảng tick; tiền rent được trả bởi vị trí đầu tiên chạm vào một mảng bị khóa vào tài khoản đó vĩnh viễn. Đây là một sự cân bằng cố ý: tái sử dụng một mảng tick hiện có là miễn phí cho mọi vị trí tiếp theo, vì vậy một pool được giao dịch nhiều chỉ trả chi phí rent một lần cho mỗi slot `(pool, start_tick_index)` bất kể có bao nhiêu sự thay đổi.

### Bitmap

Việc tìm "tick được khởi tạo tiếp theo ở bên trái/phải của tick hiện tại" phải nhanh — một swap có thể vượt qua nhiều tick. Pool lưu trữ một bitmap 1-bit-trên-mỗi-mảng-tick trong `PoolState` cho phạm vi ±1,024 mảng xung quanh tick 0. Ngoài phạm vi đó (vị trí phạm vi đầy đủ, thiết lập exotic), `TickArrayBitmapExtension` cung cấp tràn.

Một swap bước đi qua bitmap: `lowest_set_bit_above(tick_current_array_index)` cho mảng tiếp theo có một tick được khởi tạo ở phía swap đang vượt qua. Trong mảng đó, một quét bit tương tự định vị tick được khởi tạo tiếp theo.

## `liquidity_gross` và `liquidity_net`

Mỗi tick **được khởi tạo** lưu trữ hai giá trị tính thanh khoản:

* **`liquidity_gross`** — tổng của `L` trên tất cả các vị trí tham chiếu tick này làm điểm cuối. Khi `liquidity_gross` đạt không, tick trở nên chưa khởi tạo và có thể bị loại bỏ khỏi bitmap.
* **`liquidity_net`** — *có dấu* thay đổi tính thanh khoản ở cấp độ pool khi giá vượt qua tick này **di chuyển lên** (từ trái sang phải trong không gian tick). Nếu tick này là giới hạn dưới của vị trí với kích thước `L`, nó đóng góp `+L`; nếu nó là giới hạn trên của vị trí đó, nó đóng góp `−L`.

Ví dụ cụ thể: hai vị trí trên cùng một pool.

* Vị trí A: `tick_lower = -120`, `tick_upper = 0`, tính thanh khoản `L_A = 100`.
* Vị trí B: `tick_lower = -60`, `tick_upper = 60`, tính thanh khoản `L_B = 50`.

Trạng thái từng tick:

| Tick   | Được tham chiếu bởi | `liquidity_gross` | `liquidity_net` |
| ------ | ------------------- | ----------------- | --------------- |
| `-120` | A lower             | 100               | +100            |
| `-60`  | B lower             | 50                | +50             |
| `0`    | A upper             | 100               | −100            |
| `60`   | B upper             | 50                | −50             |

Tính thanh khoản ở cấp độ pool cho các giá trị `tick_current` khác nhau:

* `tick_current = -180`: `liquidity = 0` (trước bất kỳ vị trí nào)
* `tick_current = -90`: `liquidity = 100` (bên trong chỉ vị trí A)
* `tick_current = -30`: `liquidity = 150` (bên trong A và B)
* `tick_current = 30`: `liquidity = 50` (bên trong chỉ vị trí B)
* `tick_current = 90`: `liquidity = 0` (vượt qua cả hai)

Trên mỗi lần vượt qua tick trong một swap, chương trình thêm `liquidity_net` (có thể âm) vào `PoolState.liquidity`. Đây là cơ chế chính xác của Uniswap v3.

## Vị trí dưới dạng NFT

Một vị trí Raydium CLMM là một NFT. Mở một vị trí sẽ mint một mint mới hoàn toàn có cung cấp 1 vào ví của người gọi, và quyền kiểm soát mint của chương trình CLMM. Chương trình liên kết quyền sở hữu vị trí với **bất kỳ ai giữ số dư trong một ATA của mint đó** vào thời điểm CPI.

Hậu quả:

* **Vị trí có thể chuyển nhượng.** Một ví có thể bán hoặc airdrop một vị trí bằng cách chuyển NFT. Chủ sở hữu mới sau đó có thể gọi `CollectRewards`, `IncreaseLiquidity`, v.v.
* **Vị trí có thể được định địa chỉ bên ngoài CLMM.** Các marketplace và ví hiển thị các vị trí như các NFT khác. SDK đặt một `name`/`symbol` hợp lý trên siêu dữ liệu mint.
* **PDA của một vị trí được lấy từ mint NFT.** Bạn có thể tìm `PersonalPositionState` mà không cần biết ai đang giữ nó.

### Vị trí Token-2022

Các pool CLMM mới hơn có thể mint vị trí dưới Token-2022 thay vì SPL Token cổ điển. Chương trình công bố hai hướng dẫn song song — `OpenPosition` và `OpenPositionWithToken22Nft` — với ngữ nghĩa giống hệt nhau ngoại trừ chương trình token nào sở hữu mint NFT. Khả năng tương thích ví và marketplace khác nhau; giao diện Raydium theo dõi cả hai.

## Quy tắc phạm vi cho phép

Tại thời điểm `OpenPosition`, chương trình thực thi:

1. `tick_lower < tick_upper`.
2. `tick_lower % tick_spacing == 0` và `tick_upper % tick_spacing == 0`.
3. `MIN_TICK <= tick_lower` và `tick_upper <= MAX_TICK`.
4. Người gọi đã cung cấp các mảng tick chứa `tick_lower` và `tick_upper` — hoặc đã được khởi tạo hoặc thông qua một `init_tick_array` trong cùng một giao dịch.
5. Tài khoản mở rộng bitmap, nếu vị trí này kéo dài vào phạm vi mở rộng.

Nếu bất kỳ kiểm tra nào thất bại, hướng dẫn sẽ bị hoàn nguyên với `InvalidTickIndex`, `NotApproved`, hoặc `InsufficientLiquidity` tùy thuộc vào ràng buộc nào. Xem [`reference/error-codes`](/vi/reference/error-codes).

## "In-range" vs "out-of-range"

Một vị trí ở **trong dải** khi `tick_lower <= tick_current < tick_upper`. Chỉ các vị trí trong dải mới đóng góp vào `PoolState.liquidity` và do đó chỉ chúng mới kiếm được phí swap.

Một vị trí ngoài dải:

* Giữ 100% **một** token (cái mà dải của nó đã đi qua). Cụ thể, nếu `tick_current < tick_lower`, vị trí chỉ giữ token1 (nó đã bị "bán" bởi giá di chuyển); nếu `tick_current >= tick_upper`, nó chỉ giữ token0.
* **Không** kiếm được phí swap.
* **Tiếp tục** tích lũy phần thưởng nếu các luồng phần thưởng của pool phát hành cho tính thanh khoản ngoài dải — nhưng hành vi mặc định của Raydium là "chỉ phát hành cho in-range", khớp với quy ước Uniswap v3. Xem [`products/clmm/fees`](/vi/products/clmm/fees).

Các LP quản lý vị trí CLMM dành phần lớn sự chú ý của họ để giữ các vị trí trong dải khi giá di chuyển.

## Những cạm bẫy tích hợp phổ biến

* **Điểm cuối không khớp khoảng cách.** Mã tính toán một tick từ giá mục tiêu phải snap thành bội số của `tick_spacing` trước khi truyền nó tới `OpenPosition`. Các trình trợ giúp SDK (`TickUtils.getTickWithPriceAndTickspacing`) làm điều này; toán học tự tạo thường không làm.
* **Mảng tick bị thiếu.** Mở một vị trí rộng có thể yêu cầu khởi tạo một số mảng tick; quên truyền chúng làm các tài khoản writable sẽ hoàn nguyên. SDK's `openPositionFromBase` trả danh sách cho bạn.
* **Tick cũ sau một swap.** `tick_current` có thể vượt qua nhiều tick trong một swap. Nếu UX của bạn hiển thị một "tick hiện tại" từ một lệnh gọi RPC và sau đó mở một vị trí trong một lệnh gọi sau đó, vị trí tương đối so với giá trực tiếp có thể chênh lệch hàng chục tick. Tìm lại ngay trước khi ký.
* **NFT vị trí với siêu dữ liệu bổ sung.** Nếu bạn xây dựng một ví nhận ra các vị trí Raydium, phát hiện chúng bằng thẩm quyền mint (= PDA của chương trình CLMM), chứ không phải bằng một trường siêu dữ liệu được mã hóa cứng.

## Nơi đến tiếp theo

* [Math](/vi/products/clmm/math) — bước swap từng bước và dẫn xuất tăng trưởng phí mà ranh giới tick tham gia vào.
* [Accounts](/vi/products/clmm/accounts) — các bố cục `TickArrayState` và `PositionState`.
* [Fees and rewards](/vi/products/clmm/fees) — cách in-range-ness kiểm soát tích lũy phí.
* [`algorithms/clmm-math`](/vi/algorithms/clmm-math) — dẫn xuất chung của các công thức tính thanh khoản tập trung.

Nguồn:

* [`raydium-io/raydium-clmm` — modules `tick_array`, `tick`, `position`](https://github.com/raydium-io/raydium-clmm)
* "Uniswap v3 Core" whitepaper, §6 (ticks), §7 (fee growth)
