Skip to main content

nautilus_okx/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 OKX configuration.
17
18use nautilus_model::identifiers::AccountId;
19use nautilus_network::websocket::TransportBackend;
20use pyo3::prelude::*;
21
22use crate::{
23    common::enums::{OKXEnvironment, OKXInstrumentType, OKXMarginMode, OKXRegion, OKXVipLevel},
24    config::{OKXDataClientConfig, OKXExecutionClientConfig},
25};
26
27#[pymethods]
28#[pyo3_stub_gen::derive::gen_stub_pymethods]
29impl OKXDataClientConfig {
30    /// Configuration for the OKX data client.
31    #[new]
32    #[pyo3(signature = (
33        instrument_types = None,
34        environment = None,
35        region = None,
36        api_key = None,
37        api_secret = None,
38        api_passphrase = None,
39        base_url_http = None,
40        base_url_ws_public = None,
41        base_url_ws_business = None,
42        proxy_url = None,
43        http_timeout_secs = None,
44        max_retries = None,
45        retry_delay_initial_ms = None,
46        retry_delay_max_ms = None,
47        update_instruments_interval_mins = None,
48        book_stale_check_interval_secs = None,
49        book_stale_threshold_secs = None,
50        book_snapshot_timeout_secs = None,
51        vip_level = None,
52        load_spreads = false,
53        transport_backend = None,
54        instrument_families = None,
55    ))]
56    #[expect(clippy::too_many_arguments)]
57    fn py_new(
58        instrument_types: Option<Vec<OKXInstrumentType>>,
59        environment: Option<OKXEnvironment>,
60        region: Option<OKXRegion>,
61        api_key: Option<String>,
62        api_secret: Option<String>,
63        api_passphrase: Option<String>,
64        base_url_http: Option<String>,
65        base_url_ws_public: Option<String>,
66        base_url_ws_business: Option<String>,
67        proxy_url: Option<String>,
68        http_timeout_secs: Option<u64>,
69        max_retries: Option<u32>,
70        retry_delay_initial_ms: Option<u64>,
71        retry_delay_max_ms: Option<u64>,
72        update_instruments_interval_mins: Option<u64>,
73        book_stale_check_interval_secs: Option<u64>,
74        book_stale_threshold_secs: Option<u64>,
75        book_snapshot_timeout_secs: Option<u64>,
76        vip_level: Option<OKXVipLevel>,
77        load_spreads: bool,
78        transport_backend: Option<TransportBackend>,
79        instrument_families: Option<Vec<String>>,
80    ) -> Self {
81        let defaults = Self::default();
82        Self {
83            api_key,
84            api_secret,
85            api_passphrase,
86            instrument_types: instrument_types.unwrap_or(defaults.instrument_types),
87            contract_types: None,
88            load_spreads,
89            instrument_families,
90            base_url_http,
91            base_url_ws_public,
92            base_url_ws_business,
93            proxy_url,
94            environment: environment.unwrap_or(defaults.environment),
95            region: region.unwrap_or(defaults.region),
96            http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
97            max_retries: max_retries.unwrap_or(defaults.max_retries),
98            retry_delay_initial_ms: retry_delay_initial_ms
99                .unwrap_or(defaults.retry_delay_initial_ms),
100            retry_delay_max_ms: retry_delay_max_ms.unwrap_or(defaults.retry_delay_max_ms),
101            update_instruments_interval_mins: update_instruments_interval_mins
102                .unwrap_or(defaults.update_instruments_interval_mins),
103            book_stale_check_interval_secs: book_stale_check_interval_secs
104                .unwrap_or(defaults.book_stale_check_interval_secs),
105            book_stale_threshold_secs: book_stale_threshold_secs
106                .unwrap_or(defaults.book_stale_threshold_secs),
107            book_snapshot_timeout_secs: book_snapshot_timeout_secs
108                .unwrap_or(defaults.book_snapshot_timeout_secs),
109            vip_level,
110            transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
111        }
112    }
113
114    #[getter]
115    const fn has_proxy_url(&self) -> bool {
116        self.proxy_url.is_some()
117    }
118
119    fn __repr__(&self) -> String {
120        stringify!(OKXDataClientConfig).to_string()
121    }
122}
123
124#[pymethods]
125#[pyo3_stub_gen::derive::gen_stub_pymethods]
126impl OKXExecutionClientConfig {
127    /// Configuration for the OKX execution client.
128    #[new]
129    #[pyo3(signature = (
130        account_id,
131        instrument_types = None,
132        environment = None,
133        region = None,
134        api_key = None,
135        api_secret = None,
136        api_passphrase = None,
137        base_url_http = None,
138        base_url_ws_private = None,
139        base_url_ws_business = None,
140        proxy_url = None,
141        http_timeout_secs = None,
142        max_retries = None,
143        retry_delay_initial_ms = None,
144        retry_delay_max_ms = None,
145        margin_mode = None,
146        load_spreads = false,
147        auth_timeout_secs = None,
148        transport_backend = None,
149    ))]
150    #[expect(clippy::too_many_arguments)]
151    fn py_new(
152        account_id: AccountId,
153        instrument_types: Option<Vec<OKXInstrumentType>>,
154        environment: Option<OKXEnvironment>,
155        region: Option<OKXRegion>,
156        api_key: Option<String>,
157        api_secret: Option<String>,
158        api_passphrase: Option<String>,
159        base_url_http: Option<String>,
160        base_url_ws_private: Option<String>,
161        base_url_ws_business: Option<String>,
162        proxy_url: Option<String>,
163        http_timeout_secs: Option<u64>,
164        max_retries: Option<u32>,
165        retry_delay_initial_ms: Option<u64>,
166        retry_delay_max_ms: Option<u64>,
167        margin_mode: Option<OKXMarginMode>,
168        load_spreads: bool,
169        auth_timeout_secs: Option<u64>,
170        transport_backend: Option<TransportBackend>,
171    ) -> Self {
172        let defaults = Self::default();
173        Self {
174            account_id,
175            api_key,
176            api_secret,
177            api_passphrase,
178            instrument_types: instrument_types.unwrap_or(defaults.instrument_types),
179            contract_types: None,
180            instrument_families: None,
181            base_url_http,
182            base_url_ws_private,
183            base_url_ws_business,
184            proxy_url,
185            environment: environment.unwrap_or(defaults.environment),
186            region: region.unwrap_or(defaults.region),
187            http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
188            use_mm_mass_cancel: defaults.use_mm_mass_cancel,
189            max_retries: max_retries.unwrap_or(defaults.max_retries),
190            retry_delay_initial_ms: retry_delay_initial_ms
191                .unwrap_or(defaults.retry_delay_initial_ms),
192            retry_delay_max_ms: retry_delay_max_ms.unwrap_or(defaults.retry_delay_max_ms),
193            margin_mode,
194            load_spreads,
195            use_spot_margin: defaults.use_spot_margin,
196            auth_timeout_secs,
197            transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
198        }
199    }
200
201    #[getter]
202    const fn has_proxy_url(&self) -> bool {
203        self.proxy_url.is_some()
204    }
205
206    fn __repr__(&self) -> String {
207        stringify!(OKXExecutionClientConfig).to_string()
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use rstest::rstest;
214
215    use super::*;
216
217    #[rstest]
218    fn test_data_config_py_new() {
219        let config = OKXDataClientConfig::py_new(
220            None,
221            None,
222            None,
223            None,
224            None,
225            None,
226            None,
227            None,
228            None,
229            None,
230            None,
231            None,
232            None,
233            None,
234            None,
235            None,
236            None,
237            None,
238            None,
239            true,
240            None,
241            Some(vec!["BTC-USD".to_string()]),
242        );
243
244        assert_eq!(
245            config.instrument_families,
246            Some(vec!["BTC-USD".to_string()]),
247        );
248        assert!(config.load_spreads);
249        assert_eq!(config.book_stale_check_interval_secs, 5);
250        assert_eq!(config.book_stale_threshold_secs, 30);
251        assert_eq!(config.book_snapshot_timeout_secs, 3);
252    }
253
254    #[rstest]
255    fn test_exec_config_py_new_load_spreads() {
256        let config = OKXExecutionClientConfig::py_new(
257            AccountId::from("OKX-001"),
258            None,
259            None,
260            None,
261            None,
262            None,
263            None,
264            None,
265            None,
266            None,
267            None,
268            None,
269            None,
270            None,
271            None,
272            None,
273            true,
274            None,
275            None,
276        );
277
278        assert!(config.load_spreads);
279        assert_eq!(config.auth_timeout_secs, None);
280    }
281}