nautilus_model/python/defi/
profiler.rs1use std::str::FromStr;
19
20use alloy_primitives::{U160, U256};
21use nautilus_core::python::to_pyvalue_err;
22use pyo3::prelude::*;
23
24use crate::{
25 defi::{
26 Pool,
27 pool_analysis::{PoolProfiler, quote::SwapQuote, size_estimator::SizeForImpactResult},
28 },
29 identifiers::InstrumentId,
30};
31
32#[pymethods]
33#[pyo3_stub_gen::derive::gen_stub_pymethods]
34impl PoolProfiler {
35 #[getter]
36 #[pyo3(name = "pool")]
37 fn py_pool(&self) -> Pool {
38 self.pool.as_ref().clone()
39 }
40
41 #[getter]
42 #[pyo3(name = "instrument_id")]
43 fn py_instrument_id(&self) -> InstrumentId {
44 self.pool.instrument_id
45 }
46
47 #[getter]
48 #[pyo3(name = "is_initialized")]
49 fn py_is_initialized(&self) -> bool {
50 self.is_initialized
51 }
52
53 #[getter]
54 #[pyo3(name = "current_tick")]
55 fn py_current_tick(&self) -> i32 {
56 self.state.current_tick
57 }
58
59 #[getter]
60 #[pyo3(name = "price_sqrt_ratio_x96")]
61 fn py_price_sqrt_ratio_x96(&self) -> String {
62 self.state.price_sqrt_ratio_x96.to_string()
63 }
64
65 #[getter]
66 #[pyo3(name = "total_amount0_deposited")]
67 fn py_total_amount0_deposited(&self) -> String {
68 self.analytics.total_amount0_deposited.to_string()
69 }
70
71 #[getter]
72 #[pyo3(name = "total_amount1_deposited")]
73 fn py_total_amount1_deposited(&self) -> String {
74 self.analytics.total_amount1_deposited.to_string()
75 }
76
77 #[getter]
78 #[pyo3(name = "total_amount0_collected")]
79 fn py_total_amount0_collected(&self) -> String {
80 self.analytics.total_amount0_collected.to_string()
81 }
82
83 #[getter]
84 #[pyo3(name = "total_amount1_collected")]
85 fn py_total_amount1_collected(&self) -> String {
86 self.analytics.total_amount1_collected.to_string()
87 }
88
89 #[getter]
90 #[pyo3(name = "protocol_fees_token0")]
91 fn py_protocol_fees_token0(&self) -> String {
92 self.state.protocol_fees_token0.to_string()
93 }
94
95 #[getter]
96 #[pyo3(name = "protocol_fees_token1")]
97 fn py_protocol_fees_token1(&self) -> String {
98 self.state.protocol_fees_token1.to_string()
99 }
100
101 #[getter]
102 #[pyo3(name = "fee_protocol")]
103 fn py_fee_protocol(&self) -> u8 {
104 self.state.fee_protocol
105 }
106
107 #[pyo3(name = "get_active_liquidity")]
116 fn py_get_active_liquidity(&self) -> u128 {
117 self.get_active_liquidity()
118 }
119
120 #[pyo3(name = "get_active_tick_count")]
122 fn py_get_active_tick_count(&self) -> usize {
123 self.get_active_tick_count()
124 }
125
126 #[pyo3(name = "get_total_tick_count")]
134 fn py_get_total_tick_count(&self) -> usize {
135 self.get_total_tick_count()
136 }
137
138 #[pyo3(name = "get_total_active_positions")]
143 fn py_get_total_active_positions(&self) -> usize {
144 self.get_total_active_positions()
145 }
146
147 #[pyo3(name = "get_total_inactive_positions")]
152 fn py_get_total_inactive_positions(&self) -> usize {
153 self.get_total_inactive_positions()
154 }
155
156 #[pyo3(name = "estimate_balance_of_token0")]
163 fn py_estimate_balance_of_token0(&self) -> String {
164 self.estimate_balance_of_token0().to_string()
165 }
166
167 #[pyo3(name = "estimate_balance_of_token1")]
174 fn py_estimate_balance_of_token1(&self) -> String {
175 self.estimate_balance_of_token1().to_string()
176 }
177
178 #[pyo3(name = "get_total_liquidity")]
179 fn py_get_total_liquidity_all_positions(&self) -> String {
180 self.get_total_liquidity().to_string()
181 }
182
183 #[pyo3(name = "liquidity_utilization_rate")]
188 fn py_liquidity_utilization_rate(&self) -> f64 {
189 self.liquidity_utilization_rate()
190 }
191
192 #[pyo3(name = "swap_exact_in")]
194 fn py_swap_exact_in(
195 &self,
196 amount_in: &str,
197 zero_for_one: bool,
198 sqrt_price_limit_x96: Option<&str>,
199 ) -> PyResult<SwapQuote> {
200 let amount_in = U256::from_str(amount_in).map_err(to_pyvalue_err)?;
201 let sqrt_price_limit = match sqrt_price_limit_x96 {
202 Some(limit_str) => Some(U160::from_str(limit_str).map_err(to_pyvalue_err)?),
203 None => None,
204 };
205
206 self.swap_exact_in(amount_in, zero_for_one, sqrt_price_limit)
207 .map_err(to_pyvalue_err)
208 }
209
210 #[pyo3(name = "swap_exact_out")]
212 fn py_swap_exact_out(
213 &self,
214 amount_out: &str,
215 zero_for_one: bool,
216 sqrt_price_limit_x96: Option<&str>,
217 ) -> PyResult<SwapQuote> {
218 let amount_out = U256::from_str(amount_out).map_err(to_pyvalue_err)?;
219 let sqrt_price_limit = match sqrt_price_limit_x96 {
220 Some(limit_str) => Some(U160::from_str(limit_str).map_err(to_pyvalue_err)?),
221 None => None,
222 };
223
224 self.swap_exact_out(amount_out, zero_for_one, sqrt_price_limit)
225 .map_err(to_pyvalue_err)
226 }
227
228 #[pyo3(name = "size_for_impact_bps")]
243 fn py_size_for_impact_bps(&self, impact_bps: u32, zero_for_one: bool) -> PyResult<String> {
244 self.size_for_impact_bps(impact_bps, zero_for_one)
245 .map(|size| size.to_string())
246 .map_err(to_pyvalue_err)
247 }
248
249 #[pyo3(name = "size_for_impact_bps_detailed")]
257 fn py_size_for_impact_bps_detailed(
258 &self,
259 impact_bps: u32,
260 zero_for_one: bool,
261 ) -> PyResult<SizeForImpactResult> {
262 self.size_for_impact_bps_detailed(impact_bps, zero_for_one)
263 .map_err(to_pyvalue_err)
264 }
265}