nautilus_bybit/python/
mod.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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 from `pyo3`.
17
18pub mod enums;
19pub mod http;
20pub mod params;
21pub mod types;
22pub mod urls;
23pub mod websocket;
24
25use nautilus_core::python::to_pyvalue_err;
26use nautilus_model::enums::BarAggregation;
27use pyo3::prelude::*;
28
29use crate::common::{
30    consts::BYBIT_NAUTILUS_BROKER_ID,
31    parse::{bar_spec_to_bybit_interval, extract_raw_symbol},
32    symbol::BybitSymbol,
33};
34
35/// Extracts the raw symbol from a Bybit symbol by removing the product type suffix.
36///
37/// # Examples
38/// - `"ETHUSDT-LINEAR"` → `"ETHUSDT"`
39/// - `"BTCUSDT-SPOT"` → `"BTCUSDT"`
40/// - `"ETHUSDT"` → `"ETHUSDT"` (no suffix)
41#[pyfunction]
42#[pyo3(name = "bybit_extract_raw_symbol")]
43fn py_bybit_extract_raw_symbol(symbol: &str) -> &str {
44    extract_raw_symbol(symbol)
45}
46
47/// Converts a Nautilus bar aggregation and step to a Bybit kline interval string.
48///
49/// # Errors
50///
51/// Returns an error if the aggregation type or step is not supported by Bybit.
52#[pyfunction]
53#[pyo3(name = "bybit_bar_spec_to_interval")]
54fn py_bybit_bar_spec_to_interval(aggregation: u8, step: u64) -> PyResult<String> {
55    let aggregation = BarAggregation::from_repr(aggregation as usize).ok_or_else(|| {
56        pyo3::exceptions::PyValueError::new_err(format!(
57            "Invalid BarAggregation value: {aggregation}"
58        ))
59    })?;
60    let interval = bar_spec_to_bybit_interval(aggregation, step).map_err(to_pyvalue_err)?;
61    Ok(interval.to_string())
62}
63
64/// Extracts the product type from a Bybit symbol.
65///
66/// # Examples
67/// - `"ETHUSDT-LINEAR"` → `BybitProductType.LINEAR`
68/// - `"BTCUSDT-SPOT"` → `BybitProductType.SPOT`
69/// - `"BTCUSD-INVERSE"` → `BybitProductType.INVERSE`
70/// - `"ETH-26JUN26-16000-P-OPTION"` → `BybitProductType.OPTION`
71///
72/// # Errors
73///
74/// Returns an error if the symbol does not contain a valid Bybit product type suffix.
75#[pyfunction]
76#[pyo3(name = "bybit_product_type_from_symbol")]
77fn py_bybit_product_type_from_symbol(
78    symbol: &str,
79) -> PyResult<crate::common::enums::BybitProductType> {
80    let bybit_symbol = BybitSymbol::new(symbol).map_err(to_pyvalue_err)?;
81    Ok(bybit_symbol.product_type())
82}
83
84/// Loaded as `nautilus_pyo3.bybit`.
85///
86/// # Errors
87///
88/// Returns an error if any bindings fail to register with the Python module.
89#[pymodule]
90#[rustfmt::skip]
91pub fn bybit(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
92    m.add(stringify!(BYBIT_NAUTILUS_BROKER_ID), BYBIT_NAUTILUS_BROKER_ID)?;
93    m.add_class::<crate::common::enums::BybitAccountType>()?;
94    m.add_class::<crate::common::enums::BybitCancelType>()?;
95    m.add_class::<crate::common::enums::BybitEnvironment>()?;
96    m.add_class::<crate::common::enums::BybitMarginAction>()?;
97    m.add_class::<crate::common::enums::BybitMarginMode>()?;
98    m.add_class::<crate::common::enums::BybitOpenOnly>()?;
99    m.add_class::<crate::common::enums::BybitOrderFilter>()?;
100    m.add_class::<crate::common::enums::BybitOrderSide>()?;
101    m.add_class::<crate::common::enums::BybitOrderStatus>()?;
102    m.add_class::<crate::common::enums::BybitOrderType>()?;
103    m.add_class::<crate::common::enums::BybitPositionMode>()?;
104    m.add_class::<crate::common::enums::BybitProductType>()?;
105    m.add_class::<crate::common::enums::BybitStopOrderType>()?;
106    m.add_class::<crate::common::enums::BybitTimeInForce>()?;
107    m.add_class::<crate::common::enums::BybitTpSlMode>()?;
108    m.add_class::<crate::common::enums::BybitTriggerDirection>()?;
109    m.add_class::<crate::common::enums::BybitTriggerType>()?;
110    m.add_class::<crate::http::client::BybitHttpClient>()?;
111    m.add_class::<crate::http::client::BybitRawHttpClient>()?;
112    m.add_class::<crate::http::models::BybitServerTime>()?;
113    m.add_class::<crate::http::models::BybitOrder>()?;
114    m.add_class::<crate::http::models::BybitOrderCursorList>()?;
115    m.add_class::<crate::http::models::BybitTickerData>()?;
116    m.add_class::<crate::common::types::BybitMarginBorrowResult>()?;
117    m.add_class::<crate::common::types::BybitMarginRepayResult>()?;
118    m.add_class::<crate::common::types::BybitMarginStatusResult>()?;
119    m.add_class::<crate::websocket::client::BybitWebSocketClient>()?;
120    m.add_class::<crate::websocket::messages::BybitWebSocketError>()?;
121    m.add_class::<params::BybitWsPlaceOrderParams>()?;
122    m.add_class::<params::BybitWsAmendOrderParams>()?;
123    m.add_class::<params::BybitWsCancelOrderParams>()?;
124    m.add_class::<params::BybitTickersParams>()?;
125    m.add_function(wrap_pyfunction!(urls::py_get_bybit_http_base_url, m)?)?;
126    m.add_function(wrap_pyfunction!(urls::py_get_bybit_ws_url_public, m)?)?;
127    m.add_function(wrap_pyfunction!(urls::py_get_bybit_ws_url_private, m)?)?;
128    m.add_function(wrap_pyfunction!(urls::py_get_bybit_ws_url_trade, m)?)?;
129    m.add_function(wrap_pyfunction!(py_bybit_extract_raw_symbol, m)?)?;
130    m.add_function(wrap_pyfunction!(py_bybit_bar_spec_to_interval, m)?)?;
131    m.add_function(wrap_pyfunction!(py_bybit_product_type_from_symbol, m)?)?;
132    Ok(())
133}