1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Quote {
7 pub symbol: String,
9
10 pub last_price: f64,
12
13 pub change: f64,
15
16 pub change_percent: f64,
18
19 pub volume: u64,
21
22 pub average_volume: u64,
24
25 pub bid_price: f64,
27
28 pub bid_size: u64,
30
31 pub ask_price: f64,
33
34 pub ask_size: u64,
36
37 pub high: f64,
39
40 pub low: f64,
42
43 pub open: f64,
45
46 pub prev_close: f64,
48
49 pub fifty_two_week_high: f64,
51
52 pub fifty_two_week_low: f64,
54
55 pub market_cap: Option<f64>,
57
58 pub pe_ratio: Option<f64>,
60
61 pub timestamp: DateTime<Utc>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct SnapshotParams {
68 #[serde(rename = "symbols")]
70 pub symbols: String,
71
72 #[serde(rename = "category")]
74 pub category: String,
75}
76
77impl SnapshotParams {
78 pub fn new(symbols: impl Into<String>, category: impl Into<String>) -> Self {
80 Self {
81 symbols: symbols.into(),
82 category: category.into(),
83 }
84 }
85
86 pub fn new_stock(symbols: impl Into<String>) -> Self {
88 Self::new(symbols, "STK")
89 }
90
91 pub fn new_stocks(symbols: &[&str]) -> Self {
93 let symbols_str = symbols.join(",");
94 Self::new_stock(symbols_str)
95 }
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct Bar {
101 pub symbol: String,
103
104 pub open: f64,
106
107 pub high: f64,
109
110 pub low: f64,
112
113 pub close: f64,
115
116 pub volume: u64,
118
119 pub timestamp: DateTime<Utc>,
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
125#[serde(rename_all = "lowercase")]
126pub enum TimeFrame {
127 #[serde(rename = "m1")]
129 Minute1,
130
131 #[serde(rename = "m5")]
133 Minute5,
134
135 #[serde(rename = "m15")]
137 Minute15,
138
139 #[serde(rename = "m30")]
141 Minute30,
142
143 #[serde(rename = "h1")]
145 Hour1,
146
147 #[serde(rename = "h4")]
149 Hour4,
150
151 #[serde(rename = "d1")]
153 Day1,
154
155 #[serde(rename = "w1")]
157 Week1,
158
159 #[serde(rename = "mo1")]
161 Month1,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct BarQueryParams {
167 #[serde(rename = "symbol")]
169 pub symbol: String,
170
171 #[serde(rename = "category")]
173 pub category: String,
174
175 #[serde(rename = "timespan")]
177 pub time_frame: TimeFrame,
178
179 #[serde(rename = "count")]
181 pub count: String,
182}
183
184impl BarQueryParams {
185 pub fn new(
187 symbol: impl Into<String>,
188 category: impl Into<String>,
189 time_frame: TimeFrame,
190 count: u32,
191 ) -> Self {
192 Self {
193 symbol: symbol.into(),
194 category: category.into(),
195 time_frame,
196 count: count.to_string(),
197 }
198 }
199
200 pub fn new_stock(symbol: impl Into<String>, time_frame: TimeFrame) -> Self {
202 Self::new(symbol, "STK", time_frame, 200)
203 }
204
205 pub fn count(mut self, count: u32) -> Self {
207 self.count = count.to_string();
208 self
209 }
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct OptionContract {
215 pub symbol: String,
217
218 pub underlying_symbol: String,
220
221 pub strike_price: f64,
223
224 pub expiration_date: DateTime<Utc>,
226
227 pub option_type: OptionType,
229
230 pub last_price: f64,
232
233 pub change: f64,
235
236 pub change_percent: f64,
238
239 pub volume: u64,
241
242 pub open_interest: u64,
244
245 pub bid_price: f64,
247
248 pub bid_size: u64,
250
251 pub ask_price: f64,
253
254 pub ask_size: u64,
256
257 pub implied_volatility: f64,
259
260 pub delta: f64,
262
263 pub gamma: f64,
265
266 pub theta: f64,
268
269 pub vega: f64,
271
272 pub rho: f64,
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
278#[serde(rename_all = "UPPERCASE")]
279pub enum OptionType {
280 Call,
282
283 Put,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
289pub struct OptionChain {
290 pub underlying_symbol: String,
292
293 pub expiration_dates: Vec<DateTime<Utc>>,
295
296 pub strike_prices: Vec<f64>,
298
299 pub contracts: Vec<OptionContract>,
301}
302
303#[derive(Debug, Clone, Serialize, Deserialize)]
305pub struct OptionChainQueryParams {
306 pub underlying_symbol: String,
308
309 pub expiration_date: Option<DateTime<Utc>>,
311
312 pub strike_price: Option<f64>,
314
315 pub option_type: Option<OptionType>,
317}
318
319impl OptionChainQueryParams {
320 pub fn new(underlying_symbol: impl Into<String>) -> Self {
322 Self {
323 underlying_symbol: underlying_symbol.into(),
324 expiration_date: None,
325 strike_price: None,
326 option_type: None,
327 }
328 }
329
330 pub fn expiration_date(mut self, expiration_date: DateTime<Utc>) -> Self {
332 self.expiration_date = Some(expiration_date);
333 self
334 }
335
336 pub fn strike_price(mut self, strike_price: f64) -> Self {
338 self.strike_price = Some(strike_price);
339 self
340 }
341
342 pub fn option_type(mut self, option_type: OptionType) -> Self {
344 self.option_type = Some(option_type);
345 self
346 }
347}
348
349#[derive(Debug, Clone, Serialize, Deserialize)]
351pub struct NewsArticle {
352 pub id: String,
354
355 pub title: String,
357
358 pub summary: String,
360
361 pub url: String,
363
364 pub source: String,
366
367 pub publish_date: DateTime<Utc>,
369
370 pub symbols: Vec<String>,
372}
373
374#[derive(Debug, Clone, Serialize, Deserialize)]
376pub struct NewsQueryParams {
377 pub symbol: Option<String>,
379
380 pub start_date: Option<DateTime<Utc>>,
382
383 pub end_date: Option<DateTime<Utc>>,
385
386 pub limit: Option<u32>,
388}
389
390impl NewsQueryParams {
391 pub fn new() -> Self {
393 Self {
394 symbol: None,
395 start_date: None,
396 end_date: None,
397 limit: None,
398 }
399 }
400
401 pub fn symbol(mut self, symbol: impl Into<String>) -> Self {
403 self.symbol = Some(symbol.into());
404 self
405 }
406
407 pub fn start_date(mut self, start_date: DateTime<Utc>) -> Self {
409 self.start_date = Some(start_date);
410 self
411 }
412
413 pub fn end_date(mut self, end_date: DateTime<Utc>) -> Self {
415 self.end_date = Some(end_date);
416 self
417 }
418
419 pub fn limit(mut self, limit: u32) -> Self {
421 self.limit = Some(limit);
422 self
423 }
424}
425
426impl Default for NewsQueryParams {
427 fn default() -> Self {
428 Self::new()
429 }
430}
431
432#[derive(Debug, Clone, Serialize, Deserialize)]
434pub struct Instrument {
435 pub id: String,
437
438 pub symbol: String,
440
441 pub name: String,
443
444 pub exchange: String,
446
447 pub security_type: String,
449
450 pub region: String,
452
453 pub currency: String,
455
456 pub tradable: bool,
458
459 pub shortable: bool,
461
462 pub marginable: bool,
464
465 pub fractional_tradable: bool,
467}
468
469#[derive(Debug, Clone, Serialize, Deserialize)]
471pub struct InstrumentParams {
472 #[serde(rename = "symbols")]
474 pub symbols: String,
475
476 #[serde(rename = "category")]
478 pub category: String,
479}
480
481impl InstrumentParams {
482 pub fn new(symbols: impl Into<String>, category: impl Into<String>) -> Self {
484 Self {
485 symbols: symbols.into(),
486 category: category.into(),
487 }
488 }
489
490 pub fn new_stock(symbols: impl Into<String>) -> Self {
492 Self::new(symbols, "STK")
493 }
494
495 pub fn new_stocks(symbols: &[&str]) -> Self {
497 let symbols_str = symbols.join(",");
498 Self::new_stock(symbols_str)
499 }
500}
501
502#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct EodBarsParams {
505 #[serde(rename = "instrument_ids")]
507 pub instrument_ids: String,
508
509 #[serde(rename = "date", skip_serializing_if = "Option::is_none")]
511 pub date: Option<String>,
512
513 #[serde(rename = "count")]
515 pub count: String,
516}
517
518impl EodBarsParams {
519 pub fn new(instrument_ids: impl Into<String>, count: u32) -> Self {
521 Self {
522 instrument_ids: instrument_ids.into(),
523 date: None,
524 count: count.to_string(),
525 }
526 }
527
528 pub fn date(mut self, date: impl Into<String>) -> Self {
530 self.date = Some(date.into());
531 self
532 }
533}
534
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
537pub enum CorpActionEventType {
538 #[serde(rename = "SPLIT")]
540 Split,
541
542 #[serde(rename = "REVERSE_SPLIT")]
544 ReverseSplit,
545}
546
547#[derive(Debug, Clone, Serialize, Deserialize)]
549pub struct CorpActionParams {
550 #[serde(rename = "instrument_ids")]
552 pub instrument_ids: String,
553
554 #[serde(rename = "event_types")]
556 pub event_types: String,
557
558 #[serde(rename = "start_date", skip_serializing_if = "Option::is_none")]
560 pub start_date: Option<String>,
561
562 #[serde(rename = "end_date", skip_serializing_if = "Option::is_none")]
564 pub end_date: Option<String>,
565
566 #[serde(rename = "page_number", skip_serializing_if = "Option::is_none")]
568 pub page_number: Option<u32>,
569
570 #[serde(rename = "page_size", skip_serializing_if = "Option::is_none")]
572 pub page_size: Option<u32>,
573
574 #[serde(rename = "last_update_time", skip_serializing_if = "Option::is_none")]
576 pub last_update_time: Option<String>,
577}
578
579impl CorpActionParams {
580 pub fn new(instrument_ids: impl Into<String>, event_types: Vec<CorpActionEventType>) -> Self {
582 let event_types_str = event_types
583 .iter()
584 .map(|et| match et {
585 CorpActionEventType::Split => "SPLIT",
586 CorpActionEventType::ReverseSplit => "REVERSE_SPLIT",
587 })
588 .collect::<Vec<_>>()
589 .join(",");
590
591 Self {
592 instrument_ids: instrument_ids.into(),
593 event_types: event_types_str,
594 start_date: None,
595 end_date: None,
596 page_number: None,
597 page_size: None,
598 last_update_time: None,
599 }
600 }
601
602 pub fn start_date(mut self, start_date: impl Into<String>) -> Self {
604 self.start_date = Some(start_date.into());
605 self
606 }
607
608 pub fn end_date(mut self, end_date: impl Into<String>) -> Self {
610 self.end_date = Some(end_date.into());
611 self
612 }
613
614 pub fn page_number(mut self, page_number: u32) -> Self {
616 self.page_number = Some(page_number);
617 self
618 }
619
620 pub fn page_size(mut self, page_size: u32) -> Self {
622 self.page_size = Some(page_size);
623 self
624 }
625
626 pub fn last_update_time(mut self, last_update_time: impl Into<String>) -> Self {
628 self.last_update_time = Some(last_update_time.into());
629 self
630 }
631}