1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use super::super::utils::http_get;
use crate::error::{Error, Result};
use std::collections::{BTreeMap, HashMap};

use serde::{Deserialize, Serialize};
use serde_json::Value;

const BASE_URL: &str = "https://apiv2.bitz.com";

/// The RESTful client for BitZ swap markets.
///
/// * RESTful API doc: <https://apidocv2.bitz.plus/en/>
/// * Trading at: <https://swap.bitz.plus/en/>
/// * Rate Limits: <https://apidocv2.bitz.plus/en/#limit>
///   * no more than 30 times within 1 sec
pub struct BitzSwapRestClient {
    _api_key: Option<String>,
    _api_secret: Option<String>,
}

impl BitzSwapRestClient {
    pub fn new(api_key: Option<String>, api_secret: Option<String>) -> Self {
        BitzSwapRestClient {
            _api_key: api_key,
            _api_secret: api_secret,
        }
    }

    /// Get the latest Level2 snapshot of orderbook.
    ///
    /// Top 100 bids and asks are returned.
    ///
    /// For example: <https://apiv2.bitz.com/V2/Market/getContractOrderBook?contractId=101&depth=100>,
    pub fn fetch_l2_snapshot(symbol: &str) -> Result<String> {
        let symbol_id_map = get_symbol_id_map()?;
        if !symbol_id_map.contains_key(symbol) {
            return Err(Error(format!(
                "Can NOT find contractId for the pair {}",
                symbol
            )));
        }
        let contract_id = symbol_id_map.get(symbol).unwrap();
        gen_api!(format!(
            "/V2/Market/getContractOrderBook?contractId={}&depth=100",
            contract_id
        ))
    }
}

#[derive(Clone, Serialize, Deserialize)]
#[allow(non_snake_case)]
struct SwapMarket {
    contractId: String, // contract id
    pair: String,       //contract market
    status: String,
    #[serde(flatten)]
    extra: HashMap<String, Value>,
}

#[derive(Serialize, Deserialize)]
struct Response {
    status: i64,
    msg: String,
    data: Vec<SwapMarket>,
    time: i64,
    microtime: String,
    source: String,
}

fn get_symbol_id_map() -> Result<HashMap<String, String>> {
    let params = BTreeMap::new();
    let txt = http_get("https://apiv2.bitz.com/Market/getContractCoin", &params)?;
    let resp = serde_json::from_str::<Response>(&txt)?;
    if resp.status != 200 {
        return Err(Error(txt));
    }

    let mut symbol_id_map = HashMap::<String, String>::new();
    for x in resp.data.iter() {
        if x.status == "1" {
            symbol_id_map.insert(x.pair.clone(), x.contractId.clone());
        }
    }
    Ok(symbol_id_map)
}