alpaca_api_client/market_data/options/
trades.rs1use crate::request;
2use serde::Deserialize;
3use std::collections::HashMap;
4
5#[derive(Deserialize, Debug)]
6pub struct OptionTrade {
7 pub t: String, pub x: String, pub p: f64, pub s: i32, pub c: String, }
13
14pub type HistoricalOptionTrades = HashMap<String, Vec<OptionTrade>>;
15pub type LatestOptionTrades = HashMap<String, OptionTrade>;
16
17#[derive(Deserialize, Debug)]
18pub struct HistoricalOptionTradesResponse {
19 trades: HistoricalOptionTrades,
20 next_page_token: Option<String>,
21}
22
23#[derive(Deserialize, Debug)]
24pub struct LatestOptionTradesResponse {
25 trades: LatestOptionTrades,
26}
27
28pub struct HistoricalOptionTradesQuery<'a> {
29 url: &'a str,
30 symbols: Vec<&'a str>,
31 start: Option<&'a str>,
32 end: Option<&'a str>,
33 limit: Option<i32>,
34 sort_asc: bool,
35 sort_desc: bool,
36}
37
38pub struct LatestOptionTradesQuery<'a> {
39 url: &'a str,
40 symbols: Vec<&'a str>,
41 feed: Option<&'a str>,
42}
43
44impl<'a> HistoricalOptionTradesQuery<'a> {
45 pub fn new(symbols: Vec<&'a str>) -> Self {
46 Self {
47 url: "https://data.alpaca.markets/v1beta1/options/trades",
48 symbols,
49 start: None,
50 end: None,
51 limit: None,
52 sort_asc: false,
53 sort_desc: false,
54 }
55 }
56
57 pub fn start(mut self, start: &'a str) -> Self {
58 self.start = Some(start);
59 self
60 }
61
62 pub fn end(mut self, end: &'a str) -> Self {
63 self.end = Some(end);
64 self
65 }
66
67 pub fn limit(mut self, limit: i32) -> Self {
68 self.limit = Some(limit);
69 self
70 }
71
72 pub fn sort_asc(mut self) -> Self {
73 self.sort_asc = true;
74 self.sort_desc = false;
75 self
76 }
77
78 pub fn sort_desc(mut self) -> Self {
79 self.sort_desc = true;
80 self.sort_asc = false;
81 self
82 }
83
84 fn build(&self) -> String {
85 let mut query = format!("symbols={}", self.symbols.join(","));
86
87 if let Some(start) = self.start {
88 query.push_str(&format!("&start={}", start));
89 }
90
91 if let Some(end) = self.end {
92 query.push_str(&format!("&end={}", end));
93 }
94
95 if let Some(limit) = self.limit {
96 query.push_str(&format!("&limit={}", limit));
97 }
98
99 if self.sort_asc {
100 query.push_str("&sort=asc");
101 } else if self.sort_desc {
102 query.push_str("&sort=desc");
103 }
104
105 format!("{}?{}", self.url, query)
106 }
107
108 pub fn send(&self) -> Result<HistoricalOptionTrades, ureq::Error> {
109 let route = self.build();
110 let mut trades: HistoricalOptionTrades = HashMap::new();
111 let mut page_token = None;
112
113 let mut i = 0;
114 let data_limit = if let Some(limit) = self.limit {
115 limit
116 } else {
117 1000
118 };
119 loop {
120 if i >= data_limit {
121 break;
122 }
123
124 let temp_address = match page_token {
126 Some(token) => format!("{}&page_token={}", &route, &token),
127 _ => route.clone(),
128 };
129 let response = request("GET", &temp_address).call()?;
130 let response: HistoricalOptionTradesResponse = response.into_body().read_json()?;
131
132 for (symbol, trade) in response.trades {
134 i += trade.len() as i32;
135 trades.entry(symbol).or_insert(Vec::new()).extend(trade);
136 }
137
138 match response.next_page_token {
140 Some(next_page_token) => page_token = Some(next_page_token.clone()),
141 _ => break,
142 }
143 }
144
145 Ok(trades)
146 }
147}
148
149impl<'a> LatestOptionTradesQuery<'a> {
150 pub fn new(symbols: Vec<&'a str>) -> Self {
151 Self {
152 url: "https://data.alpaca.markets/v1beta1/options/trades/latest",
153 symbols,
154 feed: None,
155 }
156 }
157
158 pub fn feed(mut self, feed: &'a str) -> Self {
159 self.feed = Some(feed);
160 self
161 }
162
163 fn build(self) -> String {
164 let mut query = format!("symbols={}", self.symbols.join(","));
165
166 if let Some(feed) = self.feed {
167 query.push_str(&format!("&feed={}", feed));
168 }
169
170 format!("{}?{}", self.url, query)
171 }
172
173 pub fn send(self) -> Result<LatestOptionTrades, ureq::Error> {
174 let route = self.build();
175 let response = request("GET", &route).call()?;
176 let response: LatestOptionTradesResponse = response.into_body().read_json()?;
177 Ok(response.trades)
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn test_historical_option_trade_query() {
187 let res = HistoricalOptionTradesQuery::new(vec!["AAPL261218C00200000"])
188 .limit(10)
189 .send()
190 .unwrap();
191 dbg!(&res);
192 assert!(res.contains_key("AAPL261218C00200000"));
193 }
194
195 #[test]
196 fn test_latest_option_trade_query() {
197 let res = LatestOptionTradesQuery::new(vec!["AAPL261218C00200000"])
198 .feed("indicative")
199 .send()
200 .unwrap();
201 dbg!(&res);
202 assert!(res.contains_key("AAPL261218C00200000"));
203 }
204}