bitbank_api/
lib.rs

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
8/// Private API with authentication.
9pub mod private;
10/// Public API without authentication.
11pub mod public;
12/// Public streaming API.
13pub mod stream;
14
15use serde_with::{serde_as, DisplayFromStr};
16
17/// Asset pair
18/// - 0: base asset
19/// - 1: quote asset
20#[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        // Find the _ between the pair.
28        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/// Asset type
42#[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/// desc or asc
79#[derive(strum::EnumString, strum::Display, Debug, Clone)]
80#[strum(serialize_all = "snake_case")]
81pub enum SortOrder {
82    Desc,
83    Asc,
84}
85
86/// buy or sell
87#[derive(strum::EnumString, strum::Display, Debug, Clone)]
88#[strum(serialize_all = "snake_case")]
89pub enum Side {
90    Buy,
91    Sell,
92}
93
94/// limit or market or stop or stop limit
95#[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/// maker or taker
105#[derive(strum::EnumString, Debug, Clone)]
106#[strum(serialize_all = "snake_case")]
107pub enum MakerTaker {
108    Maker,
109    Taker,
110}
111
112/// Status of order
113#[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}