crypto_com_exchange/model/
candlestick.rs

1use serde::{Serialize, Deserialize};
2use serde_aux::prelude::deserialize_number_from_string;
3use chrono::{DateTime, Utc, serde::ts_milliseconds};
4use std::fmt;
5
6// Main container of a candlestick
7#[derive(Serialize,Deserialize, Debug)]
8pub struct CandlestickResult {
9    /// Just the instrument name
10    pub instrument_name: String,
11
12    /// Subscription name used to subscribe this event
13    pub subscription: String,
14
15    /// The time interval affected by this candlestick. The options are
16    /// 1m : one minute
17    /// 5m : five minutes
18    /// 15m : 15 minutes
19    /// 30m: 30 minutes
20    /// 1h : one hour
21    /// 4h : 4 hours
22    /// 6h : 6 hours
23    /// 12h : 12 hours
24    /// 1D : one day
25    /// 7D : one week
26    /// 14D : two weeks
27    /// 1M : one month
28    pub interval: TimeFrame,
29
30    /// Actual candlestick information
31    pub data: Vec<Candlestick>
32}
33
34/// Candlestick received from subscription
35#[derive(Serialize, Deserialize, Debug)]
36pub struct Candlestick {
37
38    /// Open price
39    #[serde(rename = "o", deserialize_with = "deserialize_number_from_string")]
40    pub open: f32,
41    
42    /// Close price
43    #[serde(rename = "c", deserialize_with = "deserialize_number_from_string")]
44    pub close: f32,
45
46    /// Highest price
47    #[serde(rename = "h", deserialize_with = "deserialize_number_from_string")]
48    pub high: f32,
49
50    /// Lowest price
51    #[serde(rename = "l", deserialize_with = "deserialize_number_from_string")]
52    pub low: f32,
53
54    /// Volume
55    #[serde(rename = "v", deserialize_with = "deserialize_number_from_string")]
56    pub volume: f32,
57
58    /// Update time
59    #[serde(rename = "ut", with = "ts_milliseconds")]
60    pub update_time: DateTime<Utc>,
61
62    /// When the candlestick starts
63    #[serde(rename = "t", with = "ts_milliseconds")]
64    pub start_time: DateTime<Utc>
65}
66
67#[derive(Serialize,Deserialize, Debug)]
68pub enum TimeFrame {
69    #[serde(rename = "1m")]
70    OneMinute,
71
72    #[serde(rename = "5m")]
73    FiveMinutes,
74
75    #[serde(rename = "15m")]
76    FiteenMinutes,
77
78    #[serde(rename = "30m")]
79    ThirtyMinutes,
80
81    #[serde(rename = "1h")]
82    OneHour,
83
84    #[serde(rename = "4h")]
85    FourHours,
86
87    #[serde(rename = "6h")]
88    SixHours,
89
90    #[serde(rename = "12h")]
91    TwelveHours,
92
93    #[serde(rename = "1D")]
94    OneDay,
95    
96    #[serde(rename = "7D")]
97    OneWeek,
98
99    #[serde(rename = "14D")]
100    TwoWeeks,
101
102    #[serde(rename = "1M")]
103    OneMonth
104}
105
106impl fmt::Display for TimeFrame {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        match *self {
109            TimeFrame::OneMinute => write!(f, "1m"),
110            TimeFrame::FiveMinutes => write!(f, "5m"),
111            TimeFrame::FiteenMinutes => write!(f, "15m"),
112            TimeFrame::ThirtyMinutes => write!(f, "30m"),
113            TimeFrame::OneHour => write!(f, "1h"),
114            TimeFrame::FourHours => write!(f, "4h"),
115            TimeFrame::SixHours => write!(f, "6h"),
116            TimeFrame::TwelveHours => write!(f, "12h"),
117            TimeFrame::OneDay => write!(f, "1D"),
118            TimeFrame::OneWeek => write!(f, "7D"),
119            TimeFrame::TwoWeeks => write!(f, "14D"),
120            TimeFrame::OneMonth => write!(f, "1M"),
121        }
122    }
123}
124
125pub fn candlestick(time_frame: TimeFrame, instrument_name: &str) -> String {
126    format!("candlestick.{time_frame}.{instrument_name}")
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use serde_json::from_str;
133
134    #[test]
135    fn check_structure() {
136        let json = "{
137            \"instrument_name\": \"ETH_CRO\",
138            \"subscription\": \"candlestick.1m.ETH_CRO\",
139            \"channel\": \"candlestick\",
140            \"depth\":300,
141            \"interval\": \"1m\",
142            \"data\":[
143              {
144                \"o\": \"162.03\",
145                \"c\": \"162.04\",
146                \"h\": \"161.96\",
147                \"l\": \"161.98\",
148                \"v\": \"336.452694\",
149                \"t\": 1589443241000,
150                \"ut\": 1589443242000
151              },
152              {
153                \"o\": \"163.03\",
154                \"c\": \"163.04\",
155                \"h\": \"162.96\",
156                \"l\": \"162.98\",
157                \"v\": \"336.452694\",
158                \"t\": 1589443241000,
159                \"ut\": 1589443242000
160              }
161              ]
162          }";
163
164        let candlestick_result = from_str::<CandlestickResult>(json).unwrap();
165        assert_eq!(candlestick_result.instrument_name, "ETH_CRO");
166        assert_eq!(candlestick_result.subscription, "candlestick.1m.ETH_CRO");
167        assert_eq!(candlestick_result.interval, "1m");
168        assert_eq!(candlestick_result.data.len(), 2);
169
170        // The data
171        let data = &candlestick_result.data[0];
172        assert_eq!(data.open, 162.03);
173        assert_eq!(data.close, 162.04);
174        assert_eq!(data.high, 161.96);
175        assert_eq!(data.low, 161.98);
176        assert_eq!(data.volume, 336.452694);
177        assert_eq!(data.start_time, DateTime::parse_from_rfc3339("2020-05-14T08:00:41+00:00").unwrap());
178        assert_eq!(data.update_time, DateTime::parse_from_rfc3339("2020-05-14T08:00:42+00:00").unwrap());
179        
180    }
181}