qamd_rs/
lib.rs

1//! # QAMD-RS
2//! 
3//! Market data protocol library for QUANTAXIS systems.
4//! Provides standardized types for market data handling and exchange.
5
6pub mod error;
7pub mod snapshot;
8pub mod tick;
9pub mod constants;
10pub mod types;
11pub mod daily;
12pub mod minute;
13
14pub use snapshot::MDSnapshot;
15pub use tick::Tick;
16pub use error::QAMDError;
17pub use types::*;
18pub use daily::{
19    DailyMarketData, 
20    DailyBar,
21    InstrumentType,
22};
23pub use minute::{
24    MinuteMarketData,
25    MinuteBar,
26};
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31    use chrono::Utc;
32    use serde_json;
33
34    #[test]
35    fn test_create_snapshot() {
36        let now = Utc::now();
37        let snapshot = MDSnapshot {
38            instrument_id: "SSE_688286".to_string(),
39            amount: 1000000.0,
40            ask_price1: 10.5,
41            ask_volume1: 100,
42            bid_price1: 10.4,
43            bid_volume1: 150,
44            last_price: 10.45,
45            datetime: now,
46            highest: 10.6,
47            lowest: 10.3,
48            open: 10.35,
49            close: OptionalF64::Value(10.5),
50            volume: 25000,
51            pre_close: 10.3,
52            lower_limit: 9.3,
53            upper_limit: 11.3,
54            average: 10.45,
55            // Set optional fields
56            ask_price2: Some(10.55),
57            ask_volume2: Some(200),
58            bid_price2: Some(10.35),
59            bid_volume2: Some(250),
60            // Other optional fields defaulted
61            ask_price3: None,
62            ask_price4: None,
63            ask_price5: None,
64            ask_price6: None,
65            ask_price7: None,
66            ask_price8: None,
67            ask_price9: None,
68            ask_price10: None,
69            ask_volume3: None,
70            ask_volume4: None,
71            ask_volume5: None,
72            ask_volume6: None,
73            ask_volume7: None,
74            ask_volume8: None,
75            ask_volume9: None,
76            ask_volume10: None,
77            bid_price3: None,
78            bid_price4: None,
79            bid_price5: None,
80            bid_price6: None,
81            bid_price7: None,
82            bid_price8: None,
83            bid_price9: None,
84            bid_price10: None,
85            bid_volume3: None,
86            bid_volume4: None,
87            bid_volume5: None,
88            bid_volume6: None,
89            bid_volume7: None,
90            bid_volume8: None,
91            bid_volume9: None,
92            bid_volume10: None,
93            open_interest: OptionalF64::String("-".to_string()),
94            pre_open_interest: OptionalF64::String("-".to_string()),
95            pre_settlement: OptionalF64::String("-".to_string()),
96            settlement: OptionalF64::String("-".to_string()),
97            iopv: OptionalF64::Null,
98        };
99
100        assert_eq!(snapshot.instrument_id, "SSE_688286");
101        assert_eq!(snapshot.last_price, 10.45);
102        let spread = snapshot.bid_ask_spread();
103        assert!((spread - 0.1).abs() < f64::EPSILON * 100.0, "Expected spread to be approximately 0.1, got {}", spread);
104        assert!(snapshot.has_level2_depth());
105        assert!(!snapshot.is_futures_or_options());
106        assert!(!snapshot.is_etf());
107    }
108
109    #[test]
110    fn test_create_tick_from_snapshot() {
111        let now = Utc::now();
112        let snapshot = MDSnapshot {
113            instrument_id: "SZSE_300750".to_string(),
114            amount: 500000.0,
115            ask_price1: 55.67,
116            ask_volume1: 500,
117            bid_price1: 55.65,
118            bid_volume1: 300,
119            last_price: 55.66,
120            datetime: now,
121            highest: 56.0,
122            lowest: 55.2,
123            open: 55.5,
124            close: OptionalF64::Value(55.66),
125            volume: 10000,
126            pre_close: 55.4,
127            lower_limit: 50.0,
128            upper_limit: 61.0,
129            average: 55.65,
130            // All other fields defaulted to None
131            ask_price2: None,
132            ask_price3: None,
133            ask_price4: None,
134            ask_price5: None,
135            ask_price6: None,
136            ask_price7: None,
137            ask_price8: None,
138            ask_price9: None,
139            ask_price10: None,
140            ask_volume2: None,
141            ask_volume3: None,
142            ask_volume4: None,
143            ask_volume5: None,
144            ask_volume6: None,
145            ask_volume7: None,
146            ask_volume8: None,
147            ask_volume9: None,
148            ask_volume10: None,
149            bid_price2: None,
150            bid_price3: None,
151            bid_price4: None,
152            bid_price5: None,
153            bid_price6: None,
154            bid_price7: None,
155            bid_price8: None,
156            bid_price9: None,
157            bid_price10: None,
158            bid_volume2: None,
159            bid_volume3: None,
160            bid_volume4: None,
161            bid_volume5: None,
162            bid_volume6: None,
163            bid_volume7: None,
164            bid_volume8: None,
165            bid_volume9: None,
166            bid_volume10: None,
167            open_interest: OptionalF64::String("-".to_string()),
168            pre_open_interest: OptionalF64::String("-".to_string()),
169            pre_settlement: OptionalF64::String("-".to_string()),
170            settlement: OptionalF64::String("-".to_string()),
171            iopv: OptionalF64::Null,
172        };
173
174        let tick = Tick::from_snapshot(&snapshot);
175        
176        assert_eq!(tick.instrument_id, "SZSE_300750");
177        assert_eq!(tick.last_price, 55.66);
178        assert_eq!(tick.volume, 10000);
179        assert_eq!(tick.amount, 500000.0);
180        assert_eq!(tick.datetime, now);
181    }
182
183    #[test]
184    fn test_serialization() {
185        let now = Utc::now();
186        let snapshot = MDSnapshot {
187            instrument_id: "SSE_688286".to_string(),
188            amount: 1000000.0,
189            ask_price1: 10.5,
190            ask_volume1: 100,
191            bid_price1: 10.4,
192            bid_volume1: 150,
193            last_price: 10.45,
194            datetime: now,
195            highest: 10.6,
196            lowest: 10.3,
197            open: 10.35,
198            close: OptionalF64::Value(10.5),
199            volume: 25000,
200            pre_close: 10.3,
201            lower_limit: 9.3,
202            upper_limit: 11.3,
203            average: 10.45,
204            // Minimal required fields
205            ask_price2: None,
206            ask_price3: None,
207            ask_price4: None,
208            ask_price5: None,
209            ask_price6: None,
210            ask_price7: None,
211            ask_price8: None,
212            ask_price9: None,
213            ask_price10: None,
214            ask_volume2: None,
215            ask_volume3: None,
216            ask_volume4: None,
217            ask_volume5: None,
218            ask_volume6: None,
219            ask_volume7: None,
220            ask_volume8: None,
221            ask_volume9: None,
222            ask_volume10: None,
223            bid_price2: None,
224            bid_price3: None,
225            bid_price4: None,
226            bid_price5: None,
227            bid_price6: None,
228            bid_price7: None,
229            bid_price8: None,
230            bid_price9: None,
231            bid_price10: None,
232            bid_volume2: None,
233            bid_volume3: None,
234            bid_volume4: None,
235            bid_volume5: None,
236            bid_volume6: None,
237            bid_volume7: None,
238            bid_volume8: None,
239            bid_volume9: None,
240            bid_volume10: None,
241            open_interest: OptionalF64::String("-".to_string()),
242            pre_open_interest: OptionalF64::String("-".to_string()),
243            pre_settlement: OptionalF64::String("-".to_string()),
244            settlement: OptionalF64::String("-".to_string()),
245            iopv: OptionalF64::Null,
246        };
247
248        let json = serde_json::to_string(&snapshot).unwrap();
249        let deserialized: MDSnapshot = serde_json::from_str(&json).unwrap();
250        
251        assert_eq!(deserialized.instrument_id, snapshot.instrument_id);
252        assert_eq!(deserialized.last_price, snapshot.last_price);
253        assert_eq!(deserialized.bid_ask_spread(), snapshot.bid_ask_spread());
254    }
255}