1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
8pub enum OrderSide {
9 Buy,
11 Sell,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
17#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
18pub enum OrderStatus {
19 Pending,
21 Open,
23 Filled,
25 Cancelled,
27 Expired,
29 Failed,
31 #[serde(other)]
33 Unknown,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
39pub enum StopDirection {
40 StopDirectionStopUp,
42 StopDirectionStopDown,
44}
45
46#[derive(Debug, Clone, Serialize)]
48pub struct MarketIoc {
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub quote_size: Option<String>,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub base_size: Option<String>,
55}
56
57#[derive(Debug, Clone, Serialize)]
59pub struct LimitGtc {
60 pub base_size: String,
62 pub limit_price: String,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub post_only: Option<bool>,
67}
68
69#[derive(Debug, Clone, Serialize)]
71pub struct LimitGtd {
72 pub base_size: String,
74 pub limit_price: String,
76 pub end_time: String,
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub post_only: Option<bool>,
81}
82
83#[derive(Debug, Clone, Serialize)]
85pub struct LimitFok {
86 pub base_size: String,
88 pub limit_price: String,
90}
91
92#[derive(Debug, Clone, Serialize)]
94pub struct StopLimitGtc {
95 pub base_size: String,
97 pub limit_price: String,
99 pub stop_price: String,
101 pub stop_direction: StopDirection,
103}
104
105#[derive(Debug, Clone, Serialize)]
107pub struct StopLimitGtd {
108 pub base_size: String,
110 pub limit_price: String,
112 pub stop_price: String,
114 pub end_time: String,
116 pub stop_direction: StopDirection,
118}
119
120#[derive(Debug, Clone, Serialize)]
122#[serde(untagged)]
123pub enum OrderConfiguration {
124 MarketIoc {
126 market_market_ioc: MarketIoc,
128 },
129 LimitGtc {
131 limit_limit_gtc: LimitGtc,
133 },
134 LimitGtd {
136 limit_limit_gtd: LimitGtd,
138 },
139 LimitFok {
141 limit_limit_fok: LimitFok,
143 },
144 StopLimitGtc {
146 stop_limit_stop_limit_gtc: StopLimitGtc,
148 },
149 StopLimitGtd {
151 stop_limit_stop_limit_gtd: StopLimitGtd,
153 },
154}
155
156impl OrderConfiguration {
157 pub fn market_buy_quote(quote_size: impl Into<String>) -> Self {
159 Self::MarketIoc {
160 market_market_ioc: MarketIoc {
161 quote_size: Some(quote_size.into()),
162 base_size: None,
163 },
164 }
165 }
166
167 pub fn market_buy_base(base_size: impl Into<String>) -> Self {
169 Self::MarketIoc {
170 market_market_ioc: MarketIoc {
171 quote_size: None,
172 base_size: Some(base_size.into()),
173 },
174 }
175 }
176
177 pub fn market_sell(base_size: impl Into<String>) -> Self {
179 Self::MarketIoc {
180 market_market_ioc: MarketIoc {
181 quote_size: None,
182 base_size: Some(base_size.into()),
183 },
184 }
185 }
186
187 pub fn limit_gtc(
189 base_size: impl Into<String>,
190 limit_price: impl Into<String>,
191 post_only: bool,
192 ) -> Self {
193 Self::LimitGtc {
194 limit_limit_gtc: LimitGtc {
195 base_size: base_size.into(),
196 limit_price: limit_price.into(),
197 post_only: Some(post_only),
198 },
199 }
200 }
201
202 pub fn limit_gtd(
204 base_size: impl Into<String>,
205 limit_price: impl Into<String>,
206 end_time: impl Into<String>,
207 post_only: bool,
208 ) -> Self {
209 Self::LimitGtd {
210 limit_limit_gtd: LimitGtd {
211 base_size: base_size.into(),
212 limit_price: limit_price.into(),
213 end_time: end_time.into(),
214 post_only: Some(post_only),
215 },
216 }
217 }
218
219 pub fn limit_fok(base_size: impl Into<String>, limit_price: impl Into<String>) -> Self {
221 Self::LimitFok {
222 limit_limit_fok: LimitFok {
223 base_size: base_size.into(),
224 limit_price: limit_price.into(),
225 },
226 }
227 }
228
229 pub fn stop_limit_gtc(
231 base_size: impl Into<String>,
232 limit_price: impl Into<String>,
233 stop_price: impl Into<String>,
234 stop_direction: StopDirection,
235 ) -> Self {
236 Self::StopLimitGtc {
237 stop_limit_stop_limit_gtc: StopLimitGtc {
238 base_size: base_size.into(),
239 limit_price: limit_price.into(),
240 stop_price: stop_price.into(),
241 stop_direction,
242 },
243 }
244 }
245
246 pub fn stop_limit_gtd(
248 base_size: impl Into<String>,
249 limit_price: impl Into<String>,
250 stop_price: impl Into<String>,
251 end_time: impl Into<String>,
252 stop_direction: StopDirection,
253 ) -> Self {
254 Self::StopLimitGtd {
255 stop_limit_stop_limit_gtd: StopLimitGtd {
256 base_size: base_size.into(),
257 limit_price: limit_price.into(),
258 stop_price: stop_price.into(),
259 end_time: end_time.into(),
260 stop_direction,
261 },
262 }
263 }
264}
265
266#[derive(Debug, Clone, Serialize)]
268pub struct CreateOrderRequest {
269 pub client_order_id: String,
271 pub product_id: String,
273 pub side: OrderSide,
275 pub order_configuration: OrderConfiguration,
277 #[serde(skip_serializing_if = "Option::is_none")]
279 pub self_trade_prevention_id: Option<String>,
280 #[serde(skip_serializing_if = "Option::is_none")]
282 pub leverage: Option<String>,
283 #[serde(skip_serializing_if = "Option::is_none")]
285 pub margin_type: Option<String>,
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub retail_portfolio_id: Option<String>,
289}
290
291impl CreateOrderRequest {
292 pub fn new(
294 client_order_id: impl Into<String>,
295 product_id: impl Into<String>,
296 side: OrderSide,
297 order_configuration: OrderConfiguration,
298 ) -> Self {
299 Self {
300 client_order_id: client_order_id.into(),
301 product_id: product_id.into(),
302 side,
303 order_configuration,
304 self_trade_prevention_id: None,
305 leverage: None,
306 margin_type: None,
307 retail_portfolio_id: None,
308 }
309 }
310}
311
312#[derive(Debug, Clone, Deserialize)]
314pub struct OrderSuccessResponse {
315 pub order_id: String,
317 pub product_id: Option<String>,
319 pub side: Option<String>,
321 pub client_order_id: Option<String>,
323}
324
325#[derive(Debug, Clone, Deserialize)]
327pub struct CreateOrderResponse {
328 pub success: bool,
330 pub failure_reason: Option<String>,
332 pub order_id: Option<String>,
334 pub success_response: Option<OrderSuccessResponse>,
336 pub error_response: Option<serde_json::Value>,
338}
339
340#[derive(Debug, Clone, Serialize)]
342pub struct CancelOrdersRequest {
343 pub order_ids: Vec<String>,
345}
346
347impl CancelOrdersRequest {
348 pub fn new(order_ids: Vec<String>) -> Self {
350 Self { order_ids }
351 }
352
353 pub fn single(order_id: impl Into<String>) -> Self {
355 Self {
356 order_ids: vec![order_id.into()],
357 }
358 }
359}
360
361#[derive(Debug, Clone, Deserialize)]
363pub struct CancelOrderResult {
364 pub success: bool,
366 pub failure_reason: Option<String>,
368 pub order_id: String,
370}
371
372#[derive(Debug, Clone, Deserialize)]
374pub struct CancelOrdersResponse {
375 pub results: Vec<CancelOrderResult>,
377}
378
379#[derive(Debug, Clone, Serialize)]
381pub struct EditOrderRequest {
382 pub order_id: String,
384 #[serde(skip_serializing_if = "Option::is_none")]
386 pub price: Option<String>,
387 #[serde(skip_serializing_if = "Option::is_none")]
389 pub size: Option<String>,
390}
391
392impl EditOrderRequest {
393 pub fn new(order_id: impl Into<String>) -> Self {
395 Self {
396 order_id: order_id.into(),
397 price: None,
398 size: None,
399 }
400 }
401
402 pub fn price(mut self, price: impl Into<String>) -> Self {
404 self.price = Some(price.into());
405 self
406 }
407
408 pub fn size(mut self, size: impl Into<String>) -> Self {
410 self.size = Some(size.into());
411 self
412 }
413}
414
415#[derive(Debug, Clone, Deserialize)]
417pub struct EditOrderResponse {
418 pub success: bool,
420 pub errors: Option<Vec<serde_json::Value>>,
422}
423
424#[derive(Debug, Clone, Deserialize)]
426pub struct Order {
427 pub order_id: String,
429 pub product_id: String,
431 pub user_id: Option<String>,
433 pub order_configuration: Option<serde_json::Value>,
435 pub side: String,
437 pub client_order_id: String,
439 pub status: String,
441 pub time_in_force: Option<String>,
443 pub created_time: Option<String>,
445 pub completion_percentage: Option<String>,
447 pub filled_size: Option<String>,
449 pub average_filled_price: Option<String>,
451 pub fee: Option<String>,
453 pub number_of_fills: Option<String>,
455 pub filled_value: Option<String>,
457 pub pending_cancel: Option<bool>,
459 pub size_in_quote: Option<bool>,
461 pub total_fees: Option<String>,
463 pub size_inclusive_of_fees: Option<bool>,
465 pub total_value_after_fees: Option<String>,
467 pub trigger_status: Option<String>,
469 pub order_type: Option<String>,
471 pub reject_reason: Option<String>,
473 pub settled: Option<bool>,
475 pub product_type: Option<String>,
477 pub reject_message: Option<String>,
479 pub cancel_message: Option<String>,
481 pub order_placement_source: Option<String>,
483 pub outstanding_hold_amount: Option<String>,
485}
486
487#[derive(Debug, Clone, Default, Serialize)]
489pub struct ListOrdersParams {
490 #[serde(skip_serializing_if = "Option::is_none")]
492 pub product_ids: Option<String>,
493 #[serde(skip_serializing_if = "Option::is_none")]
495 pub order_status: Option<String>,
496 #[serde(skip_serializing_if = "Option::is_none")]
498 pub limit: Option<u32>,
499 #[serde(skip_serializing_if = "Option::is_none")]
501 pub start_date: Option<String>,
502 #[serde(skip_serializing_if = "Option::is_none")]
504 pub end_date: Option<String>,
505 #[serde(skip_serializing_if = "Option::is_none")]
507 pub order_side: Option<String>,
508 #[serde(skip_serializing_if = "Option::is_none")]
510 pub cursor: Option<String>,
511 #[serde(skip_serializing_if = "Option::is_none")]
513 pub product_type: Option<String>,
514 #[serde(skip_serializing_if = "Option::is_none")]
516 pub order_type: Option<String>,
517 #[serde(skip_serializing_if = "Option::is_none")]
519 pub retail_portfolio_id: Option<String>,
520}
521
522impl ListOrdersParams {
523 pub fn new() -> Self {
525 Self::default()
526 }
527
528 pub fn product_id(mut self, product_id: impl Into<String>) -> Self {
530 self.product_ids = Some(product_id.into());
531 self
532 }
533
534 pub fn status(mut self, status: impl Into<String>) -> Self {
536 self.order_status = Some(status.into());
537 self
538 }
539
540 pub fn limit(mut self, limit: u32) -> Self {
542 self.limit = Some(limit);
543 self
544 }
545
546 pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
548 self.cursor = Some(cursor.into());
549 self
550 }
551}
552
553#[derive(Debug, Clone, Deserialize)]
555pub struct ListOrdersResponse {
556 pub orders: Vec<Order>,
558 pub sequence: Option<String>,
560 pub has_next: bool,
562 pub cursor: Option<String>,
564}
565
566#[derive(Debug, Clone, Deserialize)]
568pub struct Fill {
569 pub entry_id: String,
571 pub trade_id: String,
573 pub order_id: String,
575 pub trade_time: String,
577 pub trade_type: String,
579 pub price: String,
581 pub size: String,
583 pub commission: String,
585 pub product_id: String,
587 pub sequence_timestamp: Option<String>,
589 pub liquidity_indicator: Option<String>,
591 pub size_in_quote: Option<bool>,
593 pub user_id: Option<String>,
595 pub side: Option<String>,
597}
598
599#[derive(Debug, Clone, Default, Serialize)]
601pub struct ListFillsParams {
602 #[serde(skip_serializing_if = "Option::is_none")]
604 pub order_id: Option<String>,
605 #[serde(skip_serializing_if = "Option::is_none")]
607 pub product_id: Option<String>,
608 #[serde(skip_serializing_if = "Option::is_none")]
610 pub start_sequence_timestamp: Option<String>,
611 #[serde(skip_serializing_if = "Option::is_none")]
613 pub end_sequence_timestamp: Option<String>,
614 #[serde(skip_serializing_if = "Option::is_none")]
616 pub limit: Option<u32>,
617 #[serde(skip_serializing_if = "Option::is_none")]
619 pub cursor: Option<String>,
620}
621
622impl ListFillsParams {
623 pub fn new() -> Self {
625 Self::default()
626 }
627
628 pub fn order_id(mut self, order_id: impl Into<String>) -> Self {
630 self.order_id = Some(order_id.into());
631 self
632 }
633
634 pub fn product_id(mut self, product_id: impl Into<String>) -> Self {
636 self.product_id = Some(product_id.into());
637 self
638 }
639
640 pub fn limit(mut self, limit: u32) -> Self {
642 self.limit = Some(limit);
643 self
644 }
645
646 pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
648 self.cursor = Some(cursor.into());
649 self
650 }
651}
652
653#[derive(Debug, Clone, Deserialize)]
655pub struct ListFillsResponse {
656 pub fills: Vec<Fill>,
658 pub cursor: Option<String>,
660}
661
662#[derive(Debug, Clone, Serialize)]
664pub struct ClosePositionRequest {
665 pub client_order_id: String,
667 pub product_id: String,
669 #[serde(skip_serializing_if = "Option::is_none")]
671 pub size: Option<String>,
672}
673
674impl ClosePositionRequest {
675 pub fn new(client_order_id: impl Into<String>, product_id: impl Into<String>) -> Self {
677 Self {
678 client_order_id: client_order_id.into(),
679 product_id: product_id.into(),
680 size: None,
681 }
682 }
683
684 pub fn size(mut self, size: impl Into<String>) -> Self {
686 self.size = Some(size.into());
687 self
688 }
689}