jquants_api_client/api/
morning_session_stock_prices.rs

1//! Morning Session Stock Prices API.
2
3use serde::{Deserialize, Serialize};
4
5use super::{
6    shared::traits::{
7        builder::JQuantsBuilder,
8        pagination::{HasPaginationKey, MergePage, Paginatable},
9    },
10    JQuantsApiClient, JQuantsPlanClient,
11};
12
13/// Builder for Morning Session Stock Prices API.
14///
15/// See: [API Reference](https://jpx.gitbook.io/j-quants-en/api-reference/prices_am)
16#[derive(Clone, Serialize)]
17pub struct MorningSessionStockPricesApiBuilder {
18    #[serde(skip)]
19    client: JQuantsApiClient,
20
21    /// Issue code (e.g. 27800 or 2780)
22    #[serde(skip_serializing_if = "Option::is_none")]
23    code: Option<String>,
24
25    /// Pagination key.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pagination_key: Option<String>,
28}
29
30impl JQuantsBuilder<MorningSessionStockPricesResponse> for MorningSessionStockPricesApiBuilder {
31    async fn send(self) -> Result<MorningSessionStockPricesResponse, crate::JQuantsError> {
32        self.send_ref().await
33    }
34
35    async fn send_ref(&self) -> Result<MorningSessionStockPricesResponse, crate::JQuantsError> {
36        self.client.inner.get("prices/prices_am", &self).await
37    }
38}
39
40impl Paginatable<MorningSessionStockPricesResponse> for MorningSessionStockPricesApiBuilder {
41    fn pagination_key(mut self, pagination_key: impl Into<String>) -> Self {
42        self.pagination_key = Some(pagination_key.into());
43        self
44    }
45}
46
47impl MorningSessionStockPricesApiBuilder {
48    pub(crate) fn new(client: JQuantsApiClient) -> Self {
49        Self {
50            client,
51            code: None,
52            pagination_key: None,
53        }
54    }
55
56    /// Issue code (e.g. 27800 or 2780)
57    pub fn code(mut self, code: impl Into<String>) -> Self {
58        self.code = Some(code.into());
59        self
60    }
61}
62
63/// Morning Session Stock Prices API.
64pub trait MorningSessionStockPricesApi: JQuantsPlanClient {
65    /// Get api builder for morning session stock prices.
66    fn morning_session_stock_prices(&self) -> MorningSessionStockPricesApiBuilder {
67        MorningSessionStockPricesApiBuilder::new(self.get_api_client().clone())
68    }
69}
70
71/// Morning Session Stock Prices response.
72///
73/// See: [API Reference](https://jpx.gitbook.io/j-quants-en/api-reference/prices_am)
74#[derive(Debug, Clone, PartialEq, Deserialize)]
75pub struct MorningSessionStockPricesResponse {
76    /// List of morning session stock prices.
77    prices_am: Vec<MorningStockPriceItem>,
78    /// Pagination key for fetching next set of data.
79    pagination_key: Option<String>,
80}
81impl HasPaginationKey for MorningSessionStockPricesResponse {
82    fn get_pagination_key(&self) -> Option<&str> {
83        self.pagination_key.as_deref()
84    }
85}
86impl MergePage for MorningSessionStockPricesResponse {
87    fn merge_page(
88        page: Result<Vec<Self>, crate::JQuantsError>,
89    ) -> Result<Self, crate::JQuantsError> {
90        let mut page = page?;
91        let mut merged = page.pop().unwrap();
92        for p in page {
93            merged.prices_am.extend(p.prices_am);
94        }
95        merged.pagination_key = None;
96
97        Ok(merged)
98    }
99}
100
101/// Morning session stock price.
102#[derive(Debug, Clone, PartialEq, Deserialize)]
103pub struct MorningStockPriceItem {
104    /// Date
105    #[serde(rename = "Date")]
106    pub date: String,
107    /// Issue code
108    #[serde(rename = "Code")]
109    pub code: String,
110    /// Open price of the morning session
111    #[serde(rename = "MorningOpen")]
112    pub morning_open: Option<f64>,
113    /// High price of the morning session
114    #[serde(rename = "MorningHigh")]
115    pub morning_high: Option<f64>,
116    /// Low price of the morning session
117    #[serde(rename = "MorningLow")]
118    pub morning_low: Option<f64>,
119    /// Close price of the morning session
120    #[serde(rename = "MorningClose")]
121    pub morning_close: Option<f64>,
122    /// Trading volume of the morning session
123    #[serde(rename = "MorningVolume")]
124    pub morning_volume: Option<f64>,
125    /// Trading value of the morning session
126    #[serde(rename = "MorningTurnoverValue")]
127    pub morning_turnover_value: Option<f64>,
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn test_deserialize_morning_session_stock_prices_response() {
136        let json = r#"
137            {
138                "prices_am": [
139                    {
140                        "Date": "2023-03-20",
141                        "Code": "39400",
142                        "MorningOpen": 232.0,
143                        "MorningHigh": 244.0,
144                        "MorningLow": 232.0,
145                        "MorningClose": 240.0,
146                        "MorningVolume": 52600.0,
147                        "MorningTurnoverValue": 12518800.0
148                    }
149                ],
150                "pagination_key": "value1.value2."
151            }
152        "#;
153        let response: MorningSessionStockPricesResponse = serde_json::from_str(json).unwrap();
154        let expected_response: MorningSessionStockPricesResponse =
155            MorningSessionStockPricesResponse {
156                prices_am: vec![MorningStockPriceItem {
157                    date: "2023-03-20".to_string(),
158                    code: "39400".to_string(),
159                    morning_open: Some(232.0),
160                    morning_high: Some(244.0),
161                    morning_low: Some(232.0),
162                    morning_close: Some(240.0),
163                    morning_volume: Some(52600.0),
164                    morning_turnover_value: Some(12518800.0),
165                }],
166                pagination_key: Some("value1.value2.".to_string()),
167            };
168
169        pretty_assertions::assert_eq!(response, expected_response);
170    }
171
172    #[test]
173    fn test_deserialize_morning_session_stock_prices_response_no_data() {
174        let json = r#"
175            {
176                "prices_am": [
177                    {
178                        "Date": "2023-03-20",
179                        "Code": "39400",
180                        "MorningOpen": null,
181                        "MorningHigh": null,
182                        "MorningLow": null,
183                        "MorningClose": null,
184                        "MorningVolume": null,
185                        "MorningTurnoverValue": null
186                    }
187                ],
188                "pagination_key": "value1.value2."
189            }
190        "#;
191        let response: MorningSessionStockPricesResponse = serde_json::from_str(json).unwrap();
192        let expected_response: MorningSessionStockPricesResponse =
193            MorningSessionStockPricesResponse {
194                prices_am: vec![MorningStockPriceItem {
195                    date: "2023-03-20".to_string(),
196                    code: "39400".to_string(),
197                    morning_open: None,
198                    morning_high: None,
199                    morning_low: None,
200                    morning_close: None,
201                    morning_volume: None,
202                    morning_turnover_value: None,
203                }],
204                pagination_key: Some("value1.value2.".to_string()),
205            };
206
207        pretty_assertions::assert_eq!(response, expected_response);
208    }
209}