nautilus_model/defi/pool_analysis/
snapshot.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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 serde::{Deserialize, Serialize};
18
19use crate::{
20    defi::{
21        data::block::BlockPosition, pool_analysis::position::PoolPosition, tick_map::tick::PoolTick,
22    },
23    identifiers::InstrumentId,
24};
25
26/// Complete snapshot of a liquidity pool's state at a specific point in time.
27///
28/// `PoolSnapshot` provides a comprehensive, self-contained representation of a pool's
29/// entire state, bundling together the global state variables, all liquidity positions,
30/// and the complete tick distribution.
31#[cfg_attr(
32    feature = "python",
33    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
34)]
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub struct PoolSnapshot {
37    /// The instrument ID of the pool this snapshot represents.
38    pub instrument_id: InstrumentId,
39    /// Global pool state including price, tick, fees, and cumulative flows.
40    pub state: PoolState,
41    /// All liquidity positions in the pool.
42    pub positions: Vec<PoolPosition>,
43    /// Complete tick distribution across the pool's price range.
44    pub ticks: Vec<PoolTick>,
45    /// Analytics counters for the pool.
46    pub analytics: PoolAnalytics,
47    /// Block position where this snapshot was taken.
48    pub block_position: BlockPosition,
49}
50
51impl PoolSnapshot {
52    /// Creates a new `PoolSnapshot` with the specified parameters.
53    pub fn new(
54        instrument_id: InstrumentId,
55        state: PoolState,
56        positions: Vec<PoolPosition>,
57        ticks: Vec<PoolTick>,
58        analytics: PoolAnalytics,
59        block_position: BlockPosition,
60    ) -> Self {
61        Self {
62            instrument_id,
63            state,
64            positions,
65            ticks,
66            analytics,
67            block_position,
68        }
69    }
70}
71
72/// Global state snapshot of a liquidity pool at a specific point in time.
73///
74/// `PoolState` encapsulates the core global variables that define a UniswapV3-style
75/// AMM pool's current state. This includes the current price position, cumulative
76/// deposit/withdrawal flows, and protocol fee configuration.
77#[cfg_attr(
78    feature = "python",
79    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
80)]
81#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
82pub struct PoolState {
83    /// Current tick position of the pool price.
84    pub current_tick: i32,
85    /// Current sqrt price ratio as Q64.96 fixed point number.
86    pub price_sqrt_ratio_x96: U160,
87    /// Current active liquidity in the pool.
88    pub liquidity: u128,
89    /// Accumulated protocol fees in token0 units.
90    pub protocol_fees_token0: U256,
91    /// Accumulated protocol fees in token1 units.
92    pub protocol_fees_token1: U256,
93    /// Protocol fee packed: lower 4 bits for token0, upper 4 bits for token1.
94    pub fee_protocol: u8,
95    /// Global fee growth for token0 as Q128.128 fixed-point number.
96    pub fee_growth_global_0: U256,
97    /// Global fee growth for token1 as Q128.128 fixed-point number.
98    pub fee_growth_global_1: U256,
99}
100
101impl PoolState {
102    /// Creates a new `PoolState` with the specified parameters.
103    pub fn new(protocol_fees_token0: U256, protocol_fees_token1: U256, fee_protocol: u8) -> Self {
104        Self {
105            current_tick: 0,
106            price_sqrt_ratio_x96: U160::ZERO,
107            liquidity: 0,
108            protocol_fees_token0,
109            protocol_fees_token1,
110            fee_protocol,
111            fee_growth_global_0: U256::ZERO,
112            fee_growth_global_1: U256::ZERO,
113        }
114    }
115}
116
117impl Default for PoolState {
118    fn default() -> Self {
119        Self {
120            current_tick: 0,
121            price_sqrt_ratio_x96: U160::ZERO,
122            liquidity: 0,
123            protocol_fees_token0: U256::ZERO,
124            protocol_fees_token1: U256::ZERO,
125            fee_protocol: 0,
126            fee_growth_global_0: U256::ZERO,
127            fee_growth_global_1: U256::ZERO,
128        }
129    }
130}
131
132/// Analytics counters and metrics for pool operations.
133///
134/// It tracks cumulative statistics about pool activity, including
135/// deposit and collection flows, event counts, and performance metrics for debugging.
136#[cfg_attr(
137    feature = "python",
138    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
139)]
140#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
141pub struct PoolAnalytics {
142    /// Total amount of token0 deposited through mints.
143    pub total_amount0_deposited: U256,
144    /// Total amount of token1 deposited through mints.
145    pub total_amount1_deposited: U256,
146    /// Total amount of token0 collected
147    pub total_amount0_collected: U256,
148    /// Total amount of token1 collected.
149    pub total_amount1_collected: U256,
150    /// Total number of swap events processed.
151    pub total_swaps: u64,
152    /// Total number of mint events processed.
153    pub total_mints: u64,
154    /// Total number of burn events processed.
155    pub total_burns: u64,
156    /// Total number of fee collection events processed.
157    pub total_fee_collects: u64,
158    /// Total number of flash events processed.
159    pub total_flashes: u64,
160    /// Time spent processing swap events (debug builds only).
161    #[cfg(debug_assertions)]
162    #[serde(skip)]
163    pub swap_processing_time: std::time::Duration,
164    /// Time spent processing mint events (debug builds only).
165    #[cfg(debug_assertions)]
166    #[serde(skip)]
167    pub mint_processing_time: std::time::Duration,
168    /// Time spent processing burn events (debug builds only).
169    #[cfg(debug_assertions)]
170    #[serde(skip)]
171    pub burn_processing_time: std::time::Duration,
172    /// Time spent processing collect events (debug builds only).
173    #[cfg(debug_assertions)]
174    #[serde(skip)]
175    pub collect_processing_time: std::time::Duration,
176}
177
178impl Default for PoolAnalytics {
179    fn default() -> Self {
180        Self {
181            total_amount0_deposited: U256::ZERO,
182            total_amount1_deposited: U256::ZERO,
183            total_amount0_collected: U256::ZERO,
184            total_amount1_collected: U256::ZERO,
185            total_swaps: 0,
186            total_mints: 0,
187            total_burns: 0,
188            total_fee_collects: 0,
189            total_flashes: 0,
190            #[cfg(debug_assertions)]
191            swap_processing_time: std::time::Duration::ZERO,
192            #[cfg(debug_assertions)]
193            mint_processing_time: std::time::Duration::ZERO,
194            #[cfg(debug_assertions)]
195            burn_processing_time: std::time::Duration::ZERO,
196            #[cfg(debug_assertions)]
197            collect_processing_time: std::time::Duration::ZERO,
198        }
199    }
200}