1use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::str::FromStr;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
10pub enum Side {
11 Buy,
13 Sell,
15}
16
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
19#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
20pub enum TimeInForce {
21 #[serde(rename = "gtc")]
23 #[default]
24 GTC,
25 #[serde(rename = "ioc")]
27 IOC,
28 #[serde(rename = "fok")]
30 FOK,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
35#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
36pub enum OptionType {
37 #[serde(rename = "CALL", alias = "Call", alias = "call")]
39 Call,
40 #[serde(rename = "PUT", alias = "Put", alias = "put")]
42 Put,
43}
44
45impl OptionType {
46 pub const fn as_db_str(self) -> &'static str {
47 match self {
48 Self::Call => "call",
49 Self::Put => "put",
50 }
51 }
52
53 pub const fn is_call(self) -> bool {
54 matches!(self, Self::Call)
55 }
56}
57
58impl fmt::Display for OptionType {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.write_str(self.as_db_str())
61 }
62}
63
64impl FromStr for OptionType {
65 type Err = ();
66
67 fn from_str(value: &str) -> Result<Self, Self::Err> {
68 if value.eq_ignore_ascii_case("call") {
69 return Ok(Self::Call);
70 }
71 if value.eq_ignore_ascii_case("put") {
72 return Ok(Self::Put);
73 }
74 Err(())
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
80#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
81pub enum OrderStatus {
82 #[serde(rename = "ACKED", alias = "ACK")]
84 Acked,
85 #[serde(rename = "OPEN_ORDER", alias = "OPEN")]
87 OpenOrder,
88 #[serde(
90 rename = "REJECT_ORDER",
91 alias = "REJECT",
92 alias = "REJECTED",
93 alias = "Rejected"
94 )]
95 RejectOrder,
96 #[serde(rename = "FILLED", alias = "Filled")]
98 Filled,
99 #[serde(rename = "PARTIALLY_FILLED", alias = "PartiallyFilled")]
101 PartiallyFilled,
102 #[serde(rename = "CANCELED", alias = "CANCELLED")]
104 Canceled,
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
109#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
110pub enum OrderUpdateStatus {
111 #[serde(rename = "ACKED")]
113 Acked,
114 #[serde(rename = "OPEN")]
116 Open,
117 #[serde(rename = "PARTIALLY_FILLED")]
119 PartiallyFilled,
120 #[serde(rename = "FILLED")]
122 Filled,
123 #[serde(rename = "CANCELED")]
125 Canceled,
126 #[serde(rename = "REJECTED")]
128 Rejected,
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
133#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
134pub enum TradeSide {
135 #[serde(rename = "BUY", alias = "Buy", alias = "buy")]
136 Buy,
137 #[serde(rename = "SELL", alias = "Sell", alias = "sell")]
138 Sell,
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
143pub enum MarketAction {
144 #[serde(rename = "CREATE_MARKET")]
145 CreateMarket,
146 #[serde(rename = "DELETE_MARKET")]
147 DeleteMarket,
148 #[serde(rename = "EXPIRE_MARKET")]
149 ExpireMarket,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
154#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
155pub enum MarketUpdateStatus {
156 #[serde(rename = "MARKET_CREATED")]
158 MarketCreated,
159 #[serde(rename = "MARKET_ALREADY_EXISTS")]
161 MarketAlreadyExists,
162 #[serde(rename = "MARKET_DELETED")]
164 MarketDeleted,
165 #[serde(rename = "MARKET_EXPIRED")]
167 MarketExpired,
168 #[serde(rename = "MARKET_PENDING_SETTLEMENT")]
170 MarketPendingSettlement,
171 #[serde(rename = "MARKET_CREATION_FAILED")]
173 MarketCreationFailed,
174 #[serde(rename = "MARKET_DELETION_FAILED")]
176 MarketDeletionFailed,
177}
178
179#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
181pub enum OrderAction {
182 #[serde(rename = "CREATE_ORDER")]
183 CreateOrder,
184 #[serde(rename = "CANCEL_ORDER")]
185 CancelOrder,
186 #[serde(rename = "REPLACE_ORDER")]
187 ReplaceOrder,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
192pub enum TransactionStatus {
193 #[serde(rename = "PENDING")]
194 Pending,
195 #[serde(rename = "SUBMITTED")]
196 Submitted,
197 #[serde(rename = "CONFIRMED")]
198 Confirmed,
199 #[serde(rename = "FAILED")]
200 Failed,
201 #[serde(rename = "EXPIRED")]
202 Expired,
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
207#[serde(rename_all = "snake_case")]
208#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
209pub enum RfqStatus {
210 Created,
211 SentToQps,
212 QuotesReceived,
213 NoQuotes,
214 Expired,
215 Accepted,
216 Executed,
217 Failed,
218}
219
220impl RfqStatus {
221 pub fn is_terminal(&self) -> bool {
222 matches!(
223 self,
224 RfqStatus::NoQuotes | RfqStatus::Expired | RfqStatus::Executed | RfqStatus::Failed
225 )
226 }
227
228 pub fn as_str(&self) -> &'static str {
229 match self {
230 RfqStatus::Created => "created",
231 RfqStatus::SentToQps => "sent_to_qps",
232 RfqStatus::QuotesReceived => "quotes_received",
233 RfqStatus::NoQuotes => "no_quotes",
234 RfqStatus::Expired => "expired",
235 RfqStatus::Accepted => "accepted",
236 RfqStatus::Executed => "executed",
237 RfqStatus::Failed => "failed",
238 }
239 }
240}
241
242impl std::fmt::Display for RfqStatus {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 f.write_str(self.as_str())
245 }
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
250#[serde(rename_all = "snake_case")]
251#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
252pub enum QpTier {
253 Qp1,
254 Qp2,
255 Qp3Internal,
256}
257
258impl QpTier {
259 pub fn as_str(&self) -> &'static str {
260 match self {
261 QpTier::Qp1 => "qp1",
262 QpTier::Qp2 => "qp2",
263 QpTier::Qp3Internal => "qp3_internal",
264 }
265 }
266}
267
268impl std::fmt::Display for QpTier {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 f.write_str(self.as_str())
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
276#[serde(rename_all = "snake_case")]
277#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
278pub enum QpStatus {
279 Active,
280 Suspended,
281}
282
283#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
285#[serde(tag = "type", rename_all = "snake_case")]
286#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
287pub enum FillSource {
288 #[default]
289 Orderbook,
290 Rfq {
291 rfq_id: String,
292 quote_id: String,
293 },
294}
295
296bitflags::bitflags! {
297 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
301 pub struct TradingModes: u8 {
302 const ORDERBOOK = 0b0000_0001;
303 const RFQ = 0b0000_0010;
304 }
305}
306
307impl Default for TradingModes {
308 fn default() -> Self {
309 TradingModes::ORDERBOOK
310 }
311}
312
313impl TradingModes {
314 pub fn allows_orderbook(&self) -> bool {
315 self.contains(Self::ORDERBOOK)
316 }
317
318 pub fn allows_rfq(&self) -> bool {
319 self.contains(Self::RFQ)
320 }
321
322 pub fn as_db_str(&self) -> String {
325 let mut parts = Vec::with_capacity(2);
326 if self.contains(Self::ORDERBOOK) {
327 parts.push("orderbook");
328 }
329 if self.contains(Self::RFQ) {
330 parts.push("rfq");
331 }
332 parts.join("|")
333 }
334
335 pub fn from_db_str(s: &str) -> Self {
340 match s {
344 "" => return Self::empty(),
345 "orderbook_only" => return Self::ORDERBOOK,
346 "rfq_only" => return Self::RFQ,
347 "both" => return Self::ORDERBOOK | Self::RFQ,
348 _ => {}
349 }
350 let mut modes = Self::empty();
351 for part in s.split('|') {
352 match part.trim() {
353 "" => {}
354 "orderbook" => modes |= Self::ORDERBOOK,
355 "rfq" => modes |= Self::RFQ,
356 other => {
357 tracing::error!(
364 "TradingModes::from_db_str: unknown token '{}' in '{}', \
365 ignoring — may indicate schema drift or corruption",
366 other,
367 s
368 );
369 }
370 }
371 }
372 modes
373 }
374}
375
376impl std::fmt::Display for TradingModes {
377 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
378 f.write_str(&self.as_db_str())
379 }
380}
381
382impl Serialize for TradingModes {
383 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
384 serializer.serialize_str(&self.as_db_str())
385 }
386}
387
388impl<'de> Deserialize<'de> for TradingModes {
389 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
390 let s = String::deserialize(deserializer)?;
391 Ok(Self::from_db_str(&s))
392 }
393}