1#![cfg_attr(
14 not(feature = "blocking"),
15 doc = "
16# Get the latest available quote:
17```rust
18use yahoo_finance_api as yahoo;
19use time::OffsetDateTime;
20use tokio_test;
21
22fn main() {
23 let provider = yahoo::YahooConnector::new().unwrap();
24 // get the latest quotes in 1 minute intervals
25 let response = tokio_test::block_on(provider.get_latest_quotes(\"AAPL\", \"1d\")).unwrap();
26 // extract just the latest valid quote summery
27 // including timestamp,open,close,high,low,volume
28 let quote = response.last_quote().unwrap();
29 let time: OffsetDateTime =
30 OffsetDateTime::from_unix_timestamp(quote.timestamp).unwrap();
31 println!(\"At {} quote price of Apple was {}\", time, quote.close);
32}
33```
34# Get history of quotes for given time period:
35```rust
36use yahoo_finance_api as yahoo;
37use time::{macros::datetime, OffsetDateTime};
38use tokio_test;
39
40fn main() {
41 let provider = yahoo::YahooConnector::new().unwrap();
42 let start = datetime!(2020-1-1 0:00:00.00 UTC);
43 let end = datetime!(2020-1-31 23:59:59.99 UTC);
44 // returns historic quotes with daily interval
45 let resp = tokio_test::block_on(provider.get_quote_history(\"AAPL\", start, end)).unwrap();
46 let quotes = resp.quotes().unwrap();
47 println!(\"Apple's quotes in January: {:?}\", quotes);
48}
49```
50# Get the history of quotes for time range
51Another method to retrieve a range of quotes is by requesting the quotes for a given period and
52lookup frequency. Here is an example retrieving the daily quotes for the last month:
53```rust
54use yahoo_finance_api as yahoo;
55use tokio_test;
56
57fn main() {
58 let provider = yahoo::YahooConnector::new().unwrap();
59 let response = tokio_test::block_on(provider.get_quote_range(\"AAPL\", \"1d\", \"1mo\")).unwrap();
60 let quotes = response.quotes().unwrap();
61 println!(\"Apple's quotes of the last month: {:?}\", quotes);
62}
63```
64
65# Search for a ticker given a search string (e.g. company name):
66```rust
67use yahoo_finance_api as yahoo;
68use tokio_test;
69
70fn main() {
71 let provider = yahoo::YahooConnector::new().unwrap();
72 let resp = tokio_test::block_on(provider.search_ticker(\"Apple\")).unwrap();
73
74 let mut apple_found = false;
75 println!(\"All tickers found while searching for 'Apple':\");
76 for item in resp.quotes
77 {
78 println!(\"{}\", item.symbol)
79 }
80}
81```
82Some fields like `longname` are only optional and will be replaced by default
83values if missing (e.g. empty string). If you do not like this behavior,
84use `search_ticker_opt` instead which contains `Option<String>` fields,
85returning `None` if the field found missing in the response.
86"
87)]
88#![cfg_attr(
90 feature = "blocking",
91 doc = "
92# Get the latest available quote (with blocking feature enabled):
93```rust
94use yahoo_finance_api as yahoo;
95use time::OffsetDateTime;
96
97fn main() {
98 let provider = yahoo::YahooConnector::new().unwrap();
99 // get the latest quotes in 1 minute intervals
100 let response = provider.get_latest_quotes(\"AAPL\", \"1d\").unwrap();
101 // extract just the latest valid quote summery
102 // including timestamp,open,close,high,low,volume
103 let quote = response.last_quote().unwrap();
104 let time: OffsetDateTime =
105 OffsetDateTime::from_unix_timestamp(quote.timestamp).unwrap();
106 println!(\"At {} quote price of Apple was {}\", time, quote.close);
107}
108```
109# Get history of quotes for given time period:
110```rust
111use yahoo_finance_api as yahoo;
112use time::{macros::datetime, OffsetDateTime};
113
114fn main() {
115 let provider = yahoo::YahooConnector::new().unwrap();
116 let start = datetime!(2020-1-1 0:00:00.00 UTC);
117 let end = datetime!(2020-1-31 23:59:59.99 UTC);
118 // returns historic quotes with daily interval
119 let resp = provider.get_quote_history(\"AAPL\", start, end).unwrap();
120 let quotes = resp.quotes().unwrap();
121 println!(\"Apple's quotes in January: {:?}\", quotes);
122}
123
124```
125# Get the history of quotes for time range
126Another method to retrieve a range of quotes is by requesting the quotes for a given period and
127lookup frequency. Here is an example retrieving the daily quotes for the last month:
128```rust
129use yahoo_finance_api as yahoo;
130
131fn main() {
132 let provider = yahoo::YahooConnector::new().unwrap();
133 let response = provider.get_quote_range(\"AAPL\", \"1d\", \"1mo\").unwrap();
134 let quotes = response.quotes().unwrap();
135 println!(\"Apple's quotes of the last month: {:?}\", quotes);
136}
137```
138# Search for a ticker given a search string (e.g. company name):
139```rust
140use yahoo_finance_api as yahoo;
141
142fn main() {
143 let provider = yahoo::YahooConnector::new().unwrap();
144 let resp = provider.search_ticker(\"Apple\").unwrap();
145
146 let mut apple_found = false;
147 println!(\"All tickers found while searching for 'Apple':\");
148 for item in resp.quotes
149 {
150 println!(\"{}\", item.symbol)
151 }
152}
153```
154"
155)]
156
157#[cfg(feature = "debug")]
158extern crate serde_json_path_to_error as serde_json;
159
160use std::sync::Arc;
161use std::time::Duration;
162use time::OffsetDateTime;
163
164#[cfg(feature = "blocking")]
165use reqwest::blocking::{Client, ClientBuilder};
166use reqwest::Proxy;
167#[cfg(not(feature = "blocking"))]
168use reqwest::{Client, ClientBuilder};
169
170pub use quotes::decimal::Decimal;
172pub use time;
173
174mod quotes;
175mod search_result;
176mod yahoo_error;
177pub use quotes::{
178 AdjClose, AssetProfile, CapitalGain, CurrentTradingPeriod, DefaultKeyStatistics, Dividend,
179 ExtendedQuoteSummary, FinancialData, FinancialEvent, PeriodInfo, Quote, QuoteBlock, QuoteList,
180 QuoteType, Split, SummaryDetail, TradingPeriods, YChart, YMetaData, YQuoteBlock, YQuoteSummary,
181 YResponse, YSummaryData,
182};
183pub use search_result::{
184 YNewsItem, YOptionChain, YOptionChainData, YOptionChainResult, YOptionContract, YOptionDetails,
185 YQuote, YQuoteItem, YQuoteItemOpt, YSearchResult, YSearchResultOpt,
186};
187pub use yahoo_error::YahooError;
188
189const YCHART_URL: &str = "https://query1.finance.yahoo.com/v8/finance/chart";
190const YSEARCH_URL: &str = "https://query2.finance.yahoo.com/v1/finance/search";
191const Y_GET_COOKIE_URL: &str = "https://fc.yahoo.com";
192const Y_GET_CRUMB_URL: &str = "https://query1.finance.yahoo.com/v1/test/getcrumb";
193const Y_EARNINGS_URL: &str = "https://query1.finance.yahoo.com/v1/finance/visualization";
194
195const Y_COOKIE_REQUEST_HEADER: &str = "set-cookie";
197const USER_AGENT: &str = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36";
198
199macro_rules! YCHART_PERIOD_QUERY {
201 () => {
202 "{url}/{symbol}?symbol={symbol}&period1={start}&period2={end}&interval={interval}&events=div|split|capitalGains"
203 };
204}
205macro_rules! YCHART_PERIOD_QUERY_PRE_POST {
206 () => {
207 "{url}/{symbol}?symbol={symbol}&period1={start}&period2={end}&interval={interval}&events=div|split|capitalGains&includePrePost={prepost}"
208 };
209}
210macro_rules! YCHART_RANGE_QUERY {
211 () => {
212 "{url}/{symbol}?symbol={symbol}&interval={interval}&range={range}&events=div|split|capitalGains"
213 };
214}
215macro_rules! YCHART_PERIOD_INTERVAL_QUERY {
216 () => {
217 "{url}/{symbol}?symbol={symbol}&range={range}&interval={interval}&includePrePost={prepost}"
218 };
219}
220macro_rules! YTICKER_QUERY {
221 () => {
222 "{url}?q={name}"
223 };
224}
225macro_rules! YQUOTE_SUMMARY_QUERY {
226 () => {
227 "https://query2.finance.yahoo.com/v10/finance/quoteSummary/{symbol}?modules=financialData,quoteType,defaultKeyStatistics,assetProfile,summaryDetail&corsDomain=finance.yahoo.com&formatted=false&symbol={symbol}&crumb={crumb}"
228 }
229}
230macro_rules! YEARNINGS_QUERY {
231 () => {
232 "{url}?lang={lang}®ion={region}&crumb={crumb}"
233 };
234}
235
236pub struct YahooConnector {
238 client: Client,
239 url: &'static str,
240 search_url: &'static str,
241 timeout: Option<Duration>,
242 user_agent: Option<String>,
243 proxy: Option<Proxy>,
244 cookie: Option<String>,
245 crumb: Option<String>,
246}
247
248#[derive(Default)]
249pub struct YahooConnectorBuilder {
250 inner: ClientBuilder,
251 timeout: Option<Duration>,
252 user_agent: Option<String>,
253 proxy: Option<Proxy>,
254}
255
256impl YahooConnector {
257 pub fn new() -> Result<YahooConnector, YahooError> {
259 Self::builder().build()
260 }
261
262 pub fn builder() -> YahooConnectorBuilder {
263 YahooConnectorBuilder {
264 inner: Client::builder(),
265 user_agent: Some(USER_AGENT.to_string()),
266 ..Default::default()
267 }
268 }
269
270 fn default_internal() -> Self {
274 YahooConnector {
275 client: Client::default(),
276 url: YCHART_URL,
277 search_url: YSEARCH_URL,
278 timeout: None,
279 user_agent: Some(USER_AGENT.to_string()),
280 proxy: None,
281 cookie: None,
282 crumb: None,
283 }
284 }
285}
286
287impl YahooConnectorBuilder {
288 pub fn new() -> Self {
289 YahooConnector::builder()
290 }
291
292 pub fn timeout(mut self, timeout: Duration) -> Self {
293 self.timeout = Some(timeout);
294 self
295 }
296
297 pub fn user_agent(mut self, user_agent: &str) -> Self {
298 self.user_agent = Some(user_agent.to_string());
299 self
300 }
301
302 pub fn proxy(mut self, proxy: Proxy) -> Self {
303 self.proxy = Some(proxy);
304 self
305 }
306
307 pub fn build(mut self) -> Result<YahooConnector, YahooError> {
308 if let Some(timeout) = &self.timeout {
309 self.inner = self.inner.timeout(*timeout);
310 }
311 if let Some(user_agent) = &self.user_agent {
312 self.inner = self.inner.user_agent(user_agent.clone());
313 }
314 if let Some(proxy) = &self.proxy {
315 self.inner = self.inner.proxy(proxy.clone());
316 }
317
318 Ok(YahooConnector {
319 client: self.inner.use_rustls_tls().build()?,
320 timeout: self.timeout,
321 user_agent: self.user_agent,
322 proxy: self.proxy,
323 ..YahooConnector::default_internal()
324 })
325 }
326
327 pub fn build_with_client(client: Client) -> Result<YahooConnector, YahooError> {
328 Ok(YahooConnector {
329 client,
330 ..YahooConnector::default_internal()
331 })
332 }
333}
334
335#[cfg(not(feature = "blocking"))]
336pub mod async_impl;
337
338#[cfg(feature = "blocking")]
339pub mod blocking_impl;