Skip to main content

nautilus_model/defi/pool_analysis/
snapshot.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use alloy_primitives::{U160, U256};
17use nautilus_core::UnixNanos;
18use serde::{Deserialize, Serialize};
19
20use crate::{
21    defi::{
22        data::block::BlockPosition, pool_analysis::position::PoolPosition, tick_map::tick::PoolTick,
23    },
24    identifiers::InstrumentId,
25};
26
27/// Complete snapshot of a liquidity pool's state at a specific point in time.
28///
29/// `PoolSnapshot` provides a self-contained representation of a pool's
30/// entire state, bundling together the global state variables, all liquidity positions,
31/// and the complete tick distribution.
32#[cfg_attr(
33    feature = "python",
34    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model", from_py_object)
35)]
36#[cfg_attr(
37    feature = "python",
38    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.model")
39)]
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
41pub struct PoolSnapshot {
42    /// The instrument ID of the pool this snapshot represents.
43    pub instrument_id: InstrumentId,
44    /// Global pool state including price, tick, fees, and cumulative flows.
45    pub state: PoolState,
46    /// All liquidity positions in the pool.
47    pub positions: Vec<PoolPosition>,
48    /// Complete tick distribution across the pool's price range.
49    pub ticks: Vec<PoolTick>,
50    /// Analytics counters for the pool.
51    pub analytics: PoolAnalytics,
52    /// Block position where this snapshot was taken.
53    pub block_position: BlockPosition,
54    /// UNIX timestamp (nanoseconds) when the snapshot event occurred.
55    #[serde(default)]
56    pub ts_event: UnixNanos,
57    /// UNIX timestamp (nanoseconds) when the instance was created.
58    #[serde(default)]
59    pub ts_init: UnixNanos,
60}
61
62impl PoolSnapshot {
63    /// Creates a new `PoolSnapshot` with the specified parameters.
64    #[must_use]
65    #[expect(clippy::too_many_arguments)]
66    pub fn new(
67        instrument_id: InstrumentId,
68        state: PoolState,
69        positions: Vec<PoolPosition>,
70        ticks: Vec<PoolTick>,
71        analytics: PoolAnalytics,
72        block_position: BlockPosition,
73        ts_event: UnixNanos,
74        ts_init: UnixNanos,
75    ) -> Self {
76        Self {
77            instrument_id,
78            state,
79            positions,
80            ticks,
81            analytics,
82            block_position,
83            ts_event,
84            ts_init,
85        }
86    }
87}
88
89/// Global state snapshot of a liquidity pool at a specific point in time.
90///
91/// `PoolState` encapsulates the core global variables that define a UniswapV3-style
92/// AMM pool's current state. This includes the current price position, cumulative
93/// deposit/withdrawal flows, and protocol fee configuration.
94#[cfg_attr(
95    feature = "python",
96    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model", from_py_object)
97)]
98#[cfg_attr(
99    feature = "python",
100    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.model")
101)]
102#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
103pub struct PoolState {
104    /// Current tick position of the pool price.
105    pub current_tick: i32,
106    /// Current sqrt price ratio as Q64.96 fixed point number.
107    pub price_sqrt_ratio_x96: U160,
108    /// Current active liquidity in the pool.
109    pub liquidity: u128,
110    /// Accumulated protocol fees in token0 units.
111    pub protocol_fees_token0: U256,
112    /// Accumulated protocol fees in token1 units.
113    pub protocol_fees_token1: U256,
114    /// Protocol fee packed: lower 4 bits for token0, upper 4 bits for token1.
115    pub fee_protocol: u8,
116    /// Global fee growth for token0 as Q128.128 fixed-point number.
117    pub fee_growth_global_0: U256,
118    /// Global fee growth for token1 as Q128.128 fixed-point number.
119    pub fee_growth_global_1: U256,
120}
121
122impl PoolState {
123    /// Creates a new `PoolState` with the specified parameters.
124    #[must_use]
125    pub fn new(protocol_fees_token0: U256, protocol_fees_token1: U256, fee_protocol: u8) -> Self {
126        Self {
127            current_tick: 0,
128            price_sqrt_ratio_x96: U160::ZERO,
129            liquidity: 0,
130            protocol_fees_token0,
131            protocol_fees_token1,
132            fee_protocol,
133            fee_growth_global_0: U256::ZERO,
134            fee_growth_global_1: U256::ZERO,
135        }
136    }
137}
138
139impl Default for PoolState {
140    fn default() -> Self {
141        Self {
142            current_tick: 0,
143            price_sqrt_ratio_x96: U160::ZERO,
144            liquidity: 0,
145            protocol_fees_token0: U256::ZERO,
146            protocol_fees_token1: U256::ZERO,
147            fee_protocol: 0,
148            fee_growth_global_0: U256::ZERO,
149            fee_growth_global_1: U256::ZERO,
150        }
151    }
152}
153
154/// Analytics counters and metrics for pool operations.
155///
156/// It tracks cumulative statistics about pool activity, including
157/// deposit and collection flows, event counts, and performance metrics for debugging.
158#[cfg_attr(
159    feature = "python",
160    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model", from_py_object)
161)]
162#[cfg_attr(
163    feature = "python",
164    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.model")
165)]
166#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
167pub struct PoolAnalytics {
168    /// Total amount of token0 deposited through mints.
169    pub total_amount0_deposited: U256,
170    /// Total amount of token1 deposited through mints.
171    pub total_amount1_deposited: U256,
172    /// Total amount of token0 collected
173    pub total_amount0_collected: U256,
174    /// Total amount of token1 collected.
175    pub total_amount1_collected: U256,
176    /// Total number of swap events processed.
177    pub total_swaps: u64,
178    /// Total number of mint events processed.
179    pub total_mints: u64,
180    /// Total number of burn events processed.
181    pub total_burns: u64,
182    /// Total number of fee collection events processed.
183    pub total_fee_collects: u64,
184    /// Total number of flash events processed.
185    pub total_flashes: u64,
186    /// Liquidity utilization rate (active liquidity / total liquidity)
187    pub liquidity_utilization_rate: f64,
188}
189
190impl Default for PoolAnalytics {
191    fn default() -> Self {
192        Self {
193            total_amount0_deposited: U256::ZERO,
194            total_amount1_deposited: U256::ZERO,
195            total_amount0_collected: U256::ZERO,
196            total_amount1_collected: U256::ZERO,
197            total_swaps: 0,
198            total_mints: 0,
199            total_burns: 0,
200            total_fee_collects: 0,
201            total_flashes: 0,
202            liquidity_utilization_rate: 0.0,
203        }
204    }
205}