v_exchanges_methods/yahoo/
mod.rs1use eyre::{Result, bail, eyre};
2use jiff::Timestamp;
3use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
4use serde_json::Value;
5use v_utils::{NowThen, trades::Close};
6
7pub async fn vix(tf: YahooTimeframe, n: u8) -> Result<Vec<Close>> {
8 let mut headers = HeaderMap::default();
9 headers.insert(
10 USER_AGENT,
11 HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"),
12 );
13
14 let client = reqwest::Client::builder().default_headers(headers).build()?;
15
16 let url = "https://query1.finance.yahoo.com/v8/finance/chart/%5EVIX";
17 let params = [("interval", tf.to_string()), ("count", format!("{n}"))];
18
19 let response = client.get(url).query(¶ms).send().await?;
20
21 let data: Value = response.json().await?;
22 tracing::debug!("{}", data["chart"]["result"][0]);
23
24 let vix_values = {
25 let result = &data["chart"]["result"][0]; let closes = result["indicators"]["quote"][0]["close"]
28 .as_array()
29 .ok_or_else(|| eyre!("Could not extract VIX closes from Yahoo Finance response"))?;
30 let closes: Vec<f64> = closes
31 .iter()
32 .map(|v| v.as_f64().ok_or_else(|| eyre!("Could not extract VIX close from Yahoo Finance response")))
33 .collect::<Result<_, _>>()?;
34
35 let timestamps = result["timestamp"]
36 .as_array()
37 .ok_or_else(|| eyre!("Could not extract VIX timestamps from Yahoo Finance response"))?;
38 let timestamps: Vec<i64> = timestamps
39 .iter()
40 .map(|v| v.as_i64().ok_or_else(|| eyre!("Could not extract VIX timestamp from Yahoo Finance response")))
41 .collect::<Result<_, _>>()?;
42
43 closes
44 .into_iter()
45 .zip(timestamps.iter())
46 .map(|(c, t)| Close {
47 close: c,
48 timestamp: Timestamp::from_millisecond(*t).unwrap(),
49 })
50 .collect()
51 };
52
53 Ok(vix_values)
54}
55
56pub async fn vix_change(tf: YahooTimeframe, n: u8) -> Result<NowThen> {
57 let vix_history = vix(tf, n).await?;
58 if vix_history.len() < 2 {
59 bail!("Not enough VIX data to calculate change, need at least 2 points");
60 }
61 let now = vix_history.last().unwrap();
62 let then = vix_history.first().unwrap();
63 Ok(NowThen::builder()
64 .now(now.close)
65 .then(then.close)
66 .duration((now.timestamp - then.timestamp).try_into().unwrap())
67 .build())
68}
69
70crate::define_provider_timeframe!(YahooTimeframe, ["1m", "2m", "5m", "15m", "30m", "60m", "1h", "1d", "5d", "1wk", "1mo"]);