finance_query/adapters/polygon/indices/
snapshots.rs1use serde::{Deserialize, Serialize};
4
5use crate::error::{FinanceError, Result};
6
7use super::super::build_client;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11#[non_exhaustive]
12pub struct IndexSession {
13 pub change: Option<f64>,
15 pub change_percent: Option<f64>,
17 pub close: Option<f64>,
19 pub high: Option<f64>,
21 pub low: Option<f64>,
23 pub open: Option<f64>,
25 pub previous_close: Option<f64>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31#[non_exhaustive]
32pub struct IndexSnapshot {
33 pub value: Option<f64>,
35 pub name: Option<String>,
37 #[serde(rename = "type")]
39 pub index_type: Option<String>,
40 pub ticker: Option<String>,
42 pub market_status: Option<String>,
44 pub session: Option<IndexSession>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50#[non_exhaustive]
51pub struct IndexSnapshotResponse {
52 pub status: Option<String>,
54 pub request_id: Option<String>,
56 pub results: Option<Vec<IndexSnapshot>>,
58}
59
60pub async fn index_snapshot(ticker: &str) -> Result<IndexSnapshotResponse> {
64 let client = build_client()?;
65 let path = "/v3/snapshot/indices";
66 let params = [("ticker.any_of", ticker)];
67 let json = client.get_raw(path, ¶ms).await?;
68 serde_json::from_value(json).map_err(|e| FinanceError::ResponseStructureError {
69 field: "index_snapshot".to_string(),
70 context: format!("Failed to parse index snapshot response: {e}"),
71 })
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[tokio::test]
79 async fn test_index_snapshot_mock() {
80 let mut server = mockito::Server::new_async().await;
81 let _mock = server
82 .mock("GET", "/v3/snapshot/indices")
83 .match_query(mockito::Matcher::AllOf(vec![
84 mockito::Matcher::UrlEncoded("apiKey".into(), "test-key".into()),
85 mockito::Matcher::UrlEncoded("ticker.any_of".into(), "I:SPX".into()),
86 ]))
87 .with_status(200)
88 .with_header("content-type", "application/json")
89 .with_body(
90 serde_json::json!({
91 "status": "OK",
92 "request_id": "abc123",
93 "results": [
94 {
95 "value": 4790.0,
96 "name": "S&P 500",
97 "type": "indices",
98 "ticker": "I:SPX",
99 "market_status": "open",
100 "session": {
101 "change": 20.0,
102 "change_percent": 0.42,
103 "close": 4790.0,
104 "high": 4800.0,
105 "low": 4760.0,
106 "open": 4770.0,
107 "previous_close": 4770.0
108 }
109 }
110 ]
111 })
112 .to_string(),
113 )
114 .create_async()
115 .await;
116
117 let client = super::super::super::build_test_client(&server.url()).unwrap();
118 let json = client
119 .get_raw("/v3/snapshot/indices", &[("ticker.any_of", "I:SPX")])
120 .await
121 .unwrap();
122
123 let resp: IndexSnapshotResponse = serde_json::from_value(json).unwrap();
124 assert_eq!(resp.status.as_deref(), Some("OK"));
125 let results = resp.results.unwrap();
126 assert_eq!(results.len(), 1);
127 assert_eq!(results[0].ticker.as_deref(), Some("I:SPX"));
128 assert!((results[0].value.unwrap() - 4790.0).abs() < 0.01);
129 let session = results[0].session.as_ref().unwrap();
130 assert!((session.change.unwrap() - 20.0).abs() < 0.01);
131 }
132}