1use derive_builder::Builder;
42use serde::{self, Deserialize, Serialize};
43
44use crate::{
45 common::enums::{
46 OKXInstrumentType, OKXOrderStatus, OKXPositionMode, OKXPositionSide, OKXTradeMode,
47 },
48 http::error::BuildError,
49};
50
51#[allow(dead_code)] fn serialize_string_vec<S>(values: &Option<Vec<String>>, serializer: S) -> Result<S::Ok, S::Error>
53where
54 S: serde::Serializer,
55{
56 match values {
57 Some(vec) => serializer.serialize_str(&vec.join(",")),
58 None => serializer.serialize_none(),
59 }
60}
61
62#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
64#[builder(setter(into, strip_option))]
65#[serde(rename_all = "camelCase")]
66pub struct SetPositionModeParams {
67 #[serde(rename = "posMode")]
69 pub pos_mode: OKXPositionMode,
70}
71
72#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
74#[builder(default)]
75#[builder(setter(into, strip_option))]
76#[serde(rename_all = "camelCase")]
77pub struct GetPositionTiersParams {
78 pub inst_type: OKXInstrumentType,
80 pub td_mode: OKXTradeMode,
82 #[serde(skip_serializing_if = "Option::is_none")]
85 pub uly: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
89 pub inst_family: Option<String>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub inst_id: Option<String>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub ccy: Option<String>,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub tier: Option<String>,
99}
100
101#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
103#[builder(default)]
104#[builder(setter(into, strip_option))]
105#[serde(rename_all = "camelCase")]
106pub struct GetInstrumentsParams {
107 pub inst_type: OKXInstrumentType,
109 #[serde(skip_serializing_if = "Option::is_none")]
112 pub uly: Option<String>,
113 #[serde(skip_serializing_if = "Option::is_none")]
116 pub inst_family: Option<String>,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub inst_id: Option<String>,
120}
121
122#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
124#[builder(default)]
125#[builder(setter(into, strip_option))]
126#[serde(rename_all = "camelCase")]
127pub struct GetTradesParams {
128 pub inst_id: String,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub after: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub before: Option<String>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub limit: Option<u32>,
139}
140
141#[derive(Clone, Debug, Deserialize, Serialize)]
143#[serde(rename_all = "camelCase")]
144pub struct GetCandlesticksParams {
145 pub inst_id: String,
147 pub bar: String,
149 #[serde(skip_serializing_if = "Option::is_none")]
151 #[serde(rename = "after")]
152 pub after_ms: Option<i64>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 #[serde(rename = "before")]
156 pub before_ms: Option<i64>,
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub limit: Option<u32>,
160}
161
162#[derive(Debug, Default)]
164pub struct GetCandlesticksParamsBuilder {
165 inst_id: Option<String>,
166 bar: Option<String>,
167 after_ms: Option<i64>,
168 before_ms: Option<i64>,
169 limit: Option<u32>,
170}
171
172impl GetCandlesticksParamsBuilder {
173 pub fn inst_id(&mut self, inst_id: impl Into<String>) -> &mut Self {
175 self.inst_id = Some(inst_id.into());
176 self
177 }
178
179 pub fn bar(&mut self, bar: impl Into<String>) -> &mut Self {
181 self.bar = Some(bar.into());
182 self
183 }
184
185 pub fn after_ms(&mut self, after_ms: i64) -> &mut Self {
187 self.after_ms = Some(after_ms);
188 self
189 }
190
191 pub fn before_ms(&mut self, before_ms: i64) -> &mut Self {
193 self.before_ms = Some(before_ms);
194 self
195 }
196
197 pub fn limit(&mut self, limit: u32) -> &mut Self {
199 self.limit = Some(limit);
200 self
201 }
202
203 pub fn build(&mut self) -> Result<GetCandlesticksParams, BuildError> {
205 let inst_id = self.inst_id.clone().ok_or(BuildError::MissingInstId)?;
207 let bar = self.bar.clone().ok_or(BuildError::MissingBar)?;
208 let after_ms = self.after_ms;
209 let before_ms = self.before_ms;
210 let limit = self.limit;
211
212 if after_ms.is_some() && before_ms.is_some() {
215 return Err(BuildError::BothCursors);
216 }
217
218 if let (Some(after), Some(before)) = (after_ms, before_ms)
224 && after >= before
225 {
226 return Err(BuildError::InvalidTimeRange {
227 after_ms: after,
228 before_ms: before,
229 });
230 }
231
232 if let Some(nanos) = after_ms
234 && nanos.abs() > 9_999_999_999_999
235 {
236 return Err(BuildError::CursorIsNanoseconds);
237 }
238
239 if let Some(nanos) = before_ms
240 && nanos.abs() > 9_999_999_999_999
241 {
242 return Err(BuildError::CursorIsNanoseconds);
243 }
244
245 if let Some(limit) = limit
249 && limit > 300
250 {
251 return Err(BuildError::LimitTooHigh);
252 }
253
254 Ok(GetCandlesticksParams {
255 inst_id,
256 bar,
257 after_ms,
258 before_ms,
259 limit,
260 })
261 }
262}
263
264#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
266#[builder(default)]
267#[builder(setter(into, strip_option))]
268#[serde(rename_all = "camelCase")]
269pub struct GetMarkPriceParams {
270 pub inst_type: OKXInstrumentType,
272 #[serde(skip_serializing_if = "Option::is_none")]
275 pub uly: Option<String>,
276 #[serde(skip_serializing_if = "Option::is_none")]
279 pub inst_family: Option<String>,
280 #[serde(skip_serializing_if = "Option::is_none")]
282 pub inst_id: Option<String>,
283}
284
285#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
287#[builder(default)]
288#[builder(setter(into, strip_option))]
289#[serde(rename_all = "camelCase")]
290pub struct GetIndexTickerParams {
291 #[serde(skip_serializing_if = "Option::is_none")]
293 pub inst_id: Option<String>,
294 #[serde(skip_serializing_if = "Option::is_none")]
296 pub quote_ccy: Option<String>,
297}
298
299#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
301#[builder(default)]
302#[builder(setter(into, strip_option))]
303#[serde(rename_all = "camelCase")]
304pub struct GetOrderHistoryParams {
305 pub inst_type: OKXInstrumentType,
307 #[serde(skip_serializing_if = "Option::is_none")]
309 pub uly: Option<String>,
310 #[serde(skip_serializing_if = "Option::is_none")]
312 pub inst_family: Option<String>,
313 #[serde(skip_serializing_if = "Option::is_none")]
315 pub inst_id: Option<String>,
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub ord_type: Option<String>,
319 #[serde(skip_serializing_if = "Option::is_none")]
321 pub state: Option<String>,
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub after: Option<String>,
325 #[serde(skip_serializing_if = "Option::is_none")]
327 pub before: Option<String>,
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub limit: Option<u32>,
331}
332
333#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
335#[builder(default)]
336#[builder(setter(into, strip_option))]
337#[serde(rename_all = "camelCase")]
338pub struct GetOrderListParams {
339 #[serde(skip_serializing_if = "Option::is_none")]
341 pub inst_type: Option<OKXInstrumentType>,
342 #[serde(skip_serializing_if = "Option::is_none")]
344 pub inst_id: Option<String>,
345 #[serde(skip_serializing_if = "Option::is_none")]
347 pub inst_family: Option<String>,
348 #[serde(skip_serializing_if = "Option::is_none")]
350 pub state: Option<OKXOrderStatus>,
351 #[serde(skip_serializing_if = "Option::is_none")]
353 pub after: Option<String>,
354 #[serde(skip_serializing_if = "Option::is_none")]
356 pub before: Option<String>,
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub limit: Option<u32>,
360}
361
362#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
364#[builder(default)]
365#[builder(setter(into, strip_option))]
366#[serde(rename_all = "camelCase")]
367pub struct GetTransactionDetailsParams {
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub inst_type: Option<OKXInstrumentType>,
371 #[serde(skip_serializing_if = "Option::is_none")]
373 pub inst_id: Option<String>,
374 #[serde(skip_serializing_if = "Option::is_none")]
376 pub ord_id: Option<String>,
377 #[serde(skip_serializing_if = "Option::is_none")]
379 pub after: Option<String>,
380 #[serde(skip_serializing_if = "Option::is_none")]
382 pub before: Option<String>,
383 #[serde(skip_serializing_if = "Option::is_none")]
385 pub limit: Option<u32>,
386}
387
388#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
390#[builder(default)]
391#[builder(setter(into, strip_option))]
392#[serde(rename_all = "camelCase")]
393pub struct GetPositionsParams {
394 #[serde(skip_serializing_if = "Option::is_none")]
396 pub inst_type: Option<OKXInstrumentType>,
397 #[serde(skip_serializing_if = "Option::is_none")]
399 pub inst_id: Option<String>,
400 #[serde(skip_serializing_if = "Option::is_none")]
402 pub pos_id: Option<String>,
403}
404
405#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
407#[builder(default)]
408#[builder(setter(into, strip_option))]
409#[serde(rename_all = "camelCase")]
410pub struct GetPositionsHistoryParams {
411 pub inst_type: OKXInstrumentType,
413 #[serde(skip_serializing_if = "Option::is_none")]
415 pub inst_id: Option<String>,
416 #[serde(skip_serializing_if = "Option::is_none")]
418 pub pos_id: Option<String>,
419 #[serde(skip_serializing_if = "Option::is_none")]
421 pub after: Option<String>,
422 #[serde(skip_serializing_if = "Option::is_none")]
424 pub before: Option<String>,
425 #[serde(skip_serializing_if = "Option::is_none")]
427 pub limit: Option<u32>,
428}
429
430#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
432#[builder(default)]
433#[builder(setter(into, strip_option))]
434#[serde(rename_all = "camelCase")]
435pub struct GetPendingOrdersParams {
436 pub inst_type: OKXInstrumentType,
438 pub inst_id: String,
440 #[serde(skip_serializing_if = "Option::is_none")]
442 pub pos_side: Option<OKXPositionSide>,
443}
444
445#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
447#[builder(default)]
448#[builder(setter(into, strip_option))]
449#[serde(rename_all = "camelCase")]
450pub struct GetOrderParams {
451 pub inst_type: OKXInstrumentType,
453 pub inst_id: String,
455 #[serde(skip_serializing_if = "Option::is_none")]
457 pub ord_id: Option<String>,
458 #[serde(skip_serializing_if = "Option::is_none")]
460 pub cl_ord_id: Option<String>,
461 #[serde(skip_serializing_if = "Option::is_none")]
463 pub pos_side: Option<OKXPositionSide>,
464}