1use serde::{Deserialize, Serialize};
2use serde_urlencoded::to_string as to_query_params;
3use serde_with::chrono::NaiveDateTime;
4use serde_with::DefaultOnNull;
5use serde_with::TimestampMilliSeconds;
6use typed_builder::TypedBuilder;
7
8pub mod private;
10pub mod public;
12pub mod stream;
14
15use serde_with::{serde_as, DisplayFromStr};
16
17#[derive(derive_more::Display, Debug, Clone)]
21#[display(fmt = "{_0}_{_1}")]
22pub struct Pair(pub Asset, pub Asset);
23
24impl std::str::FromStr for Pair {
25 type Err = anyhow::Error;
26 fn from_str(s: &str) -> Result<Self, Self::Err> {
27 let sep = s
29 .char_indices()
30 .find(|(_, c)| *c == '_')
31 .map(|(idx, _)| idx)
32 .ok_or(anyhow::anyhow!("failed to parse pair"))?;
33
34 let x = s[0..sep].parse()?;
35 let y = s[sep + 1..].parse()?;
36
37 Ok(Self(x, y))
38 }
39}
40
41#[derive(strum::EnumString, strum::Display, Debug, Clone)]
43#[strum(serialize_all = "snake_case")]
44pub enum Asset {
45 XRP,
46 JPY,
47 BTC,
48 LTC,
49 ETH,
50 MONA,
51 BCC,
52 XLM,
53 QTUM,
54 BAT,
55 OMG,
56 XYM,
57 LINK,
58 MKR,
59 BOBA,
60 ENJ,
61 MATIC,
62 DOT,
63 DOGE,
64 ASTR,
65 ADA,
66 AVAX,
67 AXS,
68 FLR,
69 SAND,
70 GALA,
71 APE,
72 CHZ,
73 OAS,
74}
75#[cfg(test)]
76pub use Asset::*;
77
78#[derive(strum::EnumString, strum::Display, Debug, Clone)]
80#[strum(serialize_all = "snake_case")]
81pub enum SortOrder {
82 Desc,
83 Asc,
84}
85
86#[derive(strum::EnumString, strum::Display, Debug, Clone)]
88#[strum(serialize_all = "snake_case")]
89pub enum Side {
90 Buy,
91 Sell,
92}
93
94#[derive(strum::EnumString, strum::Display, Debug, Clone)]
96#[strum(serialize_all = "snake_case")]
97pub enum OrderType {
98 Limit,
99 Market,
100 Stop,
101 StopLimit,
102}
103
104#[derive(strum::EnumString, Debug, Clone)]
106#[strum(serialize_all = "snake_case")]
107pub enum MakerTaker {
108 Maker,
109 Taker,
110}
111
112#[derive(strum::EnumString, Debug, Clone)]
114#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
115pub enum OrderStatus {
116 Inactive,
117 Unfilled,
118 ParitallyFilled,
119 FullyFilled,
120 CanceledUnfilled,
121 CanceledPartiallyFilled,
122}
123
124#[derive(Deserialize, Debug)]
125struct Response {
126 success: u16,
127 data: serde_json::Value,
128}
129
130impl Response {
131 fn result(self) -> anyhow::Result<serde_json::Value> {
132 if self.success == 1 {
133 Ok(self.data)
134 } else {
135 let e: ResponseError = serde_json::from_value(self.data)?;
136 Err(ApiError { code: e.code }.into())
137 }
138 }
139}
140
141#[derive(thiserror::Error, Debug)]
142#[error("bitbank API error (code={code})")]
143struct ApiError {
144 code: u16,
145}
146
147#[derive(Deserialize, Debug)]
148struct ResponseError {
149 code: u16,
150}