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

1//! Kline/Candlestick message types for Binance Spot WebSocket API
2//!
3//! This module provides optimized data structures for processing
4//! kline/candlestick messages from Binance Spot 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 Spot 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}