Skip to main content

bybit/models/return_codes/
uta.rs

1use crate::prelude::*;
2
3/// Enum representing Bybit API V5 UTA error codes.
4///
5/// See: https://bybit-exchange.github.io/docs/v5/error#uta
6#[derive(Clone, Copy, PartialEq, Eq, Hash, Display, derive_more::Debug, derive_more::From)]
7#[repr(i32)]
8#[display("{} - {}", *self as i32, self.message())]
9pub enum UtaCode {
10    /// Invalid parameter(s).
11    InvalidParameters = 10001,
12
13    /// Invalid request: server error or request timeout.
14    InvalidRequest = 10002,
15
16    /// API key is invalid.
17    InvalidApiKey = 10003,
18
19    /// Signature error.
20    SignatureError = 10004,
21
22    /// Permission denied.
23    PermissionDenied = 10005,
24
25    /// Too many visits, exceeding IP limit.
26    TooManyVisits = 10006,
27
28    /// Unmatched IP: API key not bound to this IP.
29    UnmatchedIp = 10010,
30
31    /// Order does not exist.
32    OrderNotExist = 110001,
33
34    /// Insufficient balance in account.
35    InsufficientBalance = 110002,
36
37    /// Position does not exist.
38    PositionNotExist = 110003,
39
40    /// Insufficient margin in account.
41    InsufficientMargin = 110004,
42
43    /// Insufficient position size.
44    InsufficientPositionSize = 110005,
45
46    /// Position mode error: cannot change position mode when position exists.
47    PositionModeError = 110006,
48
49    /// Symbol not found.
50    SymbolNotFound = 110007,
51
52    /// Currency not supported.
53    CurrencyNotSupported = 110008,
54
55    /// Invalid stop order.
56    StopOrderInvalid = 110009,
57
58    /// Invalid price.
59    PriceInvalid = 110010,
60
61    /// Order quantity invalid.
62    OrderQtyInvalid = 110011,
63
64    /// Invalid order type.
65    OrderTypeInvalid = 110012,
66
67    /// Leverage not modified.
68    LeverageNotModified = 110013,
69
70    /// Leverage setting error.
71    LeverageSettingError = 110014,
72
73    /// Invalid take profit/stop loss setting.
74    TpSlSettingInvalid = 110015,
75
76    /// Order price deviates significantly from market price.
77    OrderPriceDeviate = 110017,
78
79    /// Order already cancelled.
80    OrderAlreadyCancelled = 110019,
81
82    /// Order already filled.
83    OrderAlreadyFilled = 110020,
84
85    /// Trigger price invalid.
86    TriggerPriceInvalid = 110021,
87
88    /// Reduce-only error.
89    ReduceOnlyError = 110022,
90
91    /// Invalid time-in-force.
92    TimeInForceInvalid = 110023,
93
94    /// Invalid order side.
95    OrderSideInvalid = 110024,
96
97    /// Invalid position mode.
98    PositionModeInvalid = 110025,
99
100    /// Order price is lower than liquidation price.
101    PriceLowerThanLiquidation = 110026,
102
103    /// No need to change margin.
104    MarginChangeNotNeeded = 110027,
105
106    /// Order creation timeout.
107    OrderCreationTimeout = 110028,
108
109    /// Order type not supported.
110    OrderTypeNotSupported = 110029,
111
112    /// Invalid trigger price type.
113    TriggerPriceTypeInvalid = 110030,
114
115    /// Invalid stop loss price.
116    StopLossPriceInvalid = 110031,
117
118    /// Invalid take profit price.
119    TakeProfitPriceInvalid = 110032,
120
121    /// Stop loss/take profit quantity invalid.
122    TpSlQtyInvalid = 110033,
123
124    /// Stop loss/take profit price type invalid.
125    TpSlPriceTypeInvalid = 110034,
126
127    /// Order creation failed.
128    OrderCreationFailed = 110035,
129
130    /// Order cancellation failed.
131    OrderCancellationFailed = 110036,
132
133    /// Order amend failed.
134    OrderAmendFailed = 110037,
135
136    /// Risk limit not modified.
137    RiskLimitNotModified = 110038,
138
139    /// Invalid risk ID.
140    RiskIdInvalid = 110039,
141
142    /// Non-UTA users cannot access Pre-Market Perpetual Trading.
143    NonUtaPreMarket = 110097,
144
145    /// Only Good-Till-Canceled (GTC) orders supported during Call Auction.
146    GtcOnlyCallAuction = 110098,
147}
148
149impl UtaCode {
150    /// Converts an error code (as i32 or &str) to a UtaError variant.
151    /// Returns None if the code doesn't match any variant.
152    pub fn from_code<T>(code: T) -> Option<Self>
153    where
154        T: Into<i32> + Copy,
155    {
156        let code = code.into();
157        match code {
158            10001 => Some(Self::InvalidParameters),
159            10002 => Some(Self::InvalidRequest),
160            10003 => Some(Self::InvalidApiKey),
161            10004 => Some(Self::SignatureError),
162            10005 => Some(Self::PermissionDenied),
163            10006 => Some(Self::TooManyVisits),
164            10010 => Some(Self::UnmatchedIp),
165            110001 => Some(Self::OrderNotExist),
166            110002 => Some(Self::InsufficientBalance),
167            110003 => Some(Self::PositionNotExist),
168            110004 => Some(Self::InsufficientMargin),
169            110005 => Some(Self::InsufficientPositionSize),
170            110006 => Some(Self::PositionModeError),
171            110007 => Some(Self::SymbolNotFound),
172            110008 => Some(Self::CurrencyNotSupported),
173            110009 => Some(Self::StopOrderInvalid),
174            110010 => Some(Self::PriceInvalid),
175            110011 => Some(Self::OrderQtyInvalid),
176            110012 => Some(Self::OrderTypeInvalid),
177            110013 => Some(Self::LeverageNotModified),
178            110014 => Some(Self::LeverageSettingError),
179            110015 => Some(Self::TpSlSettingInvalid),
180            110017 => Some(Self::OrderPriceDeviate),
181            110019 => Some(Self::OrderAlreadyCancelled),
182            110020 => Some(Self::OrderAlreadyFilled),
183            110021 => Some(Self::TriggerPriceInvalid),
184            110022 => Some(Self::ReduceOnlyError),
185            110023 => Some(Self::TimeInForceInvalid),
186            110024 => Some(Self::OrderSideInvalid),
187            110025 => Some(Self::PositionModeInvalid),
188            110026 => Some(Self::PriceLowerThanLiquidation),
189            110027 => Some(Self::MarginChangeNotNeeded),
190            110028 => Some(Self::OrderCreationTimeout),
191            110029 => Some(Self::OrderTypeNotSupported),
192            110030 => Some(Self::TriggerPriceTypeInvalid),
193            110031 => Some(Self::StopLossPriceInvalid),
194            110032 => Some(Self::TakeProfitPriceInvalid),
195            110033 => Some(Self::TpSlQtyInvalid),
196            110034 => Some(Self::TpSlPriceTypeInvalid),
197            110035 => Some(Self::OrderCreationFailed),
198            110036 => Some(Self::OrderCancellationFailed),
199            110037 => Some(Self::OrderAmendFailed),
200            110038 => Some(Self::RiskLimitNotModified),
201            110039 => Some(Self::RiskIdInvalid),
202            110097 => Some(Self::NonUtaPreMarket),
203            110098 => Some(Self::GtcOnlyCallAuction),
204            _ => None,
205        }
206    }
207
208    /// Returns the error message associated with the error code.
209    pub fn message(&self) -> &'static str {
210        match self {
211            Self::InvalidParameters => "Invalid parameter(s).",
212            Self::InvalidRequest => "Invalid request: server error or request timeout.",
213            Self::InvalidApiKey => "API key is invalid.",
214            Self::SignatureError => "Signature error.",
215            Self::PermissionDenied => "Permission denied.",
216            Self::TooManyVisits => "Too many visits, exceeding IP limit.",
217            Self::UnmatchedIp => "Unmatched IP: API key not bound to this IP.",
218            Self::OrderNotExist => "Order does not exist.",
219            Self::InsufficientBalance => "Insufficient balance in account.",
220            Self::PositionNotExist => "Position does not exist.",
221            Self::InsufficientMargin => "Insufficient margin in account.",
222            Self::InsufficientPositionSize => "Insufficient position size.",
223            Self::PositionModeError => {
224                "Position mode error: cannot change position mode when position exists."
225            }
226            Self::SymbolNotFound => "Symbol not found.",
227            Self::CurrencyNotSupported => "Currency not supported.",
228            Self::StopOrderInvalid => "Invalid stop order.",
229            Self::PriceInvalid => "Invalid price.",
230            Self::OrderQtyInvalid => "Order quantity invalid.",
231            Self::OrderTypeInvalid => "Invalid order type.",
232            Self::LeverageNotModified => "Leverage not modified.",
233            Self::LeverageSettingError => "Leverage setting error.",
234            Self::TpSlSettingInvalid => "Invalid take profit/stop loss setting.",
235            Self::OrderPriceDeviate => "Order price deviates significantly from market price.",
236            Self::OrderAlreadyCancelled => "Order already cancelled.",
237            Self::OrderAlreadyFilled => "Order already filled.",
238            Self::TriggerPriceInvalid => "Trigger price invalid.",
239            Self::ReduceOnlyError => "Reduce-only error.",
240            Self::TimeInForceInvalid => "Invalid time-in-force.",
241            Self::OrderSideInvalid => "Invalid order side.",
242            Self::PositionModeInvalid => "Invalid position mode.",
243            Self::PriceLowerThanLiquidation => "Order price is lower than liquidation price.",
244            Self::MarginChangeNotNeeded => "No need to change margin.",
245            Self::OrderCreationTimeout => "Order creation timeout.",
246            Self::OrderTypeNotSupported => "Order type not supported.",
247            Self::TriggerPriceTypeInvalid => "Invalid trigger price type.",
248            Self::StopLossPriceInvalid => "Invalid stop loss price.",
249            Self::TakeProfitPriceInvalid => "Invalid take profit price.",
250            Self::TpSlQtyInvalid => "Stop loss/take profit quantity invalid.",
251            Self::TpSlPriceTypeInvalid => "Stop loss/take profit price type invalid.",
252            Self::OrderCreationFailed => "Order creation failed.",
253            Self::OrderCancellationFailed => "Order cancellation failed.",
254            Self::OrderAmendFailed => "Order amend failed.",
255            Self::RiskLimitNotModified => "Risk limit not modified.",
256            Self::RiskIdInvalid => "Invalid risk ID.",
257            Self::NonUtaPreMarket => "Non-UTA users cannot access Pre-Market Perpetual Trading.",
258            Self::GtcOnlyCallAuction => {
259                "Only Good-Till-Canceled (GTC) orders supported during Call Auction."
260            }
261        }
262    }
263}
264
265#[cfg(test)]
266mod tests {
267    use super::*;
268
269    type Sut = UtaCode;
270
271    #[test]
272    fn test_from_code_i32() {
273        assert_eq!(Sut::from_code(10001), Some(Sut::InvalidParameters));
274        assert_eq!(Sut::from_code(110097), Some(Sut::NonUtaPreMarket));
275        assert_eq!(Sut::from_code(99999), None);
276    }
277
278    #[test]
279    fn test_message() {
280        assert_eq!(Sut::InvalidParameters.message(), "Invalid parameter(s).");
281        assert_eq!(
282            Sut::NonUtaPreMarket.message(),
283            "Non-UTA users cannot access Pre-Market Perpetual Trading."
284        );
285    }
286}