alpaca_data/options/
response.rs1use std::collections::HashMap;
2
3use alpaca_core::{Error as CoreError, pagination::PaginatedResponse};
4use serde::{Deserialize, Serialize};
5
6use super::{Bar, Quote, Snapshot, Trade};
7
8#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
9pub struct BarsResponse {
10 #[serde(default)]
11 pub bars: HashMap<String, Vec<Bar>>,
12 pub next_page_token: Option<String>,
13}
14
15#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
16pub struct TradesResponse {
17 #[serde(default)]
18 pub trades: HashMap<String, Vec<Trade>>,
19 pub next_page_token: Option<String>,
20}
21
22#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
23pub struct LatestQuotesResponse {
24 #[serde(default)]
25 pub quotes: HashMap<String, Quote>,
26}
27
28#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
29pub struct LatestTradesResponse {
30 #[serde(default)]
31 pub trades: HashMap<String, Trade>,
32}
33
34#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
35pub struct SnapshotsResponse {
36 #[serde(default)]
37 pub snapshots: HashMap<String, Snapshot>,
38 pub next_page_token: Option<String>,
39}
40
41#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
42pub struct ChainResponse {
43 #[serde(default)]
44 pub snapshots: HashMap<String, Snapshot>,
45 pub next_page_token: Option<String>,
46}
47
48pub type ConditionCodesResponse = HashMap<String, String>;
49pub type ExchangeCodesResponse = HashMap<String, String>;
50
51impl PaginatedResponse for BarsResponse {
52 fn next_page_token(&self) -> Option<&str> {
53 self.next_page_token.as_deref()
54 }
55
56 fn merge_page(&mut self, next: Self) -> Result<(), CoreError> {
57 merge_batch_page(&mut self.bars, next.bars);
58 self.next_page_token = next.next_page_token;
59 Ok(())
60 }
61
62 fn clear_next_page_token(&mut self) {
63 self.next_page_token = None;
64 }
65}
66
67impl PaginatedResponse for TradesResponse {
68 fn next_page_token(&self) -> Option<&str> {
69 self.next_page_token.as_deref()
70 }
71
72 fn merge_page(&mut self, next: Self) -> Result<(), CoreError> {
73 merge_batch_page(&mut self.trades, next.trades);
74 self.next_page_token = next.next_page_token;
75 Ok(())
76 }
77
78 fn clear_next_page_token(&mut self) {
79 self.next_page_token = None;
80 }
81}
82
83impl PaginatedResponse for SnapshotsResponse {
84 fn next_page_token(&self) -> Option<&str> {
85 self.next_page_token.as_deref()
86 }
87
88 fn merge_page(&mut self, next: Self) -> Result<(), CoreError> {
89 merge_snapshot_page("options.snapshots_all", &mut self.snapshots, next.snapshots)?;
90 self.next_page_token = next.next_page_token;
91 Ok(())
92 }
93
94 fn clear_next_page_token(&mut self) {
95 self.next_page_token = None;
96 }
97}
98
99impl PaginatedResponse for ChainResponse {
100 fn next_page_token(&self) -> Option<&str> {
101 self.next_page_token.as_deref()
102 }
103
104 fn merge_page(&mut self, next: Self) -> Result<(), CoreError> {
105 merge_snapshot_page("options.chain_all", &mut self.snapshots, next.snapshots)?;
106 self.next_page_token = next.next_page_token;
107 Ok(())
108 }
109
110 fn clear_next_page_token(&mut self) {
111 self.next_page_token = None;
112 }
113}
114
115fn merge_batch_page<Item>(
116 current: &mut HashMap<String, Vec<Item>>,
117 next: HashMap<String, Vec<Item>>,
118) {
119 for (symbol, mut items) in next {
120 current.entry(symbol).or_default().append(&mut items);
121 }
122}
123
124fn merge_snapshot_page(
125 operation: &str,
126 current: &mut HashMap<String, Snapshot>,
127 next: HashMap<String, Snapshot>,
128) -> Result<(), CoreError> {
129 for (symbol, snapshot) in next {
130 if current.insert(symbol.clone(), snapshot).is_some() {
131 return Err(CoreError::InvalidRequest(format!(
132 "{operation} received duplicate symbol across pages: {symbol}"
133 )));
134 }
135 }
136
137 Ok(())
138}