1use 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 #[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 book_snapshot_timeout_secs = None,
55 bars_timestamp_on_close = None,
56 ))]
57 #[expect(clippy::too_many_arguments)]
58 fn py_new(
59 product_types: Option<Vec<BybitProductType>>,
60 environment: Option<BybitEnvironment>,
61 api_key: Option<String>,
62 api_secret: Option<String>,
63 base_url_http: Option<String>,
64 base_url_ws_public: Option<String>,
65 base_url_ws_private: Option<String>,
66 proxy_url: Option<String>,
67 http_timeout_secs: Option<u64>,
68 max_retries: Option<u32>,
69 retry_delay_initial_ms: Option<u64>,
70 retry_delay_max_ms: Option<u64>,
71 heartbeat_interval_secs: Option<u64>,
72 recv_window_ms: Option<u64>,
73 update_instruments_interval_mins: Option<u64>,
74 instrument_status_poll_secs: Option<u64>,
75 transport_backend: Option<TransportBackend>,
76 book_snapshot_timeout_secs: Option<u64>,
77 bars_timestamp_on_close: Option<bool>,
78 ) -> Self {
79 let defaults = Self::default();
80 Self {
81 api_key: api_key.map(SecretString::from),
82 api_secret: api_secret.map(SecretString::from),
83 product_types: product_types.unwrap_or(defaults.product_types),
84 environment: environment.unwrap_or(defaults.environment),
85 base_url_http,
86 base_url_ws_public,
87 base_url_ws_private,
88 proxy_url: proxy_url.map(SecretString::from),
89 http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
90 max_retries: max_retries.unwrap_or(defaults.max_retries),
91 retry_delay_initial_ms: retry_delay_initial_ms
92 .unwrap_or(defaults.retry_delay_initial_ms),
93 retry_delay_max_ms: retry_delay_max_ms.unwrap_or(defaults.retry_delay_max_ms),
94 heartbeat_interval_secs: heartbeat_interval_secs
95 .unwrap_or(defaults.heartbeat_interval_secs),
96 recv_window_ms: recv_window_ms.unwrap_or(defaults.recv_window_ms),
97 update_instruments_interval_mins: update_instruments_interval_mins
98 .or(defaults.update_instruments_interval_mins),
99 instrument_poll_interval_secs: instrument_status_poll_secs
100 .or(defaults.instrument_poll_interval_secs),
101 book_snapshot_timeout_secs: book_snapshot_timeout_secs
102 .unwrap_or(defaults.book_snapshot_timeout_secs),
103 transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
104 bars_timestamp_on_close: bars_timestamp_on_close
105 .unwrap_or(defaults.bars_timestamp_on_close),
106 }
107 }
108
109 #[getter]
110 const fn instrument_status_poll_secs(&self) -> Option<u64> {
111 self.instrument_poll_interval_secs
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!(BybitDataClientConfig).to_string()
121 }
122}
123
124#[pymethods]
125#[pyo3_stub_gen::derive::gen_stub_pymethods]
126impl BybitExecutionClientConfig {
127 #[new]
129 #[pyo3(signature = (
130 product_types = None,
131 environment = None,
132 api_key = None,
133 api_secret = None,
134 base_url_http = None,
135 base_url_ws_private = None,
136 base_url_ws_trade = None,
137 proxy_url = None,
138 http_timeout_secs = None,
139 max_retries = None,
140 retry_delay_initial_ms = None,
141 retry_delay_max_ms = None,
142 heartbeat_interval_secs = None,
143 auth_timeout_secs = None,
144 recv_window_ms = None,
145 account_id = None,
146 use_spot_position_reports = None,
147 auto_repay_spot_borrows = None,
148 margin_mode = None,
149 smp_type = None,
150 transport_backend = None,
151 ))]
152 #[expect(clippy::too_many_arguments)]
153 fn py_new(
154 product_types: Option<Vec<BybitProductType>>,
155 environment: Option<BybitEnvironment>,
156 api_key: Option<String>,
157 api_secret: Option<String>,
158 base_url_http: Option<String>,
159 base_url_ws_private: Option<String>,
160 base_url_ws_trade: Option<String>,
161 proxy_url: Option<String>,
162 http_timeout_secs: Option<u64>,
163 max_retries: Option<u32>,
164 retry_delay_initial_ms: Option<u64>,
165 retry_delay_max_ms: Option<u64>,
166 heartbeat_interval_secs: Option<u64>,
167 auth_timeout_secs: Option<u64>,
168 recv_window_ms: Option<u64>,
169 account_id: Option<AccountId>,
170 use_spot_position_reports: Option<bool>,
171 auto_repay_spot_borrows: Option<bool>,
172 margin_mode: Option<BybitMarginMode>,
173 smp_type: Option<String>,
174 transport_backend: Option<TransportBackend>,
175 ) -> PyResult<Self> {
176 let smp_type = smp_type
177 .map(|value| parse_smp_type(&value))
178 .transpose()
179 .map_err(to_pyvalue_err)?;
180
181 let defaults = Self::default();
182 Ok(Self {
183 api_key: api_key.map(SecretString::from),
184 api_secret: api_secret.map(SecretString::from),
185 product_types: product_types.unwrap_or(defaults.product_types),
186 environment: environment.unwrap_or(defaults.environment),
187 base_url_http,
188 base_url_ws_private,
189 base_url_ws_trade,
190 proxy_url: proxy_url.map(SecretString::from),
191 http_timeout_secs: http_timeout_secs.unwrap_or(defaults.http_timeout_secs),
192 max_retries: max_retries.unwrap_or(defaults.max_retries),
193 retry_delay_initial_ms: retry_delay_initial_ms
194 .unwrap_or(defaults.retry_delay_initial_ms),
195 retry_delay_max_ms: retry_delay_max_ms.unwrap_or(defaults.retry_delay_max_ms),
196 heartbeat_interval_secs: heartbeat_interval_secs
197 .unwrap_or(defaults.heartbeat_interval_secs),
198 auth_timeout_secs,
199 recv_window_ms: recv_window_ms.unwrap_or(defaults.recv_window_ms),
200 account_id,
201 use_spot_position_reports: use_spot_position_reports
202 .unwrap_or(defaults.use_spot_position_reports),
203 auto_repay_spot_borrows: auto_repay_spot_borrows
204 .unwrap_or(defaults.auto_repay_spot_borrows),
205 futures_leverages: None,
206 position_mode: None,
207 margin_mode,
208 smp_type,
209 transport_backend: transport_backend.unwrap_or(defaults.transport_backend),
210 })
211 }
212
213 #[getter]
214 #[pyo3(name = "smp_type")]
215 fn py_smp_type(&self) -> Option<String> {
216 self.smp_type.map(|smp_type| smp_type.as_ref().to_string())
217 }
218
219 #[getter]
220 const fn has_proxy_url(&self) -> bool {
221 self.proxy_url.is_some()
222 }
223
224 fn __repr__(&self) -> String {
225 stringify!(BybitExecutionClientConfig).to_string()
226 }
227}