Skip to main content

rust_okx/api/trade/
requests.rs

1use serde::Serialize;
2
3use crate::model::{OrderSide, OrderState, OrderType, PositionSide, TradeMode};
4
5mod advanced;
6mod algo;
7
8pub use advanced::*;
9pub use algo::*;
10
11/// A request to place an order.
12///
13/// Construct with [`PlaceOrderRequest::new`] (required fields) and chain setters
14/// for optional fields. Optional fields are omitted from the request body when
15/// unset.
16#[derive(Debug, Clone, Serialize)]
17pub struct PlaceOrderRequest {
18    #[serde(rename = "instId")]
19    inst_id: String,
20    #[serde(rename = "tdMode")]
21    td_mode: TradeMode,
22    side: OrderSide,
23    #[serde(rename = "ordType")]
24    ord_type: OrderType,
25    sz: String,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    ccy: Option<String>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    tag: Option<String>,
30    #[serde(rename = "px", skip_serializing_if = "Option::is_none")]
31    px: Option<String>,
32    #[serde(rename = "posSide", skip_serializing_if = "Option::is_none")]
33    pos_side: Option<PositionSide>,
34    #[serde(rename = "clOrdId", skip_serializing_if = "Option::is_none")]
35    cl_ord_id: Option<String>,
36    #[serde(rename = "reduceOnly", skip_serializing_if = "Option::is_none")]
37    reduce_only: Option<bool>,
38    #[serde(rename = "tgtCcy", skip_serializing_if = "Option::is_none")]
39    tgt_ccy: Option<String>,
40}
41
42impl PlaceOrderRequest {
43    /// Create a new order request with the required fields.
44    pub fn new(
45        inst_id: impl Into<String>,
46        td_mode: TradeMode,
47        side: OrderSide,
48        ord_type: OrderType,
49        sz: impl Into<String>,
50    ) -> Self {
51        Self {
52            inst_id: inst_id.into(),
53            td_mode,
54            side,
55            ord_type,
56            sz: sz.into(),
57            ccy: None,
58            tag: None,
59            px: None,
60            pos_side: None,
61            cl_ord_id: None,
62            reduce_only: None,
63            tgt_ccy: None,
64        }
65    }
66
67    /// Set the order price (required for `limit`-style orders).
68    pub fn price(mut self, px: impl Into<String>) -> Self {
69        self.px = Some(px.into());
70        self
71    }
72
73    /// Set the position side (`long`/`short`/`net`).
74    pub fn position_side(mut self, pos_side: PositionSide) -> Self {
75        self.pos_side = Some(pos_side);
76        self
77    }
78
79    /// Set a client-supplied order ID.
80    pub fn client_order_id(mut self, cl_ord_id: impl Into<String>) -> Self {
81        self.cl_ord_id = Some(cl_ord_id.into());
82        self
83    }
84
85    /// Mark the order as reduce-only.
86    pub fn reduce_only(mut self, reduce_only: bool) -> Self {
87        self.reduce_only = Some(reduce_only);
88        self
89    }
90
91    /// Set the quantity unit for spot market orders (`base_ccy`/`quote_ccy`).
92    pub fn target_ccy(mut self, tgt_ccy: impl Into<String>) -> Self {
93        self.tgt_ccy = Some(tgt_ccy.into());
94        self
95    }
96
97    /// Set the margin currency.
98    pub fn currency(mut self, ccy: impl Into<String>) -> Self {
99        self.ccy = Some(ccy.into());
100        self
101    }
102
103    /// Set an order tag.
104    pub fn tag(mut self, tag: impl Into<String>) -> Self {
105        self.tag = Some(tag.into());
106        self
107    }
108}
109
110/// A request to cancel an order.
111#[derive(Debug, Clone, Serialize)]
112pub struct CancelOrderRequest {
113    #[serde(rename = "instId")]
114    inst_id: String,
115    #[serde(rename = "ordId", skip_serializing_if = "Option::is_none")]
116    ord_id: Option<String>,
117    #[serde(rename = "clOrdId", skip_serializing_if = "Option::is_none")]
118    cl_ord_id: Option<String>,
119}
120
121impl CancelOrderRequest {
122    /// Cancel by OKX order ID.
123    pub fn by_order_id(inst_id: impl Into<String>, ord_id: impl Into<String>) -> Self {
124        Self {
125            inst_id: inst_id.into(),
126            ord_id: Some(ord_id.into()),
127            cl_ord_id: None,
128        }
129    }
130
131    /// Cancel by client order ID.
132    pub fn by_client_order_id(inst_id: impl Into<String>, cl_ord_id: impl Into<String>) -> Self {
133        Self {
134            inst_id: inst_id.into(),
135            ord_id: None,
136            cl_ord_id: Some(cl_ord_id.into()),
137        }
138    }
139}
140
141/// A request to amend an order.
142#[derive(Debug, Clone, Serialize)]
143pub struct AmendOrderRequest {
144    #[serde(rename = "instId")]
145    inst_id: String,
146    #[serde(rename = "ordId", skip_serializing_if = "Option::is_none")]
147    ord_id: Option<String>,
148    #[serde(rename = "clOrdId", skip_serializing_if = "Option::is_none")]
149    cl_ord_id: Option<String>,
150    #[serde(rename = "reqId", skip_serializing_if = "Option::is_none")]
151    req_id: Option<String>,
152    #[serde(rename = "cxlOnFail", skip_serializing_if = "Option::is_none")]
153    cxl_on_fail: Option<bool>,
154    #[serde(rename = "newSz", skip_serializing_if = "Option::is_none")]
155    new_sz: Option<String>,
156    #[serde(rename = "newPx", skip_serializing_if = "Option::is_none")]
157    new_px: Option<String>,
158}
159
160impl AmendOrderRequest {
161    /// Create an amend-order request for an instrument.
162    pub fn new(inst_id: impl Into<String>) -> Self {
163        Self {
164            inst_id: inst_id.into(),
165            ord_id: None,
166            cl_ord_id: None,
167            req_id: None,
168            cxl_on_fail: None,
169            new_sz: None,
170            new_px: None,
171        }
172    }
173
174    /// Set the OKX order ID.
175    pub fn order_id(mut self, ord_id: impl Into<String>) -> Self {
176        self.ord_id = Some(ord_id.into());
177        self
178    }
179
180    /// Set the client order ID.
181    pub fn client_order_id(mut self, cl_ord_id: impl Into<String>) -> Self {
182        self.cl_ord_id = Some(cl_ord_id.into());
183        self
184    }
185
186    /// Set a request ID.
187    pub fn request_id(mut self, req_id: impl Into<String>) -> Self {
188        self.req_id = Some(req_id.into());
189        self
190    }
191
192    /// Set whether OKX should cancel the order if amendment fails.
193    pub fn cancel_on_fail(mut self, cxl_on_fail: bool) -> Self {
194        self.cxl_on_fail = Some(cxl_on_fail);
195        self
196    }
197
198    /// Set the new order size.
199    pub fn new_size(mut self, new_sz: impl Into<String>) -> Self {
200        self.new_sz = Some(new_sz.into());
201        self
202    }
203
204    /// Set the new order price.
205    pub fn new_price(mut self, new_px: impl Into<String>) -> Self {
206        self.new_px = Some(new_px.into());
207        self
208    }
209}
210
211/// A request to close positions.
212#[derive(Debug, Clone, Serialize)]
213pub struct ClosePositionRequest {
214    #[serde(rename = "instId")]
215    inst_id: String,
216    #[serde(rename = "mgnMode")]
217    mgn_mode: TradeMode,
218    #[serde(rename = "posSide", skip_serializing_if = "Option::is_none")]
219    pos_side: Option<PositionSide>,
220    #[serde(skip_serializing_if = "Option::is_none")]
221    ccy: Option<String>,
222    #[serde(rename = "autoCxl", skip_serializing_if = "Option::is_none")]
223    auto_cancel: Option<bool>,
224    #[serde(rename = "clOrdId", skip_serializing_if = "Option::is_none")]
225    cl_ord_id: Option<String>,
226    #[serde(skip_serializing_if = "Option::is_none")]
227    tag: Option<String>,
228}
229
230impl ClosePositionRequest {
231    /// Create a close-position request.
232    pub fn new(inst_id: impl Into<String>, mgn_mode: TradeMode) -> Self {
233        Self {
234            inst_id: inst_id.into(),
235            mgn_mode,
236            pos_side: None,
237            ccy: None,
238            auto_cancel: None,
239            cl_ord_id: None,
240            tag: None,
241        }
242    }
243
244    /// Set the position side.
245    pub fn position_side(mut self, pos_side: PositionSide) -> Self {
246        self.pos_side = Some(pos_side);
247        self
248    }
249
250    /// Set the margin currency.
251    pub fn currency(mut self, ccy: impl Into<String>) -> Self {
252        self.ccy = Some(ccy.into());
253        self
254    }
255
256    /// Set whether pending orders should be canceled automatically.
257    pub fn auto_cancel(mut self, auto_cancel: bool) -> Self {
258        self.auto_cancel = Some(auto_cancel);
259        self
260    }
261
262    /// Set the client order ID.
263    pub fn client_order_id(mut self, cl_ord_id: impl Into<String>) -> Self {
264        self.cl_ord_id = Some(cl_ord_id.into());
265        self
266    }
267
268    /// Set an order tag.
269    pub fn tag(mut self, tag: impl Into<String>) -> Self {
270        self.tag = Some(tag.into());
271        self
272    }
273}
274
275/// Query parameters for pending order lists.
276#[derive(Debug, Clone, Default, Serialize)]
277pub struct OrderListRequest {
278    #[serde(rename = "instType", skip_serializing_if = "Option::is_none")]
279    inst_type: Option<crate::model::InstType>,
280    #[serde(rename = "uly", skip_serializing_if = "Option::is_none")]
281    underlying: Option<String>,
282    #[serde(rename = "instId", skip_serializing_if = "Option::is_none")]
283    inst_id: Option<String>,
284    #[serde(rename = "ordType", skip_serializing_if = "Option::is_none")]
285    ord_type: Option<OrderType>,
286    #[serde(skip_serializing_if = "Option::is_none")]
287    state: Option<OrderState>,
288    #[serde(skip_serializing_if = "Option::is_none")]
289    after: Option<String>,
290    #[serde(skip_serializing_if = "Option::is_none")]
291    before: Option<String>,
292    #[serde(skip_serializing_if = "Option::is_none")]
293    limit: Option<u32>,
294    #[serde(rename = "instFamily", skip_serializing_if = "Option::is_none")]
295    inst_family: Option<String>,
296}
297
298impl OrderListRequest {
299    /// Create an empty order-list query.
300    pub fn new() -> Self {
301        Self::default()
302    }
303
304    /// Set the instrument type filter.
305    pub fn inst_type(mut self, inst_type: crate::model::InstType) -> Self {
306        self.inst_type = Some(inst_type);
307        self
308    }
309
310    /// Set the underlying filter.
311    pub fn underlying(mut self, underlying: impl Into<String>) -> Self {
312        self.underlying = Some(underlying.into());
313        self
314    }
315
316    /// Set the instrument ID filter.
317    pub fn inst_id(mut self, inst_id: impl Into<String>) -> Self {
318        self.inst_id = Some(inst_id.into());
319        self
320    }
321
322    /// Set the order type filter.
323    pub fn order_type(mut self, ord_type: OrderType) -> Self {
324        self.ord_type = Some(ord_type);
325        self
326    }
327
328    /// Set the order state filter.
329    pub fn state(mut self, state: OrderState) -> Self {
330        self.state = Some(state);
331        self
332    }
333
334    /// Return records after this pagination cursor.
335    pub fn after(mut self, after: impl Into<String>) -> Self {
336        self.after = Some(after.into());
337        self
338    }
339
340    /// Return records before this pagination cursor.
341    pub fn before(mut self, before: impl Into<String>) -> Self {
342        self.before = Some(before.into());
343        self
344    }
345
346    /// Set the maximum number of rows to return.
347    pub fn limit(mut self, limit: u32) -> Self {
348        self.limit = Some(limit);
349        self
350    }
351
352    /// Set the instrument family filter.
353    pub fn inst_family(mut self, inst_family: impl Into<String>) -> Self {
354        self.inst_family = Some(inst_family.into());
355        self
356    }
357}
358
359/// Query parameters for order history.
360#[derive(Debug, Clone, Serialize)]
361pub struct OrderHistoryRequest {
362    #[serde(flatten)]
363    base: OrderListRequest,
364    #[serde(skip_serializing_if = "Option::is_none")]
365    begin: Option<String>,
366    #[serde(skip_serializing_if = "Option::is_none")]
367    end: Option<String>,
368}
369
370impl OrderHistoryRequest {
371    /// Create an order-history query with the required instrument type.
372    pub fn new(inst_type: crate::model::InstType) -> Self {
373        Self {
374            base: OrderListRequest::new().inst_type(inst_type),
375            begin: None,
376            end: None,
377        }
378    }
379
380    /// Set the common order-list filters.
381    pub fn filters(mut self, base: OrderListRequest) -> Self {
382        self.base = base;
383        self
384    }
385
386    /// Set the begin timestamp.
387    pub fn begin(mut self, begin: impl Into<String>) -> Self {
388        self.begin = Some(begin.into());
389        self
390    }
391
392    /// Set the end timestamp.
393    pub fn end(mut self, end: impl Into<String>) -> Self {
394        self.end = Some(end.into());
395        self
396    }
397}
398
399/// Query parameters for fills.
400#[derive(Debug, Clone, Default, Serialize)]
401pub struct FillsRequest {
402    #[serde(rename = "instType", skip_serializing_if = "Option::is_none")]
403    inst_type: Option<crate::model::InstType>,
404    #[serde(rename = "uly", skip_serializing_if = "Option::is_none")]
405    underlying: Option<String>,
406    #[serde(rename = "instId", skip_serializing_if = "Option::is_none")]
407    inst_id: Option<String>,
408    #[serde(rename = "ordId", skip_serializing_if = "Option::is_none")]
409    ord_id: Option<String>,
410    #[serde(skip_serializing_if = "Option::is_none")]
411    after: Option<String>,
412    #[serde(skip_serializing_if = "Option::is_none")]
413    before: Option<String>,
414    #[serde(skip_serializing_if = "Option::is_none")]
415    begin: Option<String>,
416    #[serde(skip_serializing_if = "Option::is_none")]
417    end: Option<String>,
418    #[serde(skip_serializing_if = "Option::is_none")]
419    limit: Option<u32>,
420    #[serde(rename = "instFamily", skip_serializing_if = "Option::is_none")]
421    inst_family: Option<String>,
422}
423
424impl FillsRequest {
425    /// Create an empty fills query.
426    pub fn new() -> Self {
427        Self::default()
428    }
429
430    /// Set the instrument type filter.
431    pub fn inst_type(mut self, inst_type: crate::model::InstType) -> Self {
432        self.inst_type = Some(inst_type);
433        self
434    }
435
436    /// Set the underlying filter.
437    pub fn underlying(mut self, underlying: impl Into<String>) -> Self {
438        self.underlying = Some(underlying.into());
439        self
440    }
441
442    /// Set the instrument ID filter.
443    pub fn inst_id(mut self, inst_id: impl Into<String>) -> Self {
444        self.inst_id = Some(inst_id.into());
445        self
446    }
447
448    /// Set the order ID filter.
449    pub fn order_id(mut self, ord_id: impl Into<String>) -> Self {
450        self.ord_id = Some(ord_id.into());
451        self
452    }
453
454    /// Return records after this pagination cursor.
455    pub fn after(mut self, after: impl Into<String>) -> Self {
456        self.after = Some(after.into());
457        self
458    }
459
460    /// Return records before this pagination cursor.
461    pub fn before(mut self, before: impl Into<String>) -> Self {
462        self.before = Some(before.into());
463        self
464    }
465
466    /// Set the begin timestamp.
467    pub fn begin(mut self, begin: impl Into<String>) -> Self {
468        self.begin = Some(begin.into());
469        self
470    }
471
472    /// Set the end timestamp.
473    pub fn end(mut self, end: impl Into<String>) -> Self {
474        self.end = Some(end.into());
475        self
476    }
477
478    /// Set the maximum number of rows to return.
479    pub fn limit(mut self, limit: u32) -> Self {
480        self.limit = Some(limit);
481        self
482    }
483
484    /// Set the instrument family filter.
485    pub fn inst_family(mut self, inst_family: impl Into<String>) -> Self {
486        self.inst_family = Some(inst_family.into());
487        self
488    }
489}
490
491/// Query parameters for historical fills.
492///
493/// This is intentionally separate from [`FillsRequest`] because OKX documents
494/// `instType` as required for `GET /api/v5/trade/fills-history`, while it is
495/// optional for `GET /api/v5/trade/fills`.
496#[derive(Debug, Clone, Serialize)]
497pub struct FillHistoryRequest {
498    #[serde(rename = "instType")]
499    inst_type: crate::model::InstType,
500    #[serde(rename = "instId", skip_serializing_if = "Option::is_none")]
501    inst_id: Option<String>,
502    #[serde(rename = "ordId", skip_serializing_if = "Option::is_none")]
503    ord_id: Option<String>,
504    #[serde(skip_serializing_if = "Option::is_none")]
505    after: Option<String>,
506    #[serde(skip_serializing_if = "Option::is_none")]
507    before: Option<String>,
508    #[serde(skip_serializing_if = "Option::is_none")]
509    begin: Option<String>,
510    #[serde(skip_serializing_if = "Option::is_none")]
511    end: Option<String>,
512    #[serde(skip_serializing_if = "Option::is_none")]
513    limit: Option<u32>,
514}
515
516impl FillHistoryRequest {
517    /// Create a historical fills query with the required instrument type.
518    pub fn new(inst_type: crate::model::InstType) -> Self {
519        Self {
520            inst_type,
521            inst_id: None,
522            ord_id: None,
523            after: None,
524            before: None,
525            begin: None,
526            end: None,
527            limit: None,
528        }
529    }
530
531    /// Set the instrument ID filter.
532    pub fn inst_id(mut self, inst_id: impl Into<String>) -> Self {
533        self.inst_id = Some(inst_id.into());
534        self
535    }
536
537    /// Set the order ID filter.
538    pub fn order_id(mut self, ord_id: impl Into<String>) -> Self {
539        self.ord_id = Some(ord_id.into());
540        self
541    }
542
543    /// Return records after this pagination cursor.
544    pub fn after(mut self, after: impl Into<String>) -> Self {
545        self.after = Some(after.into());
546        self
547    }
548
549    /// Return records before this pagination cursor.
550    pub fn before(mut self, before: impl Into<String>) -> Self {
551        self.before = Some(before.into());
552        self
553    }
554
555    /// Set the begin timestamp.
556    pub fn begin(mut self, begin: impl Into<String>) -> Self {
557        self.begin = Some(begin.into());
558        self
559    }
560
561    /// Set the end timestamp.
562    pub fn end(mut self, end: impl Into<String>) -> Self {
563        self.end = Some(end.into());
564        self
565    }
566
567    /// Set the maximum number of rows to return.
568    pub fn limit(mut self, limit: u32) -> Self {
569        self.limit = Some(limit);
570        self
571    }
572}