use std::fmt::Display;
use chrono::{DateTime, Datelike, TimeZone, Utc};
use nautilus_model::enums::{AggressorSide, OrderSide, TriggerType};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use strum::{AsRefStr, EnumIter, EnumString};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
#[repr(i32)]
pub enum BybitUnifiedMarginStatus {
ClassicAccount = 1,
UnifiedTradingAccount10 = 3,
UnifiedTradingAccount10Pro = 4,
UnifiedTradingAccount20 = 5,
UnifiedTradingAccount20Pro = 6,
}
#[derive(
Clone,
Copy,
Debug,
strum::Display,
Eq,
PartialEq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize,
Deserialize,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitMarginMode {
IsolatedMargin,
RegularMargin,
PortfolioMargin,
}
#[derive(
Clone,
Copy,
Debug,
strum::Display,
Eq,
PartialEq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize_repr,
Deserialize_repr,
)]
#[repr(i32)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitPositionMode {
MergedSingle = 0,
BothSides = 3,
}
#[derive(
Clone,
Copy,
Debug,
strum::Display,
Eq,
PartialEq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize_repr,
Deserialize_repr,
)]
#[repr(i32)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitPositionIdx {
OneWay = 0,
BuyHedge = 1,
SellHedge = 2,
}
#[derive(
Copy,
Clone,
Debug,
strum::Display,
PartialEq,
Eq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize,
Deserialize,
)]
#[serde(rename_all = "UPPERCASE")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitAccountType {
Unified,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum BybitApiKeyType {
Hmac = 1,
Rsa = 2,
}
#[derive(
Copy,
Clone,
Debug,
strum::Display,
PartialEq,
Eq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize,
Deserialize,
)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitEnvironment {
Mainnet,
Demo,
Testnet,
}
#[derive(
Copy,
Clone,
Debug,
strum::Display,
Default,
PartialEq,
Eq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize,
Deserialize,
)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitProductType {
#[default]
Spot,
Linear,
Inverse,
Option,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitMarginTrading {
#[serde(rename = "none")]
None,
#[serde(rename = "utaOnly")]
UtaOnly,
#[serde(rename = "both")]
Both,
#[serde(other)]
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitInnovationFlag {
#[serde(rename = "0")]
Standard,
#[serde(rename = "1")]
Innovation,
#[serde(other)]
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BybitInstrumentStatus {
PreLaunch,
Trading,
Delivering,
Closed,
#[serde(other)]
Other,
}
impl BybitProductType {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Spot => "spot",
Self::Linear => "linear",
Self::Inverse => "inverse",
Self::Option => "option",
}
}
#[must_use]
pub const fn suffix(self) -> &'static str {
match self {
Self::Spot => "-SPOT",
Self::Linear => "-LINEAR",
Self::Inverse => "-INVERSE",
Self::Option => "-OPTION",
}
}
#[must_use]
pub fn from_suffix(symbol: &str) -> Option<Self> {
if symbol.ends_with("-SPOT") {
Some(Self::Spot)
} else if symbol.ends_with("-LINEAR") {
Some(Self::Linear)
} else if symbol.ends_with("-INVERSE") {
Some(Self::Inverse)
} else if symbol.ends_with("-OPTION") {
Some(Self::Option)
} else {
None
}
}
#[must_use]
pub fn is_spot(self) -> bool {
matches!(self, Self::Spot)
}
#[must_use]
pub fn is_linear(self) -> bool {
matches!(self, Self::Linear)
}
#[must_use]
pub fn is_inverse(self) -> bool {
matches!(self, Self::Inverse)
}
#[must_use]
pub fn is_option(self) -> bool {
matches!(self, Self::Option)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BybitContractType {
LinearPerpetual,
LinearFutures,
InversePerpetual,
InverseFutures,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BybitOptionType {
Call,
Put,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BybitSymbolType {
Xstocks,
Stock,
Forex,
Commodity,
#[serde(other)]
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitPositionSide {
#[serde(rename = "")]
Flat,
#[serde(rename = "Buy")]
Buy,
#[serde(rename = "Sell")]
Sell,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitWsOrderRequestOp {
#[serde(rename = "order.create")]
Create,
#[serde(rename = "order.amend")]
Amend,
#[serde(rename = "order.cancel")]
Cancel,
#[serde(rename = "order.create-batch")]
CreateBatch,
#[serde(rename = "order.amend-batch")]
AmendBatch,
#[serde(rename = "order.cancel-batch")]
CancelBatch,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitKlineInterval {
#[serde(rename = "1")]
Minute1,
#[serde(rename = "3")]
Minute3,
#[serde(rename = "5")]
Minute5,
#[serde(rename = "15")]
Minute15,
#[serde(rename = "30")]
Minute30,
#[serde(rename = "60")]
Hour1,
#[serde(rename = "120")]
Hour2,
#[serde(rename = "240")]
Hour4,
#[serde(rename = "360")]
Hour6,
#[serde(rename = "720")]
Hour12,
#[serde(rename = "D")]
Day1,
#[serde(rename = "W")]
Week1,
#[serde(rename = "M")]
Month1,
}
impl BybitKlineInterval {
#[must_use]
pub fn bar_end_time_ms(&self, start_ms: i64) -> i64 {
match self {
Self::Month1 => {
let start_dt = DateTime::from_timestamp_millis(start_ms)
.unwrap_or_else(|| Utc.timestamp_millis_opt(0).unwrap());
let (year, month) = if start_dt.month() == 12 {
(start_dt.year() + 1, 1)
} else {
(start_dt.year(), start_dt.month() + 1)
};
Utc.with_ymd_and_hms(year, month, 1, 0, 0, 0)
.single()
.map_or(start_ms + 2_678_400_000, |dt| dt.timestamp_millis())
}
_ => start_ms + self.duration_ms(),
}
}
#[must_use]
pub const fn duration_ms(&self) -> i64 {
match self {
Self::Minute1 => 60_000,
Self::Minute3 => 180_000,
Self::Minute5 => 300_000,
Self::Minute15 => 900_000,
Self::Minute30 => 1_800_000,
Self::Hour1 => 3_600_000,
Self::Hour2 => 7_200_000,
Self::Hour4 => 14_400_000,
Self::Hour6 => 21_600_000,
Self::Hour12 => 43_200_000,
Self::Day1 => 86_400_000,
Self::Week1 => 604_800_000,
Self::Month1 => 2_678_400_000, }
}
}
impl Display for BybitKlineInterval {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::Minute1 => "1",
Self::Minute3 => "3",
Self::Minute5 => "5",
Self::Minute15 => "15",
Self::Minute30 => "30",
Self::Hour1 => "60",
Self::Hour2 => "120",
Self::Hour4 => "240",
Self::Hour6 => "360",
Self::Hour12 => "720",
Self::Day1 => "D",
Self::Week1 => "W",
Self::Month1 => "M",
};
write!(f, "{s}")
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitOrderStatus {
#[serde(rename = "Created")]
Created,
#[serde(rename = "New")]
New,
#[serde(rename = "Rejected")]
Rejected,
#[serde(rename = "PartiallyFilled")]
PartiallyFilled,
#[serde(rename = "PartiallyFilledCanceled")]
PartiallyFilledCanceled,
#[serde(rename = "Filled")]
Filled,
#[serde(rename = "Cancelled")]
Canceled,
#[serde(rename = "Untriggered")]
Untriggered,
#[serde(rename = "Triggered")]
Triggered,
#[serde(rename = "Deactivated")]
Deactivated,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitOrderSide {
#[serde(rename = "")]
Unknown,
#[serde(rename = "Buy")]
Buy,
#[serde(rename = "Sell")]
Sell,
}
impl From<BybitOrderSide> for AggressorSide {
fn from(value: BybitOrderSide) -> Self {
match value {
BybitOrderSide::Buy => Self::Buyer,
BybitOrderSide::Sell => Self::Seller,
BybitOrderSide::Unknown => Self::NoAggressor,
}
}
}
impl From<BybitOrderSide> for OrderSide {
fn from(value: BybitOrderSide) -> Self {
match value {
BybitOrderSide::Buy => Self::Buy,
BybitOrderSide::Sell => Self::Sell,
BybitOrderSide::Unknown => Self::NoOrderSide,
}
}
}
impl TryFrom<OrderSide> for BybitOrderSide {
type Error = anyhow::Error;
fn try_from(value: OrderSide) -> Result<Self, Self::Error> {
match value {
OrderSide::Buy => Ok(Self::Buy),
OrderSide::Sell => Ok(Self::Sell),
_ => anyhow::bail!("unsupported OrderSide for Bybit: {value:?}"),
}
}
}
impl From<BybitTriggerType> for TriggerType {
fn from(value: BybitTriggerType) -> Self {
match value {
BybitTriggerType::None => Self::Default,
BybitTriggerType::LastPrice => Self::LastPrice,
BybitTriggerType::IndexPrice => Self::IndexPrice,
BybitTriggerType::MarkPrice => Self::MarkPrice,
}
}
}
impl From<TriggerType> for BybitTriggerType {
fn from(value: TriggerType) -> Self {
match value {
TriggerType::Default | TriggerType::LastPrice | TriggerType::NoTrigger => {
Self::LastPrice
}
TriggerType::IndexPrice => Self::IndexPrice,
TriggerType::MarkPrice => Self::MarkPrice,
_ => Self::LastPrice,
}
}
}
pub fn resolve_trigger_type(trigger_type: Option<TriggerType>) -> BybitTriggerType {
trigger_type.map_or(BybitTriggerType::LastPrice, BybitTriggerType::from)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitCancelType {
CancelByUser,
CancelByReduceOnly,
CancelByPrepareLackOfMargin,
CancelByPrepareOrderFilter,
CancelByPrepareOrderMarginCheckFailed,
CancelByPrepareOrderCommission,
CancelByPrepareOrderRms,
CancelByPrepareOrderOther,
CancelByRiskLimit,
CancelOnDisconnect,
CancelByStopOrdersExceeded,
CancelByPzMarketClose,
CancelByMarginCheckFailed,
CancelByPzTakeover,
CancelByAdmin,
CancelByTpSlTsClear,
CancelByAmendNotModified,
CancelByPzCancel,
CancelByCrossSelfMatch,
CancelBySelfMatchPrevention,
#[serde(other)]
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BybitCreateType {
CreateByUser,
CreateByClosing,
CreateByTakeProfit,
CreateByStopLoss,
CreateByTrailingStop,
CreateByStopOrder,
CreateByPartialTakeProfit,
CreateByPartialStopLoss,
CreateByAdl,
CreateByLiquidate,
CreateByTakeover,
CreateByTpsl,
CreateByBboOrder,
#[serde(other)]
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BybitBboSideType {
Queue,
Counterparty,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitOrderType {
#[serde(rename = "Market")]
Market,
#[serde(rename = "Limit")]
Limit,
#[serde(rename = "UNKNOWN")]
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitStopOrderType {
#[serde(rename = "")]
None,
#[serde(rename = "UNKNOWN")]
Unknown,
#[serde(rename = "TakeProfit")]
TakeProfit,
#[serde(rename = "StopLoss")]
StopLoss,
#[serde(rename = "TrailingStop")]
TrailingStop,
#[serde(rename = "Stop")]
Stop,
#[serde(rename = "PartialTakeProfit")]
PartialTakeProfit,
#[serde(rename = "PartialStopLoss")]
PartialStopLoss,
#[serde(rename = "tpslOrder")]
TpslOrder,
#[serde(rename = "OcoOrder")]
OcoOrder,
#[serde(rename = "MmRateClose")]
MmRateClose,
#[serde(rename = "BidirectionalTpslOrder")]
BidirectionalTpslOrder,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitTriggerType {
#[serde(rename = "")]
None,
#[serde(rename = "LastPrice")]
LastPrice,
#[serde(rename = "IndexPrice")]
IndexPrice,
#[serde(rename = "MarkPrice")]
MarkPrice,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
#[repr(i32)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitTriggerDirection {
None = 0,
RisesTo = 1,
FallsTo = 2,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitTpSlMode {
Full,
Partial,
#[serde(other)]
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitTimeInForce {
#[serde(rename = "GTC")]
Gtc,
#[serde(rename = "IOC")]
Ioc,
#[serde(rename = "FOK")]
Fok,
#[serde(rename = "PostOnly")]
PostOnly,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitExecType {
#[serde(rename = "Trade")]
Trade,
#[serde(rename = "AdlTrade")]
AdlTrade,
#[serde(rename = "Funding")]
Funding,
#[serde(rename = "BustTrade")]
BustTrade,
#[serde(rename = "Delivery")]
Delivery,
#[serde(rename = "Settle")]
Settle,
#[serde(rename = "BlockTrade")]
BlockTrade,
#[serde(rename = "MovePosition")]
MovePosition,
#[serde(rename = "UNKNOWN")]
Unknown,
}
impl BybitExecType {
#[must_use]
pub const fn is_exchange_generated(&self) -> bool {
matches!(
self,
Self::AdlTrade | Self::BustTrade | Self::Delivery | Self::Settle
)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitTransactionType {
#[serde(rename = "TRANSFER_IN")]
TransferIn,
#[serde(rename = "TRANSFER_OUT")]
TransferOut,
#[serde(rename = "TRADE")]
Trade,
#[serde(rename = "SETTLEMENT")]
Settlement,
#[serde(rename = "DELIVERY")]
Delivery,
#[serde(rename = "LIQUIDATION")]
Liquidation,
#[serde(rename = "AIRDRP")]
Airdrop,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum BybitEndpointType {
None,
Asset,
Market,
Account,
Trade,
Position,
User,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Serialize_repr, Deserialize_repr)]
#[repr(i32)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitOpenOnly {
#[default]
OpenOnly = 0,
ClosedRecent = 1,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
module = "nautilus_trader.core.nautilus_pyo3.bybit",
eq,
eq_int,
from_py_object
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitOrderFilter {
#[default]
Order,
StopOrder,
#[serde(rename = "tpslOrder")]
TpslOrder,
OcoOrder,
BidirectionalTpslOrder,
}
#[derive(
Clone,
Copy,
Debug,
strum::Display,
Eq,
PartialEq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize,
Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[cfg_attr(
feature = "python",
pyo3::pyclass(
eq,
eq_int,
hash,
frozen,
rename_all = "SCREAMING_SNAKE_CASE",
module = "nautilus_trader.core.nautilus_pyo3.bybit",
from_py_object,
)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.bybit")
)]
pub enum BybitMarginAction {
Borrow,
Repay,
GetBorrowAmount,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BybitPositionStatus {
Normal,
Settle,
Delivering,
#[serde(other)]
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitMarketUnit {
#[serde(rename = "baseCoin")]
BaseCoin,
#[serde(rename = "quoteCoin")]
QuoteCoin,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum BybitSmpType {
None,
CancelMaker,
CancelTaker,
CancelBoth,
#[serde(other)]
Other,
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case::minute1(BybitKlineInterval::Minute1, 60_000)]
#[case::minute3(BybitKlineInterval::Minute3, 180_000)]
#[case::minute5(BybitKlineInterval::Minute5, 300_000)]
#[case::minute15(BybitKlineInterval::Minute15, 900_000)]
#[case::minute30(BybitKlineInterval::Minute30, 1_800_000)]
#[case::hour1(BybitKlineInterval::Hour1, 3_600_000)]
#[case::hour2(BybitKlineInterval::Hour2, 7_200_000)]
#[case::hour4(BybitKlineInterval::Hour4, 14_400_000)]
#[case::hour6(BybitKlineInterval::Hour6, 21_600_000)]
#[case::hour12(BybitKlineInterval::Hour12, 43_200_000)]
#[case::day1(BybitKlineInterval::Day1, 86_400_000)]
#[case::week1(BybitKlineInterval::Week1, 604_800_000)]
#[case::month1(BybitKlineInterval::Month1, 2_678_400_000)]
fn test_kline_interval_duration_ms(
#[case] interval: BybitKlineInterval,
#[case] expected_ms: i64,
) {
assert_eq!(interval.duration_ms(), expected_ms);
}
#[rstest]
fn test_bar_end_time_ms_non_monthly_adds_duration() {
let interval = BybitKlineInterval::Minute1;
let start_ms = 1704067200000i64;
assert_eq!(interval.bar_end_time_ms(start_ms), start_ms + 60_000);
}
#[rstest]
#[case::jan_31_days(1704067200000i64, 1706745600000i64)]
#[case::feb_leap_year_29_days(1706745600000i64, 1709251200000i64)]
#[case::apr_30_days(1711929600000i64, 1714521600000i64)]
#[case::dec_to_next_year(1733011200000i64, 1735689600000i64)]
fn test_bar_end_time_ms_monthly_variable_lengths(
#[case] start_ms: i64,
#[case] expected_end_ms: i64,
) {
let interval = BybitKlineInterval::Month1;
assert_eq!(interval.bar_end_time_ms(start_ms), expected_end_ms);
}
#[rstest]
#[case(BybitExecType::Trade, false)]
#[case(BybitExecType::AdlTrade, true)]
#[case(BybitExecType::BustTrade, true)]
#[case(BybitExecType::Delivery, true)]
#[case(BybitExecType::Settle, true)]
#[case(BybitExecType::Funding, false)]
fn test_exec_type_is_exchange_generated(
#[case] exec_type: BybitExecType,
#[case] expected: bool,
) {
assert_eq!(exec_type.is_exchange_generated(), expected);
}
}