tickrs_api/
model.rs

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}