bitbank_api/public/
candlestick.rs

1use super::*;
2
3mod raw {
4    use super::*;
5
6    #[derive(Deserialize, Debug)]
7    pub struct Response {
8        pub candlestick: Candlestick,
9    }
10    #[derive(Deserialize, Debug)]
11    pub struct Candlestick(
12        pub Ohlcv,
13        // This is a workaround.
14        // Without this, newtype tries to deserialize as x not as [x]
15        #[serde(skip)] (),
16    );
17
18    #[derive(Deserialize, Debug)]
19    pub struct Ohlcv {
20        pub ohlcv: Vec<OhlcvItem>,
21    }
22
23    #[serde_as]
24    #[derive(Deserialize, Debug)]
25    pub struct OhlcvItem(
26        #[serde_as(as = "DisplayFromStr")] pub f64,
27        #[serde_as(as = "DisplayFromStr")] pub f64,
28        #[serde_as(as = "DisplayFromStr")] pub f64,
29        #[serde_as(as = "DisplayFromStr")] pub f64,
30        #[serde_as(as = "DisplayFromStr")] pub f64,
31        #[serde_as(as = "TimestampMilliSeconds")] pub NaiveDateTime,
32    );
33}
34
35#[derive(Debug)]
36pub struct Candlestick {
37    pub start: f64,
38    pub high: f64,
39    pub low: f64,
40    pub end: f64,
41    pub volume: f64,
42    pub timestamp: NaiveDateTime,
43}
44impl Candlestick {
45    fn new(x: raw::OhlcvItem) -> Self {
46        Candlestick {
47            start: x.0,
48            high: x.1,
49            low: x.2,
50            end: x.3,
51            volume: x.4,
52            timestamp: x.5,
53        }
54    }
55}
56
57#[derive(derive_more::Display, Debug, Clone)]
58pub enum CandleType {
59    #[display(fmt = "1min")]
60    Min1,
61    #[display(fmt = "5min")]
62    Min5,
63    #[display(fmt = "15min")]
64    Min15,
65    #[display(fmt = "30min")]
66    Min30,
67    #[display(fmt = "1hour")]
68    Hour1,
69
70    #[display(fmt = "4hour")]
71    Hour4,
72    #[display(fmt = "8hour")]
73    Hour8,
74    #[display(fmt = "12hour")]
75    Hour12,
76    #[display(fmt = "1day")]
77    Day1,
78    #[display(fmt = "1week")]
79    Week1,
80    #[display(fmt = "1month")]
81    Month1,
82}
83
84#[derive(derive_more::Display, Clone)]
85pub enum Period {
86    #[display(fmt = "{_0}")]
87    YYYY(u16),
88    #[display(fmt = "{_0}{_1}{_2}")]
89    YYYYMMDD(u16, u8, u8),
90}
91
92#[derive(TypedBuilder)]
93pub struct Params {
94    pair: Pair,
95    candle_type: CandleType,
96    period: Period,
97}
98
99fn path(params: Params) -> String {
100    format!(
101        "/{}/candlestick/{}/{}",
102        params.pair, params.candle_type, params.period
103    )
104}
105
106pub async fn get(params: Params) -> anyhow::Result<Vec<Candlestick>> {
107    let resp: raw::Response = do_get(path(params)).await?;
108    let ohlcv = resp.candlestick.0;
109    Ok(ohlcv.ohlcv.into_iter().map(Candlestick::new).collect())
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    #[test]
116    fn test_path() -> anyhow::Result<()> {
117        let params = Params::builder()
118            .pair(Pair(XRP, JPY))
119            .candle_type(CandleType::Day1)
120            .period(Period::YYYY(2023))
121            .build();
122        let path = path(params);
123        assert_eq!(path, "/xrp_jpy/candlestick/1day/2023");
124        Ok(())
125    }
126
127    #[tokio::test]
128    async fn test_candlestick_yyyy() -> anyhow::Result<()> {
129        let params = Params::builder()
130            .pair(Pair(XRP, JPY))
131            .candle_type(CandleType::Month1)
132            .period(Period::YYYY(2022))
133            .build();
134        let resp = get(params).await?;
135        dbg!(&resp);
136        Ok(())
137    }
138
139    #[tokio::test]
140    async fn test_candlestick_yyyymmdd() -> anyhow::Result<()> {
141        let params = Params::builder()
142            .pair(Pair(XRP, JPY))
143            .candle_type(CandleType::Min15)
144            .period(Period::YYYYMMDD(2022, 12, 25))
145            .build();
146        let resp = get(params).await?;
147        dbg!(&resp);
148        Ok(())
149    }
150}