1use chrono::Utc;
2use hmac::{Hmac, Mac, NewMac};
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use sha2::Sha256;
6
7type HmacSha256 = Hmac<Sha256>;
8
9#[derive(Copy, Clone, Debug)]
10pub enum ID<'a> {
11 OrderId(i64),
12 ClientOId(&'a str),
13}
14
15#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
16#[serde(rename_all = "UPPERCASE")]
17pub enum Side {
18 Buy,
19 Sell,
20}
21
22#[derive(Copy, Clone, Serialize)]
23#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
24pub(super) enum OrderType {
25 Limit,
26 Market,
27 StopLoss,
28 StopLossLimit,
29 TakeProfit,
30 TakeProfitLimit,
31 LimitMaker,
32}
33
34#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
35#[serde(rename_all = "UPPERCASE")]
36pub enum TimeInForce {
37 Gtc,
38 Ioc,
39 Fok,
40}
41
42#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
43#[serde(rename_all = "UPPERCASE")]
44pub enum OrderRespType {
45 Ack,
46 Result,
47 Full,
48}
49
50#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
51pub enum Interval {
52 #[serde(rename = "1m")]
53 OneMinute,
54 #[serde(rename = "3m")]
55 ThreeMinutes,
56 #[serde(rename = "5m")]
57 FiveMinutes,
58 #[serde(rename = "15m")]
59 FifTeenMinutes,
60 #[serde(rename = "30m")]
61 ThirtyMinutes,
62 #[serde(rename = "1h")]
63 OneHour,
64 #[serde(rename = "2h")]
65 TwoHours,
66 #[serde(rename = "4h")]
67 FourHours,
68 #[serde(rename = "6h")]
69 SixHours,
70 #[serde(rename = "8h")]
71 EightHours,
72 #[serde(rename = "12h")]
73 TwelveHours,
74 #[serde(rename = "1d")]
75 OneDay,
76 #[serde(rename = "3d")]
77 ThreeDays,
78 #[serde(rename = "1w")]
79 OneWeek,
80 #[serde(rename = "1M")]
81 OneMonth,
82}
83
84#[derive(Default, Serialize)]
85#[serde(rename_all = "camelCase")]
86pub(super) struct Parameters<'a> {
87 pub symbol: Option<&'a str>,
88 pub limit: Option<usize>,
89 pub from_id: Option<i64>,
90 pub start_time: Option<i64>,
91 pub end_time: Option<i64>,
92 pub interval: Option<Interval>,
93 pub side: Option<Side>,
94 #[serde(rename = "type")]
95 pub order_type: Option<OrderType>,
96 pub time_in_force: Option<TimeInForce>,
97 pub quantity: Option<f64>,
98 pub price: Option<f64>,
99 pub new_client_order_id: Option<&'a str>,
100 pub stop_price: Option<f64>,
101 pub iceberg_qty: Option<f64>,
102 pub new_order_resp_type: Option<OrderRespType>,
103 pub order_id: Option<i64>,
104 pub orig_client_order_id: Option<&'a str>,
105 pub list_client_order_id: Option<&'a str>,
106 pub limit_client_order_id: Option<&'a str>,
107 pub stop_client_order_id: Option<&'a str>,
108 pub limit_iceberg_qty: Option<f64>,
109 pub stop_iceberg_qty: Option<f64>,
110 pub stop_limit_price: Option<f64>,
111 pub stop_limit_time_in_force: Option<TimeInForce>,
112 pub order_list_id: Option<i64>,
113 pub listen_key: Option<&'a str>,
114 pub address: Option<&'a str>,
115 pub address_tag: Option<&'a str>,
116 pub name: Option<&'a str>,
117 pub asset: Option<&'a str>,
118 pub status: Option<Value>,
119 pub email: Option<&'a str>,
120 pub page: Option<usize>,
121 pub from_email: Option<&'a str>,
122 pub to_email: Option<&'a str>,
123 pub amount: Option<f64>,
124 pub recv_window: Option<usize>,
125 pub timestamp: Option<i64>,
126 pub signature: Option<String>,
127}
128
129impl<'a> Parameters<'a> {
130 pub fn sign<T: Into<String>>(&mut self, secret: T) -> crate::error::Result<&Self> {
131 self.timestamp = Some(Utc::now().timestamp_millis());
132
133 let message = serde_urlencoded::to_string(&self)?;
134 let mut mac = HmacSha256::new_varkey(secret.into().as_bytes())?;
135 mac.update(message.as_bytes());
136 let signature = mac.finalize();
137
138 self.signature = Some(hex::encode(signature.into_bytes()));
139 Ok(self)
140 }
141}