1use std::fmt;
2use std::hash::{Hash, Hasher};
3use std::marker::PhantomData;
4
5use anyhow::Result;
6use serde::de::{SeqAccess, Visitor};
7use serde::{Deserialize, Deserializer};
8
9#[derive(Debug, Clone)]
10pub struct CrumbData {
11 pub cookie: String,
12 pub crumb: String,
13}
14
15#[derive(Debug, Deserialize, Clone)]
16#[serde(rename_all = "camelCase")]
17pub struct Chart {
18 pub chart: ChartStatus,
19}
20
21#[derive(Debug, Deserialize, Clone)]
22#[serde(rename_all = "camelCase")]
23pub struct ChartStatus {
24 pub result: Option<Vec<ChartData>>,
25 pub error: Option<Error>,
26}
27
28#[derive(Debug, Deserialize, Clone)]
29#[serde(rename_all = "camelCase")]
30pub struct Error {
31 pub code: String,
32 pub description: String,
33}
34
35#[derive(Debug, Deserialize, Clone)]
36#[serde(rename_all = "camelCase")]
37pub struct ChartData {
38 pub meta: ChartMeta,
39 pub timestamp: Vec<i64>,
40 pub indicators: ChartIndicators,
41}
42#[derive(Debug, Deserialize, Clone)]
43#[serde(rename_all = "camelCase")]
44pub struct ChartMeta {
45 pub instrument_type: Option<String>,
46 pub regular_market_price: f64,
47 pub chart_previous_close: f64,
48 pub current_trading_period: Option<ChartCurrentTradingPeriod>,
49}
50
51impl Hash for ChartMeta {
52 fn hash<H: Hasher>(&self, state: &mut H) {
53 self.instrument_type.hash(state);
54 self.regular_market_price.to_bits().hash(state);
55 self.chart_previous_close.to_bits().hash(state);
56 self.current_trading_period.hash(state);
57 }
58}
59
60#[derive(Debug, Deserialize, Clone, Hash)]
61#[serde(rename_all = "camelCase")]
62pub struct ChartCurrentTradingPeriod {
63 pub regular: ChartTradingPeriod,
64 pub pre: ChartTradingPeriod,
65 pub post: ChartTradingPeriod,
66}
67
68#[derive(Debug, Deserialize, Clone, Hash)]
69#[serde(rename_all = "camelCase")]
70pub struct ChartTradingPeriod {
71 pub start: i64,
72 pub end: i64,
73}
74
75#[derive(Debug, Deserialize, Clone)]
76#[serde(rename_all = "camelCase")]
77pub struct ChartIndicators {
78 pub quote: Vec<ChartQuote>,
79 pub adjclose: Option<Vec<ChartAdjClose>>,
80}
81
82#[derive(Debug, Deserialize, Clone)]
83#[serde(rename_all = "camelCase")]
84pub struct ChartAdjClose {
85 #[serde(deserialize_with = "deserialize_vec")]
86 pub adjclose: Vec<f64>,
87}
88
89#[derive(Debug, Deserialize, Clone)]
90#[serde(rename_all = "camelCase")]
91pub struct ChartQuote {
92 #[serde(deserialize_with = "deserialize_vec")]
93 pub close: Vec<f64>,
94 #[serde(deserialize_with = "deserialize_vec")]
95 pub volume: Vec<u64>,
96 #[serde(deserialize_with = "deserialize_vec")]
97 pub high: Vec<f64>,
98 #[serde(deserialize_with = "deserialize_vec")]
99 pub low: Vec<f64>,
100 #[serde(deserialize_with = "deserialize_vec")]
101 pub open: Vec<f64>,
102}
103
104#[derive(Debug, Deserialize, Clone)]
105#[serde(rename_all = "camelCase")]
106pub struct Company {
107 #[serde(rename = "quoteSummary")]
108 pub company: CompanyStatus,
109}
110
111#[derive(Debug, Deserialize, Clone)]
112#[serde(rename_all = "camelCase")]
113pub struct CompanyStatus {
114 pub result: Option<Vec<CompanyData>>,
115 pub error: Option<Error>,
116}
117
118#[derive(Debug, Deserialize, Clone)]
119#[serde(rename_all = "camelCase")]
120pub struct CompanyData {
121 #[serde(rename = "assetProfile")]
122 pub profile: Option<CompanyProfile>,
123 pub price: CompanyPrice,
124}
125
126#[derive(Debug, Deserialize, Clone, Hash)]
127#[serde(rename_all = "camelCase")]
128pub struct CompanyProfile {
129 pub website: Option<String>,
130 pub industry: Option<String>,
131 pub sector: Option<String>,
132 #[serde(rename = "longBusinessSummary")]
133 pub description: Option<String>,
134 #[serde(rename = "fullTimeEmployees")]
135 pub employees: Option<u64>,
136}
137
138#[derive(Debug, Deserialize, Clone)]
139#[serde(rename_all = "camelCase")]
140pub struct CompanyPrice {
141 pub symbol: String,
142 pub short_name: String,
143 pub long_name: Option<String>,
144 pub regular_market_price: CompanyMarketPrice,
145 pub regular_market_previous_close: CompanyMarketPrice,
146 pub post_market_price: OptionalCompanyMarketPrice,
147 pub regular_market_volume: OptionalCompanyMarketPrice,
148 pub currency: Option<String>,
149}
150
151#[derive(Debug, Deserialize, Clone)]
152#[serde(rename_all = "camelCase")]
153pub struct CompanyMarketPrice {
154 #[serde(rename = "raw")]
155 pub price: f64,
156 pub fmt: String,
157}
158
159#[derive(Debug, Deserialize, Clone)]
160#[serde(rename_all = "camelCase")]
161pub struct OptionalCompanyMarketPrice {
162 #[serde(rename = "raw")]
163 pub price: Option<f64>,
164 pub fmt: Option<String>,
165}
166
167#[derive(Debug, Deserialize, Clone)]
168#[serde(rename_all = "camelCase")]
169pub struct Options {
170 pub option_chain: OptionsStatus,
171}
172
173#[derive(Debug, Deserialize, Clone)]
174#[serde(rename_all = "camelCase")]
175pub struct OptionsStatus {
176 pub result: Option<Vec<OptionsHeader>>,
177 pub error: Option<Error>,
178}
179
180#[derive(Debug, Deserialize, Clone)]
181#[serde(rename_all = "camelCase")]
182pub struct OptionsHeader {
183 pub quote: OptionsQuote,
184 pub expiration_dates: Vec<i64>,
185 pub options: Vec<OptionsData>,
186}
187
188#[derive(Debug, Deserialize, Clone)]
189#[serde(rename_all = "camelCase")]
190pub struct OptionsQuote {
191 pub regular_market_price: f64,
192}
193
194impl Hash for OptionsQuote {
195 fn hash<H: Hasher>(&self, state: &mut H) {
196 self.regular_market_price.to_bits().hash(state);
197 }
198}
199
200#[derive(Debug, Deserialize, Clone, Hash)]
201#[serde(rename_all = "camelCase")]
202pub struct OptionsData {
203 pub expiration_date: i64,
204 pub calls: Vec<OptionsContract>,
205 pub puts: Vec<OptionsContract>,
206}
207
208#[derive(Debug, Deserialize, Clone)]
209#[serde(rename_all = "camelCase")]
210pub struct OptionsContract {
211 pub strike: f64,
212 pub last_price: f64,
213 pub change: f64,
214 #[serde(default)]
215 pub percent_change: f64,
216 pub volume: Option<u64>,
217 pub open_interest: Option<u64>,
218 pub bid: Option<f64>,
219 pub ask: Option<f64>,
220 pub implied_volatility: Option<f64>,
221 pub in_the_money: Option<bool>,
222 pub currency: Option<String>,
223}
224
225impl Hash for OptionsContract {
226 fn hash<H: Hasher>(&self, state: &mut H) {
227 self.strike.to_bits().hash(state);
228 self.last_price.to_bits().hash(state);
229 self.change.to_bits().hash(state);
230 self.percent_change.to_bits().hash(state);
231 self.volume.hash(state);
232 self.open_interest.hash(state);
233 self.bid.map(|f| f.to_bits()).hash(state);
234 self.ask.map(|f| f.to_bits()).hash(state);
235 self.implied_volatility.map(|f| f.to_bits()).hash(state);
236 self.in_the_money.hash(state);
237 self.currency.hash(state);
238 }
239}
240
241fn deserialize_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
242where
243 D: Deserializer<'de>,
244 T: Deserialize<'de> + Default,
245{
246 struct SeqVisitor<T>(PhantomData<T>);
247
248 impl<'de, T> Visitor<'de> for SeqVisitor<T>
249 where
250 T: Deserialize<'de> + Default,
251 {
252 type Value = Vec<T>;
253
254 fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
255 fmt.write_str("default vec")
256 }
257
258 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
259 let mut vec = Vec::new();
260 while let Ok(Some(elem)) = seq.next_element::<Option<T>>() {
261 vec.push(elem.unwrap_or_default());
262 }
263 Ok(vec)
264 }
265 }
266 deserializer.deserialize_seq(SeqVisitor(PhantomData))
267}