rusty_feeder/exchange/binance/futures/data/
kline.rs

1//! Kline/Candlestick message types for Binance Futures WebSocket API
2//!
3//! This module provides optimized data structures for processing
4//! kline/candlestick messages from Binance Futures WebSocket streams.
5
6use rust_decimal::Decimal;
7use rust_decimal_macros::dec;
8use serde::{Deserialize, Serialize};
9use smartstring::alias::String;
10
11/// Kline/Candlestick message from Binance Futures WebSocket
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[repr(align(16))] // Align for better memory access
14pub struct KlineMessage {
15    /// Event type
16    #[serde(rename = "e")]
17    pub event_type: String,
18
19    /// Event time
20    #[serde(rename = "E")]
21    pub event_time: u64,
22
23    /// Symbol
24    #[serde(rename = "s")]
25    pub symbol: String,
26
27    /// Kline data
28    #[serde(rename = "k")]
29    pub kline: KlineData,
30}
31
32/// Kline/Candlestick data
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct KlineData {
35    /// Kline start time
36    #[serde(rename = "t")]
37    pub start_time: u64,
38
39    /// Kline close time
40    #[serde(rename = "T")]
41    pub close_time: u64,
42
43    /// Symbol
44    #[serde(rename = "s")]
45    pub symbol: String,
46
47    /// Interval
48    #[serde(rename = "i")]
49    pub interval: String,
50
51    /// First trade ID
52    #[serde(rename = "f")]
53    pub first_trade_id: u64,
54
55    /// Last trade ID
56    #[serde(rename = "L")]
57    pub last_trade_id: u64,
58
59    /// Open price
60    #[serde(rename = "o")]
61    pub open: String,
62
63    /// Close price
64    #[serde(rename = "c")]
65    pub close: String,
66
67    /// High price
68    #[serde(rename = "h")]
69    pub high: String,
70
71    /// Low price
72    #[serde(rename = "l")]
73    pub low: String,
74
75    /// Base asset volume
76    #[serde(rename = "v")]
77    pub volume: String,
78
79    /// Number of trades
80    #[serde(rename = "n")]
81    pub number_of_trades: u64,
82
83    /// Is this kline closed?
84    #[serde(rename = "x")]
85    pub is_closed: bool,
86
87    /// Quote asset volume
88    #[serde(rename = "q")]
89    pub quote_volume: String,
90
91    /// Taker buy base asset volume
92    #[serde(rename = "V")]
93    pub taker_buy_volume: String,
94
95    /// Taker buy quote asset volume
96    #[serde(rename = "Q")]
97    pub taker_buy_quote_volume: String,
98
99    /// Ignore
100    #[serde(rename = "B", default)]
101    pub ignore: String,
102}
103
104/// Parsed kline data with Decimal values
105#[derive(Debug, Clone)]
106#[repr(align(16))] // Align for better memory access
107pub struct ParsedKlineData {
108    /// Symbol
109    pub symbol: String,
110
111    /// Interval
112    pub interval: String,
113
114    /// Start time
115    pub start_time: u64,
116
117    /// Close time
118    pub close_time: u64,
119
120    /// Open price
121    pub open: Decimal,
122
123    /// High price
124    pub high: Decimal,
125
126    /// Low price
127    pub low: Decimal,
128
129    /// Close price
130    pub close: Decimal,
131
132    /// Volume
133    pub volume: Decimal,
134
135    /// Number of trades
136    pub number_of_trades: u64,
137
138    /// Is closed
139    pub is_closed: bool,
140
141    /// Quote asset volume
142    pub quote_volume: Decimal,
143
144    /// Event time (when message was generated)
145    pub event_time: u64,
146}
147
148impl From<KlineMessage> for ParsedKlineData {
149    fn from(msg: KlineMessage) -> Self {
150        ParsedKlineData {
151            symbol: msg.symbol,
152            interval: msg.kline.interval,
153            start_time: msg.kline.start_time,
154            close_time: msg.kline.close_time,
155            open: msg.kline.open.parse().unwrap_or(dec!(0)),
156            high: msg.kline.high.parse().unwrap_or(dec!(0)),
157            low: msg.kline.low.parse().unwrap_or(dec!(0)),
158            close: msg.kline.close.parse().unwrap_or(dec!(0)),
159            volume: msg.kline.volume.parse().unwrap_or(dec!(0)),
160            number_of_trades: msg.kline.number_of_trades,
161            is_closed: msg.kline.is_closed,
162            quote_volume: msg.kline.quote_volume.parse().unwrap_or(dec!(0)),
163            event_time: msg.event_time,
164        }
165    }
166}
167
168/// Continuous kline/candlestick message (perpetual contracts)
169#[derive(Debug, Clone, Serialize, Deserialize)]
170#[repr(align(16))] // Align for better memory access
171pub struct ContinuousKlineMessage {
172    /// Event type
173    #[serde(rename = "e")]
174    pub event_type: String,
175
176    /// Event time
177    #[serde(rename = "E")]
178    pub event_time: u64,
179
180    /// Symbol
181    #[serde(rename = "ps")]
182    pub pair: String,
183
184    /// Contract type
185    #[serde(rename = "ct")]
186    pub contract_type: String,
187
188    /// Kline data
189    #[serde(rename = "k")]
190    pub kline: ContinuousKlineData,
191}
192
193/// Continuous kline/candlestick data
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ContinuousKlineData {
196    /// Kline start time
197    #[serde(rename = "t")]
198    pub start_time: u64,
199
200    /// Kline close time
201    #[serde(rename = "T")]
202    pub close_time: u64,
203
204    /// Pair
205    #[serde(rename = "ps")]
206    pub pair: String,
207
208    /// Contract type
209    #[serde(rename = "ct")]
210    pub contract_type: String,
211
212    /// Interval
213    #[serde(rename = "i")]
214    pub interval: String,
215
216    /// First trade ID
217    #[serde(rename = "f")]
218    pub first_trade_id: i64,
219
220    /// Last trade ID
221    #[serde(rename = "L")]
222    pub last_trade_id: i64,
223
224    /// Open price
225    #[serde(rename = "o")]
226    pub open: String,
227
228    /// Close price
229    #[serde(rename = "c")]
230    pub close: String,
231
232    /// High price
233    #[serde(rename = "h")]
234    pub high: String,
235
236    /// Low price
237    #[serde(rename = "l")]
238    pub low: String,
239
240    /// Base asset volume
241    #[serde(rename = "v")]
242    pub volume: String,
243
244    /// Number of trades
245    #[serde(rename = "n")]
246    pub number_of_trades: u64,
247
248    /// Is this kline closed?
249    #[serde(rename = "x")]
250    pub is_closed: bool,
251
252    /// Quote asset volume
253    #[serde(rename = "q")]
254    pub quote_volume: String,
255}
256
257/// Parsed continuous kline data with Decimal values
258#[derive(Debug, Clone)]
259#[repr(align(16))] // Align for better memory access
260pub struct ParsedContinuousKlineData {
261    /// Pair
262    pub pair: String,
263
264    /// Contract type
265    pub contract_type: String,
266
267    /// Interval
268    pub interval: String,
269
270    /// Start time
271    pub start_time: u64,
272
273    /// Close time
274    pub close_time: u64,
275
276    /// Open price
277    pub open: Decimal,
278
279    /// High price
280    pub high: Decimal,
281
282    /// Low price
283    pub low: Decimal,
284
285    /// Close price
286    pub close: Decimal,
287
288    /// Volume
289    pub volume: Decimal,
290
291    /// Number of trades
292    pub number_of_trades: u64,
293
294    /// Is closed
295    pub is_closed: bool,
296
297    /// Quote asset volume
298    pub quote_volume: Decimal,
299
300    /// Event time (when message was generated)
301    pub event_time: u64,
302}
303
304impl From<ContinuousKlineMessage> for ParsedContinuousKlineData {
305    fn from(msg: ContinuousKlineMessage) -> Self {
306        ParsedContinuousKlineData {
307            pair: msg.pair,
308            contract_type: msg.contract_type,
309            interval: msg.kline.interval,
310            start_time: msg.kline.start_time,
311            close_time: msg.kline.close_time,
312            open: msg.kline.open.parse().unwrap_or(dec!(0)),
313            high: msg.kline.high.parse().unwrap_or(dec!(0)),
314            low: msg.kline.low.parse().unwrap_or(dec!(0)),
315            close: msg.kline.close.parse().unwrap_or(dec!(0)),
316            volume: msg.kline.volume.parse().unwrap_or(dec!(0)),
317            number_of_trades: msg.kline.number_of_trades,
318            is_closed: msg.kline.is_closed,
319            quote_volume: msg.kline.quote_volume.parse().unwrap_or(dec!(0)),
320            event_time: msg.event_time,
321        }
322    }
323}