1use serde::{Deserialize, Serialize};
17use strum::{AsRefStr, Display, EnumIter, EnumString};
18
19#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
21#[cfg_attr(
22 feature = "python",
23 pyo3::pyclass(
24 module = "nautilus_trader.core.nautilus_pyo3.coinbase",
25 eq,
26 from_py_object,
27 rename_all = "SCREAMING_SNAKE_CASE"
28 )
29)]
30#[cfg_attr(
31 feature = "python",
32 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.coinbase")
33)]
34pub enum CoinbaseEnvironment {
35 #[default]
37 Live,
38 Sandbox,
40}
41
42impl CoinbaseEnvironment {
43 #[must_use]
45 pub const fn is_sandbox(self) -> bool {
46 matches!(self, Self::Sandbox)
47 }
48}
49
50#[derive(
52 Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString, EnumIter,
53)]
54#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
55#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
56pub enum CoinbaseProductType {
57 Spot,
58 Future,
59 #[serde(rename = "UNKNOWN_PRODUCT_TYPE")]
60 #[strum(serialize = "UNKNOWN_PRODUCT_TYPE")]
61 Unknown,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
66#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
67#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
68pub enum CoinbaseOrderSide {
69 Buy,
70 Sell,
71 #[serde(rename = "UNKNOWN_ORDER_SIDE")]
72 #[strum(serialize = "UNKNOWN_ORDER_SIDE")]
73 Unknown,
74}
75
76#[derive(
78 Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString, AsRefStr,
79)]
80#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
81#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
82pub enum CoinbaseOrderType {
83 #[serde(rename = "UNKNOWN_ORDER_TYPE")]
84 #[strum(serialize = "UNKNOWN_ORDER_TYPE")]
85 Unknown,
86 #[serde(alias = "Market")]
87 Market,
88 #[serde(alias = "Limit")]
89 Limit,
90 #[serde(alias = "Stop")]
91 Stop,
92 #[serde(alias = "StopLimit", alias = "Stop Limit")]
93 StopLimit,
94 #[serde(alias = "Bracket")]
95 Bracket,
96 Twap,
97 #[serde(alias = "Roll Open")]
98 RollOpen,
99 #[serde(alias = "Roll Close")]
100 RollClose,
101 Liquidation,
102 Scaled,
103}
104
105#[derive(
107 Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString, AsRefStr,
108)]
109#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
110#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
111pub enum CoinbaseOrderStatus {
112 Pending,
113 Open,
114 Filled,
115 Cancelled,
116 Expired,
117 Failed,
118 #[serde(rename = "UNKNOWN_ORDER_STATUS")]
119 #[strum(serialize = "UNKNOWN_ORDER_STATUS")]
120 Unknown,
121 Queued,
122 CancelQueued,
123 EditQueued,
124}
125
126impl CoinbaseOrderStatus {
127 #[must_use]
130 pub const fn is_terminal(self) -> bool {
131 matches!(
132 self,
133 Self::Filled | Self::Cancelled | Self::Expired | Self::Failed
134 )
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
140#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
141#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
142pub enum CoinbaseTimeInForce {
143 #[serde(rename = "UNKNOWN_TIME_IN_FORCE")]
144 #[strum(serialize = "UNKNOWN_TIME_IN_FORCE")]
145 Unknown,
146 GoodUntilDateTime,
147 GoodUntilCancelled,
148 ImmediateOrCancel,
149 FillOrKill,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
154#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
155#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
156pub enum CoinbaseTriggerStatus {
157 #[serde(rename = "UNKNOWN_TRIGGER_STATUS")]
158 #[strum(serialize = "UNKNOWN_TRIGGER_STATUS")]
159 Unknown,
160 InvalidOrderType,
161 StopPending,
162 StopTriggered,
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
167#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
168#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
169pub enum CoinbaseOrderPlacementSource {
170 #[serde(rename = "UNKNOWN_PLACEMENT_SOURCE")]
171 #[strum(serialize = "UNKNOWN_PLACEMENT_SOURCE")]
172 Unknown,
173 RetailSimple,
174 RetailAdvanced,
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
179#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
180#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
181#[cfg_attr(
182 feature = "python",
183 pyo3::pyclass(
184 module = "nautilus_trader.core.nautilus_pyo3.coinbase",
185 eq,
186 eq_int,
187 frozen,
188 from_py_object,
189 rename_all = "SCREAMING_SNAKE_CASE"
190 )
191)]
192#[cfg_attr(
193 feature = "python",
194 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.coinbase")
195)]
196pub enum CoinbaseMarginType {
197 #[serde(alias = "Cross")]
198 Cross,
199 #[serde(alias = "Isolated")]
200 Isolated,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
205#[serde(rename_all = "snake_case")]
206#[strum(serialize_all = "snake_case")]
207pub enum CoinbaseProductStatus {
208 Online,
209 Offline,
210 Delisted,
211 #[serde(rename = "")]
213 #[strum(serialize = "")]
214 Unset,
215 Unknown,
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
221#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
222#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
223pub enum CoinbaseProductVenue {
224 Cbe,
226 Fcm,
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
232pub enum CoinbaseFcmTradingSessionState {
233 #[serde(rename = "FCM_TRADING_SESSION_STATE_UNDEFINED")]
234 #[strum(serialize = "FCM_TRADING_SESSION_STATE_UNDEFINED")]
235 Undefined,
236 #[serde(rename = "FCM_TRADING_SESSION_STATE_OPEN")]
237 #[strum(serialize = "FCM_TRADING_SESSION_STATE_OPEN")]
238 Open,
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
243pub enum CoinbaseFcmTradingSessionClosedReason {
244 #[serde(rename = "FCM_TRADING_SESSION_CLOSED_REASON_UNDEFINED")]
245 #[strum(serialize = "FCM_TRADING_SESSION_CLOSED_REASON_UNDEFINED")]
246 Undefined,
247 #[serde(rename = "FCM_TRADING_SESSION_CLOSED_REASON_EXCHANGE_MAINTENANCE")]
248 #[strum(serialize = "FCM_TRADING_SESSION_CLOSED_REASON_EXCHANGE_MAINTENANCE")]
249 ExchangeMaintenance,
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
254pub enum CoinbaseRiskManagedBy {
255 #[serde(rename = "UNKNOWN_RISK_MANAGEMENT_TYPE")]
256 #[strum(serialize = "UNKNOWN_RISK_MANAGEMENT_TYPE")]
257 Unknown,
258 #[serde(rename = "MANAGED_BY_FCM")]
259 #[strum(serialize = "MANAGED_BY_FCM")]
260 ManagedByFcm,
261 #[serde(rename = "MANAGED_BY_VENUE")]
262 #[strum(serialize = "MANAGED_BY_VENUE")]
263 ManagedByVenue,
264}
265
266#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
268#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
269#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
270pub enum CoinbaseAccountType {
271 #[serde(alias = "ACCOUNT_TYPE_CRYPTO")]
276 #[strum(to_string = "CRYPTO", serialize = "ACCOUNT_TYPE_CRYPTO")]
277 Crypto,
278 #[serde(alias = "ACCOUNT_TYPE_FIAT")]
279 #[strum(to_string = "FIAT", serialize = "ACCOUNT_TYPE_FIAT")]
280 Fiat,
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
285pub enum CoinbaseFillTradeType {
286 #[serde(rename = "FILL")]
287 #[strum(serialize = "FILL")]
288 Fill,
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
293pub enum CoinbaseFcmPositionSide {
294 #[serde(rename = "FUTURES_POSITION_SIDE_UNSPECIFIED")]
295 #[strum(serialize = "FUTURES_POSITION_SIDE_UNSPECIFIED")]
296 Unspecified,
297 #[serde(rename = "LONG")]
298 #[strum(serialize = "LONG")]
299 Long,
300 #[serde(rename = "SHORT")]
301 #[strum(serialize = "SHORT")]
302 Short,
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
307pub enum CoinbaseMarginWindowType {
308 #[serde(rename = "FCM_MARGIN_WINDOW_TYPE_INTRADAY")]
309 #[strum(serialize = "FCM_MARGIN_WINDOW_TYPE_INTRADAY")]
310 Intraday,
311 #[serde(rename = "FCM_MARGIN_WINDOW_TYPE_OVERNIGHT")]
312 #[strum(serialize = "FCM_MARGIN_WINDOW_TYPE_OVERNIGHT")]
313 Overnight,
314}
315
316#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
318pub enum CoinbaseMarginLevel {
319 #[serde(rename = "MARGIN_LEVEL_TYPE_BASE")]
320 #[strum(serialize = "MARGIN_LEVEL_TYPE_BASE")]
321 Base,
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
326#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
327#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
328pub enum CoinbaseContractExpiryType {
329 #[serde(
330 rename = "UNKNOWN_CONTRACT_EXPIRY_TYPE",
331 alias = "UNKNOWN_CONTRACT_EXPIRY"
332 )]
333 #[strum(
334 serialize = "UNKNOWN_CONTRACT_EXPIRY_TYPE",
335 serialize = "UNKNOWN_CONTRACT_EXPIRY"
336 )]
337 Unknown,
338 Expiring,
339 #[serde(rename = "PERPETUAL")]
341 #[strum(serialize = "PERPETUAL")]
342 Perpetual,
343}
344
345#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
347pub enum CoinbaseFuturesAssetType {
348 #[serde(rename = "FUTURES_ASSET_TYPE_CRYPTO")]
349 #[strum(serialize = "FUTURES_ASSET_TYPE_CRYPTO")]
350 Crypto,
351 #[serde(rename = "FUTURES_ASSET_TYPE_ENERGY")]
352 #[strum(serialize = "FUTURES_ASSET_TYPE_ENERGY")]
353 Energy,
354 #[serde(rename = "FUTURES_ASSET_TYPE_METALS")]
355 #[strum(serialize = "FUTURES_ASSET_TYPE_METALS")]
356 Metals,
357 #[serde(rename = "FUTURES_ASSET_TYPE_STOCKS")]
358 #[strum(serialize = "FUTURES_ASSET_TYPE_STOCKS")]
359 Stocks,
360}
361
362#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
364#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
365#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
366pub enum CoinbaseLiquidityIndicator {
367 Maker,
368 Taker,
369 Unknown,
370}
371
372#[derive(
374 Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString, AsRefStr,
375)]
376pub enum CoinbaseStopDirection {
377 #[serde(rename = "STOP_DIRECTION_STOP_DOWN")]
378 #[strum(serialize = "STOP_DIRECTION_STOP_DOWN")]
379 StopDown,
380 #[serde(rename = "STOP_DIRECTION_STOP_UP")]
381 #[strum(serialize = "STOP_DIRECTION_STOP_UP")]
382 StopUp,
383}
384
385#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
387#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
388#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
389pub enum CoinbaseGranularity {
390 OneMinute,
391 FiveMinute,
392 FifteenMinute,
393 ThirtyMinute,
394 OneHour,
395 TwoHour,
396 SixHour,
397 OneDay,
398}
399
400#[derive(
402 Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString, AsRefStr,
403)]
404#[serde(rename_all = "snake_case")]
405#[strum(serialize_all = "snake_case")]
406pub enum CoinbaseWsChannel {
407 Level2,
408 MarketTrades,
409 Ticker,
410 TickerBatch,
411 Candles,
412 User,
413 Heartbeats,
414 FuturesBalanceSummary,
415 Status,
416}
417
418impl CoinbaseWsChannel {
419 #[must_use]
421 pub fn requires_auth(&self) -> bool {
422 matches!(self, Self::User | Self::FuturesBalanceSummary)
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use std::str::FromStr;
429
430 use rstest::rstest;
431
432 use super::*;
433
434 #[rstest]
435 #[case(CoinbaseProductType::Spot, "SPOT")]
436 #[case(CoinbaseProductType::Future, "FUTURE")]
437 fn test_product_type_display(#[case] variant: CoinbaseProductType, #[case] expected: &str) {
438 assert_eq!(variant.to_string(), expected);
439 }
440
441 #[rstest]
442 #[case("BUY", CoinbaseOrderSide::Buy)]
443 #[case("SELL", CoinbaseOrderSide::Sell)]
444 fn test_order_side_from_str(#[case] input: &str, #[case] expected: CoinbaseOrderSide) {
445 assert_eq!(CoinbaseOrderSide::from_str(input).unwrap(), expected);
446 }
447
448 #[rstest]
449 #[case(CoinbaseOrderStatus::Filled, true)]
450 #[case(CoinbaseOrderStatus::Cancelled, true)]
451 #[case(CoinbaseOrderStatus::Expired, true)]
452 #[case(CoinbaseOrderStatus::Failed, true)]
453 #[case(CoinbaseOrderStatus::Open, false)]
454 #[case(CoinbaseOrderStatus::Pending, false)]
455 #[case(CoinbaseOrderStatus::Queued, false)]
456 #[case(CoinbaseOrderStatus::CancelQueued, false)]
457 #[case(CoinbaseOrderStatus::EditQueued, false)]
458 #[case(CoinbaseOrderStatus::Unknown, false)]
459 fn test_order_status_is_terminal(#[case] status: CoinbaseOrderStatus, #[case] expected: bool) {
460 assert_eq!(status.is_terminal(), expected);
461 }
462
463 #[rstest]
464 fn test_ws_channel_requires_auth() {
465 assert!(CoinbaseWsChannel::User.requires_auth());
466 assert!(CoinbaseWsChannel::FuturesBalanceSummary.requires_auth());
467 assert!(!CoinbaseWsChannel::Level2.requires_auth());
468 assert!(!CoinbaseWsChannel::MarketTrades.requires_auth());
469 assert!(!CoinbaseWsChannel::Ticker.requires_auth());
470 }
471
472 #[rstest]
473 fn test_order_status_serialization() {
474 let status = CoinbaseOrderStatus::Open;
475 let json = serde_json::to_string(&status).unwrap();
476 assert_eq!(json, "\"OPEN\"");
477
478 let deserialized: CoinbaseOrderStatus = serde_json::from_str("\"CANCELLED\"").unwrap();
479 assert_eq!(deserialized, CoinbaseOrderStatus::Cancelled);
480 }
481
482 #[rstest]
483 fn test_screaming_snake_case_multi_word() {
484 let json = serde_json::to_string(&CoinbaseOrderType::StopLimit).unwrap();
485 assert_eq!(json, "\"STOP_LIMIT\"");
486
487 let json = serde_json::to_string(&CoinbaseOrderStatus::CancelQueued).unwrap();
488 assert_eq!(json, "\"CANCEL_QUEUED\"");
489
490 let json = serde_json::to_string(&CoinbaseTimeInForce::GoodUntilDateTime).unwrap();
491 assert_eq!(json, "\"GOOD_UNTIL_DATE_TIME\"");
492
493 let json = serde_json::to_string(&CoinbaseGranularity::FifteenMinute).unwrap();
494 assert_eq!(json, "\"FIFTEEN_MINUTE\"");
495 }
496
497 #[rstest]
498 fn test_order_type_accepts_title_case_aliases() {
499 let order_type: CoinbaseOrderType = serde_json::from_str("\"Limit\"").unwrap();
500 assert_eq!(order_type, CoinbaseOrderType::Limit);
501
502 let order_type: CoinbaseOrderType = serde_json::from_str("\"StopLimit\"").unwrap();
503 assert_eq!(order_type, CoinbaseOrderType::StopLimit);
504
505 let order_type: CoinbaseOrderType = serde_json::from_str("\"Stop Limit\"").unwrap();
506 assert_eq!(order_type, CoinbaseOrderType::StopLimit);
507
508 let order_type = CoinbaseOrderType::from_str("STOP_LIMIT").unwrap();
509 assert_eq!(order_type, CoinbaseOrderType::StopLimit);
510
511 let order_type = CoinbaseOrderType::from_str("TWAP").unwrap();
512 assert_eq!(order_type, CoinbaseOrderType::Twap);
513
514 let order_type = CoinbaseOrderType::from_str("LIQUIDATION").unwrap();
515 assert_eq!(order_type, CoinbaseOrderType::Liquidation);
516 }
517
518 #[rstest]
519 fn test_account_type_accepts_current_wire_values() {
520 let account_type: CoinbaseAccountType = serde_json::from_str("\"FIAT\"").unwrap();
521 assert_eq!(account_type, CoinbaseAccountType::Fiat);
522
523 let account_type = CoinbaseAccountType::from_str("CRYPTO").unwrap();
524 assert_eq!(account_type, CoinbaseAccountType::Crypto);
525 }
526
527 #[rstest]
532 fn test_account_type_accepts_qualified_wire_values() {
533 let account_type: CoinbaseAccountType =
534 serde_json::from_str("\"ACCOUNT_TYPE_CRYPTO\"").unwrap();
535 assert_eq!(account_type, CoinbaseAccountType::Crypto);
536
537 let account_type: CoinbaseAccountType =
538 serde_json::from_str("\"ACCOUNT_TYPE_FIAT\"").unwrap();
539 assert_eq!(account_type, CoinbaseAccountType::Fiat);
540
541 let account_type = CoinbaseAccountType::from_str("ACCOUNT_TYPE_CRYPTO").unwrap();
542 assert_eq!(account_type, CoinbaseAccountType::Crypto);
543 }
544
545 #[rstest]
548 fn test_account_type_display_uses_short_form() {
549 assert_eq!(CoinbaseAccountType::Crypto.to_string(), "CRYPTO");
550 assert_eq!(CoinbaseAccountType::Fiat.to_string(), "FIAT");
551 assert_eq!(
552 serde_json::to_string(&CoinbaseAccountType::Crypto).unwrap(),
553 "\"CRYPTO\""
554 );
555 }
556
557 #[rstest]
558 fn test_margin_type_accepts_request_and_ws_spellings() {
559 let margin_type: CoinbaseMarginType = serde_json::from_str("\"CROSS\"").unwrap();
560 assert_eq!(margin_type, CoinbaseMarginType::Cross);
561
562 let margin_type: CoinbaseMarginType = serde_json::from_str("\"Cross\"").unwrap();
563 assert_eq!(margin_type, CoinbaseMarginType::Cross);
564 }
565
566 #[rstest]
567 fn test_contract_expiry_type_accepts_websocket_alias() {
568 let expiry_type: CoinbaseContractExpiryType =
569 serde_json::from_str("\"UNKNOWN_CONTRACT_EXPIRY\"").unwrap();
570 assert_eq!(expiry_type, CoinbaseContractExpiryType::Unknown);
571 }
572
573 #[rstest]
574 fn test_ws_channel_snake_case() {
575 let json = serde_json::to_string(&CoinbaseWsChannel::Level2).unwrap();
576 assert_eq!(json, "\"level2\"");
577
578 let json = serde_json::to_string(&CoinbaseWsChannel::MarketTrades).unwrap();
579 assert_eq!(json, "\"market_trades\"");
580
581 let json = serde_json::to_string(&CoinbaseWsChannel::FuturesBalanceSummary).unwrap();
582 assert_eq!(json, "\"futures_balance_summary\"");
583 }
584
585 #[rstest]
586 fn test_unknown_variants_have_qualified_names() {
587 let json = serde_json::to_string(&CoinbaseProductType::Unknown).unwrap();
588 assert_eq!(json, "\"UNKNOWN_PRODUCT_TYPE\"");
589
590 let json = serde_json::to_string(&CoinbaseOrderSide::Unknown).unwrap();
591 assert_eq!(json, "\"UNKNOWN_ORDER_SIDE\"");
592
593 let json = serde_json::to_string(&CoinbaseOrderType::Unknown).unwrap();
594 assert_eq!(json, "\"UNKNOWN_ORDER_TYPE\"");
595
596 let json = serde_json::to_string(&CoinbaseOrderStatus::Unknown).unwrap();
597 assert_eq!(json, "\"UNKNOWN_ORDER_STATUS\"");
598
599 let json = serde_json::to_string(&CoinbaseTimeInForce::Unknown).unwrap();
600 assert_eq!(json, "\"UNKNOWN_TIME_IN_FORCE\"");
601
602 let json = serde_json::to_string(&CoinbaseTriggerStatus::Unknown).unwrap();
603 assert_eq!(json, "\"UNKNOWN_TRIGGER_STATUS\"");
604
605 let json = serde_json::to_string(&CoinbaseOrderPlacementSource::Unknown).unwrap();
606 assert_eq!(json, "\"UNKNOWN_PLACEMENT_SOURCE\"");
607
608 let json = serde_json::to_string(&CoinbaseContractExpiryType::Unknown).unwrap();
609 assert_eq!(json, "\"UNKNOWN_CONTRACT_EXPIRY_TYPE\"");
610
611 let json = serde_json::to_string(&CoinbaseRiskManagedBy::Unknown).unwrap();
612 assert_eq!(json, "\"UNKNOWN_RISK_MANAGEMENT_TYPE\"");
613 }
614}