Skip to main content

nautilus_lighter/python/
config.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
16//! Python bindings for Lighter configuration.
17
18use nautilus_core::string::secret::SecretString;
19use nautilus_model::identifiers::{AccountId, Venue};
20use nautilus_network::websocket::TransportBackend;
21use pyo3::pymethods;
22
23use crate::{
24    common::enums::{LighterDeployment, LighterEnvironment},
25    config::{LighterDataClientConfig, LighterExecutionClientConfig},
26};
27
28#[pymethods]
29#[pyo3_stub_gen::derive::gen_stub_pymethods]
30impl LighterDataClientConfig {
31    /// Configuration for the Lighter live data client.
32    #[new]
33    #[pyo3(signature = (
34        base_url_http = None,
35        base_url_ws = None,
36        proxy_url = None,
37        environment = None,
38        account_index = None,
39        api_key_index = None,
40        private_key = None,
41        http_timeout_secs = None,
42        ws_timeout_secs = None,
43        update_instruments_interval_mins = None,
44        rest_quota_per_min = None,
45        transport_backend = None,
46        deployment = None,
47        venue = None,
48        book_snapshot_timeout_secs = None,
49    ))]
50    #[expect(clippy::too_many_arguments)]
51    fn py_new(
52        base_url_http: Option<String>,
53        base_url_ws: Option<String>,
54        proxy_url: Option<String>,
55        environment: Option<LighterEnvironment>,
56        account_index: Option<u64>,
57        api_key_index: Option<u8>,
58        private_key: Option<String>,
59        http_timeout_secs: Option<u64>,
60        ws_timeout_secs: Option<u64>,
61        update_instruments_interval_mins: Option<u64>,
62        rest_quota_per_min: Option<u32>,
63        transport_backend: Option<TransportBackend>,
64        deployment: Option<LighterDeployment>,
65        venue: Option<Venue>,
66        book_snapshot_timeout_secs: Option<u64>,
67    ) -> Self {
68        let defaults = Self::default();
69        Self {
70            environment: environment.unwrap_or(defaults.environment),
71            deployment: deployment.unwrap_or(defaults.deployment),
72            venue,
73            account_index,
74            api_key_index,
75            private_key: private_key.map(SecretString::from),
76            base_url_http,
77            base_url_ws,
78            proxy_url: proxy_url.map(SecretString::from),
79            http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
80            ws_timeout_secs: ws_timeout_secs.unwrap_or(defaults.ws_timeout_secs),
81            update_instruments_interval_mins: update_instruments_interval_mins
82                .unwrap_or(defaults.update_instruments_interval_mins),
83            book_snapshot_timeout_secs: book_snapshot_timeout_secs
84                .unwrap_or(defaults.book_snapshot_timeout_secs),
85            rest_quota_per_min,
86            transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
87        }
88    }
89
90    #[getter]
91    const fn has_proxy_url(&self) -> bool {
92        self.proxy_url.is_some()
93    }
94
95    fn __repr__(&self) -> String {
96        stringify!(LighterDataClientConfig).to_string()
97    }
98}
99
100#[pymethods]
101#[pyo3_stub_gen::derive::gen_stub_pymethods]
102impl LighterExecutionClientConfig {
103    /// Configuration for the Lighter live execution client.
104    #[new]
105    #[pyo3(signature = (
106        account_id,
107        account_index = None,
108        api_key_index = None,
109        private_key = None,
110        base_url_http = None,
111        base_url_ws = None,
112        proxy_url = None,
113        environment = None,
114        http_timeout_secs = None,
115        ws_timeout_secs = None,
116        market_order_slippage_bps = None,
117        rest_quota_per_min = None,
118        sendtx_quota_per_min = None,
119        transport_backend = None,
120        deployment = None,
121        venue = None,
122        use_gtd = true,
123    ))]
124    #[expect(clippy::too_many_arguments)]
125    fn py_new(
126        account_id: AccountId,
127        account_index: Option<u64>,
128        api_key_index: Option<u8>,
129        private_key: Option<String>,
130        base_url_http: Option<String>,
131        base_url_ws: Option<String>,
132        proxy_url: Option<String>,
133        environment: Option<LighterEnvironment>,
134        http_timeout_secs: Option<u64>,
135        ws_timeout_secs: Option<u64>,
136        market_order_slippage_bps: Option<u32>,
137        rest_quota_per_min: Option<u32>,
138        sendtx_quota_per_min: Option<u32>,
139        transport_backend: Option<TransportBackend>,
140        deployment: Option<LighterDeployment>,
141        venue: Option<Venue>,
142        use_gtd: bool,
143    ) -> Self {
144        let defaults = Self::default();
145        Self {
146            environment: environment.unwrap_or(defaults.environment),
147            deployment: deployment.unwrap_or(defaults.deployment),
148            venue,
149            account_id,
150            account_index,
151            api_key_index,
152            private_key: private_key.map(SecretString::from),
153            base_url_http,
154            base_url_ws,
155            proxy_url: proxy_url.map(SecretString::from),
156            http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
157            ws_timeout_secs: ws_timeout_secs.unwrap_or(defaults.ws_timeout_secs),
158            market_order_slippage_bps: market_order_slippage_bps
159                .unwrap_or(defaults.market_order_slippage_bps),
160            rest_quota_per_min,
161            sendtx_quota_per_min,
162            transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
163            use_gtd,
164        }
165    }
166
167    #[getter]
168    const fn has_proxy_url(&self) -> bool {
169        self.proxy_url.is_some()
170    }
171
172    fn __repr__(&self) -> String {
173        stringify!(LighterExecutionClientConfig).to_string()
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use rstest::rstest;
180
181    use super::*;
182
183    #[rstest]
184    fn test_data_config_py_new_book_timeout() {
185        let config = LighterDataClientConfig::py_new(
186            None,
187            None,
188            None,
189            None,
190            None,
191            None,
192            None,
193            None,
194            None,
195            None,
196            Some(7),
197            None,
198            None,
199            None,
200            Some(42),
201        );
202
203        assert_eq!(config.rest_quota_per_min, Some(7));
204        assert_eq!(config.book_snapshot_timeout_secs, 42);
205    }
206
207    #[rstest]
208    fn test_data_config_py_new_book_timeout_default() {
209        let config = LighterDataClientConfig::py_new(
210            None, None, None, None, None, None, None, None, None, None, None, None, None, None,
211            None,
212        );
213
214        assert_eq!(config.book_snapshot_timeout_secs, 10);
215    }
216}