nautilus_bybit/python/
mod.rs1pub mod config;
19pub mod enums;
20pub mod factories;
21pub mod http;
22pub mod params;
23pub mod types;
24
25use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
26use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
27use nautilus_model::enums::{BarAggregation, OrderSide};
28use nautilus_system::get_global_pyo3_registry;
29use pyo3::prelude::*;
30
31use crate::{
32 common::{
33 consts::{BYBIT, BYBIT_CLIENT_ID, BYBIT_VENUE},
34 enums::{BybitOrderSide, BybitPositionIdx, BybitPositionMode},
35 parse::{bar_spec_to_bybit_interval, extract_raw_symbol, resolve_position_idx},
36 symbol::BybitSymbol,
37 },
38 config::{BybitDataClientConfig, BybitExecutionClientConfig},
39 factories::{BybitDataClientFactory, BybitExecutionClientFactory},
40};
41
42#[pyfunction]
49#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.bybit")]
50#[pyo3(name = "bybit_extract_raw_symbol")]
51fn py_bybit_extract_raw_symbol(symbol: &str) -> &str {
52 extract_raw_symbol(symbol)
53}
54
55#[pyfunction]
61#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.bybit")]
62#[pyo3(name = "bybit_bar_spec_to_interval")]
63fn py_bybit_bar_spec_to_interval(aggregation: BarAggregation, step: u64) -> PyResult<String> {
64 let interval = bar_spec_to_bybit_interval(aggregation, step).map_err(to_pyvalue_err)?;
65 Ok(interval.to_string())
66}
67
68#[pyfunction]
80#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.bybit")]
81#[pyo3(name = "bybit_product_type_from_symbol")]
82fn py_bybit_product_type_from_symbol(
83 symbol: &str,
84) -> PyResult<crate::common::enums::BybitProductType> {
85 let bybit_symbol = BybitSymbol::new(symbol).map_err(to_pyvalue_err)?;
86 Ok(bybit_symbol.product_type())
87}
88
89#[pyfunction]
95#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.bybit")]
96#[pyo3(name = "bybit_resolve_position_idx")]
97#[pyo3(signature = (position_mode, order_side, is_reduce_only, manual_override=None))]
98fn py_bybit_resolve_position_idx(
99 position_mode: Option<BybitPositionMode>,
100 order_side: OrderSide,
101 is_reduce_only: bool,
102 manual_override: Option<BybitPositionIdx>,
103) -> Option<BybitPositionIdx> {
104 let bybit_side = BybitOrderSide::from(order_side);
105 resolve_position_idx(position_mode, bybit_side, is_reduce_only, manual_override)
106}
107
108#[expect(clippy::needless_pass_by_value)]
109fn extract_bybit_data_factory(
110 py: Python<'_>,
111 factory: Py<PyAny>,
112) -> PyResult<Box<dyn DataClientFactory>> {
113 match factory.extract::<BybitDataClientFactory>(py) {
114 Ok(f) => Ok(Box::new(f)),
115 Err(e) => Err(to_pyvalue_err(format!(
116 "Failed to extract BybitDataClientFactory: {e}"
117 ))),
118 }
119}
120
121#[expect(clippy::needless_pass_by_value)]
122fn extract_bybit_exec_factory(
123 py: Python<'_>,
124 factory: Py<PyAny>,
125) -> PyResult<Box<dyn ExecutionClientFactory>> {
126 match factory.extract::<BybitExecutionClientFactory>(py) {
127 Ok(f) => Ok(Box::new(f)),
128 Err(e) => Err(to_pyvalue_err(format!(
129 "Failed to extract BybitExecutionClientFactory: {e}"
130 ))),
131 }
132}
133
134#[expect(clippy::needless_pass_by_value)]
135fn extract_bybit_data_config(py: Python<'_>, config: Py<PyAny>) -> PyResult<Box<dyn ClientConfig>> {
136 match config.extract::<BybitDataClientConfig>(py) {
137 Ok(c) => Ok(Box::new(c)),
138 Err(e) => Err(to_pyvalue_err(format!(
139 "Failed to extract BybitDataClientConfig: {e}"
140 ))),
141 }
142}
143
144#[expect(clippy::needless_pass_by_value)]
145fn extract_bybit_exec_config(py: Python<'_>, config: Py<PyAny>) -> PyResult<Box<dyn ClientConfig>> {
146 match config.extract::<BybitExecutionClientConfig>(py) {
147 Ok(c) => Ok(Box::new(c)),
148 Err(e) => Err(to_pyvalue_err(format!(
149 "Failed to extract BybitExecutionClientConfig: {e}"
150 ))),
151 }
152}
153
154#[pymodule]
160#[rustfmt::skip]
161pub fn bybit(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
162 m.add(stringify!(BYBIT), BYBIT)?;
163 m.add(stringify!(BYBIT_CLIENT_ID), *BYBIT_CLIENT_ID)?;
164 m.add(stringify!(BYBIT_VENUE), *BYBIT_VENUE)?;
165 m.add_class::<crate::common::enums::BybitAccountType>()?;
166 m.add_class::<crate::common::enums::BybitCancelType>()?;
167 m.add_class::<crate::common::enums::BybitEnvironment>()?;
168 m.add_class::<crate::common::enums::BybitMarginAction>()?;
169 m.add_class::<crate::common::enums::BybitMarginMode>()?;
170 m.add_class::<crate::common::enums::BybitOpenOnly>()?;
171 m.add_class::<crate::common::enums::BybitOrderFilter>()?;
172 m.add_class::<crate::common::enums::BybitOrderSide>()?;
173 m.add_class::<crate::common::enums::BybitOrderStatus>()?;
174 m.add_class::<crate::common::enums::BybitOrderType>()?;
175 m.add_class::<crate::common::enums::BybitPositionIdx>()?;
176 m.add_class::<crate::common::enums::BybitPositionMode>()?;
177 m.add_class::<crate::common::enums::BybitProductType>()?;
178 m.add_class::<crate::common::enums::BybitStopOrderType>()?;
179 m.add_class::<crate::common::enums::BybitTimeInForce>()?;
180 m.add_class::<crate::common::enums::BybitTpSlMode>()?;
181 m.add_class::<crate::common::enums::BybitTriggerDirection>()?;
182 m.add_class::<crate::common::enums::BybitTriggerType>()?;
183 m.add_class::<crate::http::client::BybitHttpClient>()?;
184 m.add_class::<crate::http::client::BybitRawHttpClient>()?;
185 m.add_class::<crate::http::models::BybitServerTime>()?;
186 m.add_class::<crate::http::models::BybitAccountDetails>()?;
187 m.add_class::<crate::http::models::BybitApiKeyPermissions>()?;
188 m.add_class::<crate::http::models::BybitFeeRate>()?;
189 m.add_class::<crate::http::models::BybitOrder>()?;
190 m.add_class::<crate::http::models::BybitOrderCursorList>()?;
191 m.add_class::<crate::http::models::BybitTickerData>()?;
192 m.add_class::<crate::common::types::BybitMarginBorrowResult>()?;
193 m.add_class::<crate::common::types::BybitMarginRepayResult>()?;
194 m.add_class::<crate::common::types::BybitMarginStatusResult>()?;
195 m.add_class::<params::BybitTickersParams>()?;
196 m.add_class::<params::BybitNativeTpSlParams>()?;
197 m.add_class::<BybitDataClientConfig>()?;
198 m.add_class::<BybitDataClientFactory>()?;
199 m.add_class::<BybitExecutionClientConfig>()?;
200 m.add_class::<BybitExecutionClientFactory>()?;
201 m.add_function(wrap_pyfunction!(py_bybit_extract_raw_symbol, m)?)?;
202 m.add_function(wrap_pyfunction!(py_bybit_bar_spec_to_interval, m)?)?;
203 m.add_function(wrap_pyfunction!(py_bybit_product_type_from_symbol, m)?)?;
204 m.add_function(wrap_pyfunction!(py_bybit_resolve_position_idx, m)?)?;
205
206 let registry = get_global_pyo3_registry();
207
208 if let Err(e) =
209 registry.register_factory_extractor(BYBIT.to_string(), extract_bybit_data_factory)
210 {
211 return Err(to_pyruntime_err(format!(
212 "Failed to register Bybit data factory extractor: {e}"
213 )));
214 }
215
216 if let Err(e) = registry
217 .register_exec_factory_extractor(BYBIT.to_string(), extract_bybit_exec_factory)
218 {
219 return Err(to_pyruntime_err(format!(
220 "Failed to register Bybit exec factory extractor: {e}"
221 )));
222 }
223
224 if let Err(e) = registry.register_config_extractor(
225 "BybitDataClientConfig".to_string(),
226 extract_bybit_data_config,
227 ) {
228 return Err(to_pyruntime_err(format!(
229 "Failed to register Bybit data config extractor: {e}"
230 )));
231 }
232
233 if let Err(e) = registry.register_config_extractor(
234 "BybitExecutionClientConfig".to_string(),
235 extract_bybit_exec_config,
236 ) {
237 return Err(to_pyruntime_err(format!(
238 "Failed to register Bybit exec config extractor: {e}"
239 )));
240 }
241
242 Ok(())
243}