Skip to main content

nautilus_bybit/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 Bybit configuration.
17
18use nautilus_core::{python::to_pyvalue_err, string::secret::SecretString};
19use nautilus_model::identifiers::AccountId;
20use nautilus_network::websocket::TransportBackend;
21use pyo3::{PyResult, pymethods};
22
23use crate::{
24    common::{
25        enums::{BybitEnvironment, BybitMarginMode, BybitProductType},
26        parse::parse_smp_type,
27    },
28    config::{BybitDataClientConfig, BybitExecutionClientConfig},
29};
30
31#[pymethods]
32#[pyo3_stub_gen::derive::gen_stub_pymethods]
33impl BybitDataClientConfig {
34    /// Configuration for the Bybit live data client.
35    #[new]
36    #[pyo3(signature = (
37        product_types = None,
38        environment = None,
39        api_key = None,
40        api_secret = None,
41        base_url_http = None,
42        base_url_ws_public = None,
43        base_url_ws_private = None,
44        proxy_url = None,
45        http_timeout_secs = None,
46        max_retries = None,
47        retry_delay_initial_ms = None,
48        retry_delay_max_ms = None,
49        heartbeat_interval_secs = None,
50        recv_window_ms = None,
51        update_instruments_interval_mins = None,
52        instrument_status_poll_secs = None,
53        transport_backend = None,
54    ))]
55    #[expect(clippy::too_many_arguments)]
56    fn py_new(
57        product_types: Option<Vec<BybitProductType>>,
58        environment: Option<BybitEnvironment>,
59        api_key: Option<String>,
60        api_secret: Option<String>,
61        base_url_http: Option<String>,
62        base_url_ws_public: Option<String>,
63        base_url_ws_private: Option<String>,
64        proxy_url: Option<String>,
65        http_timeout_secs: Option<u64>,
66        max_retries: Option<u32>,
67        retry_delay_initial_ms: Option<u64>,
68        retry_delay_max_ms: Option<u64>,
69        heartbeat_interval_secs: Option<u64>,
70        recv_window_ms: Option<u64>,
71        update_instruments_interval_mins: Option<u64>,
72        instrument_status_poll_secs: Option<u64>,
73        transport_backend: Option<TransportBackend>,
74    ) -> Self {
75        let defaults = Self::default();
76        Self {
77            api_key: api_key.map(SecretString::from),
78            api_secret: api_secret.map(SecretString::from),
79            product_types: product_types.unwrap_or(defaults.product_types),
80            environment: environment.unwrap_or(defaults.environment),
81            base_url_http,
82            base_url_ws_public,
83            base_url_ws_private,
84            proxy_url: proxy_url.map(SecretString::from),
85            http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
86            max_retries: max_retries.unwrap_or(defaults.max_retries),
87            retry_delay_initial_ms: retry_delay_initial_ms
88                .unwrap_or(defaults.retry_delay_initial_ms),
89            retry_delay_max_ms: retry_delay_max_ms.unwrap_or(defaults.retry_delay_max_ms),
90            heartbeat_interval_secs: heartbeat_interval_secs
91                .unwrap_or(defaults.heartbeat_interval_secs),
92            recv_window_ms: recv_window_ms.unwrap_or(defaults.recv_window_ms),
93            update_instruments_interval_mins: update_instruments_interval_mins
94                .or(defaults.update_instruments_interval_mins),
95            instrument_poll_interval_secs: instrument_status_poll_secs
96                .or(defaults.instrument_poll_interval_secs),
97            transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
98        }
99    }
100
101    #[getter]
102    const fn instrument_status_poll_secs(&self) -> Option<u64> {
103        self.instrument_poll_interval_secs
104    }
105
106    #[getter]
107    const fn has_proxy_url(&self) -> bool {
108        self.proxy_url.is_some()
109    }
110
111    fn __repr__(&self) -> String {
112        stringify!(BybitDataClientConfig).to_string()
113    }
114}
115
116#[pymethods]
117#[pyo3_stub_gen::derive::gen_stub_pymethods]
118impl BybitExecutionClientConfig {
119    /// Configuration for the Bybit live execution client.
120    #[new]
121    #[pyo3(signature = (
122        product_types = None,
123        environment = None,
124        api_key = None,
125        api_secret = None,
126        base_url_http = None,
127        base_url_ws_private = None,
128        base_url_ws_trade = None,
129        proxy_url = None,
130        http_timeout_secs = None,
131        max_retries = None,
132        retry_delay_initial_ms = None,
133        retry_delay_max_ms = None,
134        heartbeat_interval_secs = None,
135        auth_timeout_secs = None,
136        recv_window_ms = None,
137        account_id = None,
138        use_spot_position_reports = None,
139        auto_repay_spot_borrows = None,
140        margin_mode = None,
141        smp_type = None,
142        transport_backend = None,
143    ))]
144    #[expect(clippy::too_many_arguments)]
145    fn py_new(
146        product_types: Option<Vec<BybitProductType>>,
147        environment: Option<BybitEnvironment>,
148        api_key: Option<String>,
149        api_secret: Option<String>,
150        base_url_http: Option<String>,
151        base_url_ws_private: Option<String>,
152        base_url_ws_trade: Option<String>,
153        proxy_url: Option<String>,
154        http_timeout_secs: Option<u64>,
155        max_retries: Option<u32>,
156        retry_delay_initial_ms: Option<u64>,
157        retry_delay_max_ms: Option<u64>,
158        heartbeat_interval_secs: Option<u64>,
159        auth_timeout_secs: Option<u64>,
160        recv_window_ms: Option<u64>,
161        account_id: Option<AccountId>,
162        use_spot_position_reports: Option<bool>,
163        auto_repay_spot_borrows: Option<bool>,
164        margin_mode: Option<BybitMarginMode>,
165        smp_type: Option<String>,
166        transport_backend: Option<TransportBackend>,
167    ) -> PyResult<Self> {
168        let smp_type = smp_type
169            .map(|value| parse_smp_type(&value))
170            .transpose()
171            .map_err(to_pyvalue_err)?;
172
173        let defaults = Self::default();
174        Ok(Self {
175            api_key: api_key.map(SecretString::from),
176            api_secret: api_secret.map(SecretString::from),
177            product_types: product_types.unwrap_or(defaults.product_types),
178            environment: environment.unwrap_or(defaults.environment),
179            base_url_http,
180            base_url_ws_private,
181            base_url_ws_trade,
182            proxy_url: proxy_url.map(SecretString::from),
183            http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
184            max_retries: max_retries.unwrap_or(defaults.max_retries),
185            retry_delay_initial_ms: retry_delay_initial_ms
186                .unwrap_or(defaults.retry_delay_initial_ms),
187            retry_delay_max_ms: retry_delay_max_ms.unwrap_or(defaults.retry_delay_max_ms),
188            heartbeat_interval_secs: heartbeat_interval_secs
189                .unwrap_or(defaults.heartbeat_interval_secs),
190            auth_timeout_secs,
191            recv_window_ms: recv_window_ms.unwrap_or(defaults.recv_window_ms),
192            account_id,
193            use_spot_position_reports: use_spot_position_reports
194                .unwrap_or(defaults.use_spot_position_reports),
195            auto_repay_spot_borrows: auto_repay_spot_borrows
196                .unwrap_or(defaults.auto_repay_spot_borrows),
197            futures_leverages: None,
198            position_mode: None,
199            margin_mode,
200            smp_type,
201            transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
202        })
203    }
204
205    #[getter]
206    #[pyo3(name = "smp_type")]
207    fn py_smp_type(&self) -> Option<String> {
208        self.smp_type.map(|smp_type| smp_type.as_ref().to_string())
209    }
210
211    #[getter]
212    const fn has_proxy_url(&self) -> bool {
213        self.proxy_url.is_some()
214    }
215
216    fn __repr__(&self) -> String {
217        stringify!(BybitExecutionClientConfig).to_string()
218    }
219}