Skip to main content

gateio_rs/api/spot/
create_order.rs

1use crate::http::{Credentials, Method, request::Request};
2use serde_json::{Map, Value, json};
3
4/// Request builder for creating trading orders.
5///
6/// Creates a new buy or sell order on Gate.io spot markets. Supports various order types
7/// including limit, market, immediate-or-cancel (IOC), and fill-or-kill (FOK) orders.
8///
9/// # API Endpoint
10/// `POST /api/v4/spot/orders`
11///
12/// # Authentication
13/// This endpoint requires API key authentication with signing.
14///
15/// # Examples
16///
17/// ```rust,no_run
18/// use gateio_rs::{
19///     api::spot::create_order,
20///     http::Credentials,
21///     ureq::GateHttpClient,
22/// };
23///
24/// let credentials = Credentials::new("api_key", "api_secret");
25/// let client = GateHttpClient::default().credentials(credentials);
26///
27/// // Limit buy order
28/// let request = create_order("BTC_USDT", "buy", "0.001")
29///     .price("50000")
30///     .order_type("limit")
31///     .time_in_force("gtc")
32///     .text("t-my-order-123");
33/// let response = client.send(request)?;
34///
35/// // Market sell order
36/// let request = create_order("BTC_USDT", "sell", "0.001")
37///     .order_type("market");
38/// let response = client.send(request)?;
39/// # Ok::<(), Box<dyn std::error::Error>>(()).expect("");
40/// ```
41///
42/// # Parameter Details
43///
44/// ## Order Types (`order_type`)
45/// - `"limit"`: Limit order (default) - requires price
46/// - `"market"`: Market order - executes immediately at market price
47/// - `"ioc"`: Immediate-or-cancel - taker only
48/// - `"poc"`: Post-only - maker only (enjoys maker fee)
49/// - `"fok"`: Fill-or-kill - complete fill or cancel
50///
51/// ## Time in Force (`time_in_force`)
52/// - `"gtc"`: Good-till-cancelled (default)
53/// - `"ioc"`: Immediate-or-cancel
54/// - `"poc"`: Post-only
55/// - `"fok"`: Fill-or-kill
56///
57/// ## Amount Rules
58/// - **Limit orders**: Amount refers to base currency (e.g., BTC in BTC_USDT)
59/// - **Market buy**: Amount refers to quote currency (e.g., USDT in BTC_USDT)
60/// - **Market sell**: Amount refers to base currency (e.g., BTC in BTC_USDT)
61///
62/// ## Account Types (`account`)
63/// - `"spot"`: Spot trading account
64/// - `"margin"`: Margin trading account
65/// - `"cross_margin"`: Cross margin account
66/// - `"unified"`: Unified account
67///
68/// ## Self-Trading Prevention (`stp_act`)
69/// - `"cn"`: Cancel newest orders
70/// - `"co"`: Cancel oldest orders
71/// - `"cb"`: Cancel both old and new orders
72///
73/// ## Text Field Rules
74/// Custom order ID must:
75/// - Be prefixed with `"t-"`
76/// - Be no longer than 28 bytes (excluding prefix)
77/// - Contain only: 0-9, A-Z, a-z, underscore, hyphen, or dot
78pub struct CreateOrder {
79    /// Custom order ID
80    pub text: Option<String>,
81    /// Trading pair
82    pub currency_pair: String,
83    /// Order type
84    pub order_type: Option<String>,
85    /// Account type
86    pub account: Option<String>,
87    /// Order side
88    pub side: String,
89    /// Order amount
90    pub amount: String,
91    /// Order price
92    pub price: Option<String>,
93    /// Time in force
94    pub time_in_force: Option<String>,
95    /// Iceberg amount
96    pub iceberg: Option<String>,
97    /// Auto borrow funds
98    pub auto_borrow: Option<bool>,
99    /// Auto repay borrowed
100    pub auto_repay: Option<bool>,
101    /// Self-trade prevention
102    pub stp_act: Option<String>,
103    /// Processing mode
104    pub action_mode: Option<String>,
105    /// Request expiration time
106    pub x_gate_exp_time: Option<u128>,
107    /// API credentials
108    pub credentials: Option<Credentials>,
109}
110
111impl CreateOrder {
112    /// Create new order request
113    pub fn new(currency_pair: &str, side: &str, amount: &str) -> Self {
114        Self {
115            text: None,
116            currency_pair: currency_pair.to_owned(),
117            order_type: None,
118            account: None,
119            side: side.to_owned(),
120            amount: amount.to_owned(),
121            price: None,
122            time_in_force: None,
123            iceberg: None,
124            auto_borrow: None,
125            auto_repay: None,
126            stp_act: None,
127            action_mode: None,
128            x_gate_exp_time: None,
129            credentials: None,
130        }
131    }
132
133    /// Set custom order ID
134    pub fn text(mut self, text: &str) -> Self {
135        self.text = Some(text.into());
136        self
137    }
138
139    /// Set order type
140    pub fn order_type(mut self, order_type: &str) -> Self {
141        self.order_type = Some(order_type.into());
142        self
143    }
144
145    /// Set account type
146    pub fn account(mut self, account: &str) -> Self {
147        self.account = Some(account.into());
148        self
149    }
150
151    /// Set order price
152    pub fn price(mut self, price: &str) -> Self {
153        self.price = Some(price.into());
154        self
155    }
156
157    /// Set time in force
158    pub fn time_in_force(mut self, time_in_force: &str) -> Self {
159        self.time_in_force = Some(time_in_force.into());
160        self
161    }
162
163    /// Set iceberg amount
164    pub fn iceberg(mut self, iceberg: &str) -> Self {
165        self.iceberg = Some(iceberg.into());
166        self
167    }
168
169    /// Enable auto borrow
170    pub fn auto_borrow(mut self, auto_borrow: bool) -> Self {
171        self.auto_borrow = Some(auto_borrow.into());
172        self
173    }
174
175    /// Enable auto repay
176    pub fn auto_repay(mut self, auto_repay: bool) -> Self {
177        self.auto_repay = Some(auto_repay.into());
178        self
179    }
180
181    /// Set self-trade prevention
182    pub fn stp_act(mut self, stp_act: &str) -> Self {
183        self.stp_act = Some(stp_act.into());
184        self
185    }
186
187    /// Set processing mode
188    pub fn action_mode(mut self, action_mode: &str) -> Self {
189        self.action_mode = Some(action_mode.into());
190        self
191    }
192
193    /// Set expiration time
194    pub fn x_gate_exp_time(mut self, x_gate_exp_time: u128) -> Self {
195        self.x_gate_exp_time = Some(x_gate_exp_time.into());
196        self
197    }
198
199    /// Set API credentials
200    pub fn credentials(mut self, creds: Credentials) -> Self {
201        self.credentials = Some(creds);
202        self
203    }
204}
205
206impl From<CreateOrder> for Request {
207    fn from(request: CreateOrder) -> Request {
208        let params = Vec::new();
209        let mut payload = Map::new();
210
211        payload.insert("currency_pair".to_string(), json!(request.currency_pair));
212        payload.insert("side".to_string(), json!(request.side));
213        payload.insert("amount".to_string(), json!(request.amount));
214
215        if let Some(text) = request.text {
216            payload.insert("text".to_string(), json!(text));
217        }
218
219        if let Some(order_type) = request.order_type {
220            payload.insert("type".to_string(), json!(order_type));
221        }
222
223        if let Some(account) = request.account {
224            payload.insert("account".to_string(), json!(account));
225        }
226
227        if let Some(price) = request.price {
228            payload.insert("price".to_string(), json!(price));
229        }
230
231        if let Some(time_in_force) = request.time_in_force {
232            payload.insert("time_in_force".to_string(), json!(time_in_force));
233        }
234
235        if let Some(iceberg) = request.iceberg {
236            payload.insert("iceberg".to_string(), json!(iceberg));
237        }
238
239        if let Some(auto_borrow) = request.auto_borrow {
240            payload.insert("auto_borrow".to_string(), json!(auto_borrow));
241        }
242
243        if let Some(auto_repay) = request.auto_repay {
244            payload.insert("auto_repay".to_string(), json!(auto_repay));
245        }
246
247        if let Some(stp_act) = request.stp_act {
248            payload.insert("stp_act".to_string(), json!(stp_act));
249        }
250
251        if let Some(action_mode) = request.action_mode {
252            payload.insert("action_mode".to_string(), json!(action_mode));
253        }
254
255        let payload_json = Value::Object(payload);
256
257        Request {
258            method: Method::Post,
259            path: "/api/v4/spot/orders".into(),
260            params,
261            payload: payload_json.to_string(),
262            x_gate_exp_time: request.x_gate_exp_time,
263            credentials: request.credentials,
264            sign: true,
265        }
266    }
267}