1use std::{fmt, marker::PhantomData};
3
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5
6use crate::PriceLimit;
7
8use super::{
9 shared::traits::{
10 builder::JQuantsBuilder,
11 pagination::{HasPaginationKey, MergePage, Paginatable},
12 },
13 JQuantsApiClient, JQuantsPlanClient,
14};
15
16#[derive(Clone, Serialize)]
18pub struct DailyStockPricesBuilder<R: DeserializeOwned + fmt::Debug + Clone> {
19 #[serde(skip)]
20 client: JQuantsApiClient,
21 #[serde(skip)]
22 phantom: PhantomData<R>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
29 code: Option<String>,
30 #[serde(skip_serializing_if = "Option::is_none")]
32 from: Option<String>,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 to: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
40 date: Option<String>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pagination_key: Option<String>,
45}
46
47impl<R: DeserializeOwned + fmt::Debug + Clone> JQuantsBuilder<R> for DailyStockPricesBuilder<R> {
48 async fn send(self) -> Result<R, crate::JQuantsError> {
49 self.send_ref().await
50 }
51
52 async fn send_ref(&self) -> Result<R, crate::JQuantsError> {
53 self.client.inner.get("prices/daily_quotes", self).await
54 }
55}
56
57impl<R: DeserializeOwned + fmt::Debug + Clone + HasPaginationKey + MergePage> Paginatable<R>
58 for DailyStockPricesBuilder<R>
59{
60 fn pagination_key(mut self, pagination_key: impl Into<String>) -> Self {
61 self.pagination_key = Some(pagination_key.into());
62 self
63 }
64}
65
66impl<R: DeserializeOwned + fmt::Debug + Clone> DailyStockPricesBuilder<R> {
67 pub(crate) fn new(client: JQuantsApiClient) -> Self {
69 Self {
70 client,
71 phantom: PhantomData,
72 code: None,
73 from: None,
74 to: None,
75 date: None,
76 pagination_key: None,
77 }
78 }
79
80 pub fn code(mut self, code: impl Into<String>) -> Self {
82 self.code = Some(code.into());
83 self
84 }
85
86 pub fn from(mut self, from: impl Into<String>) -> Self {
88 self.from = Some(from.into());
89 self
90 }
91
92 pub fn to(mut self, to: impl Into<String>) -> Self {
94 self.to = Some(to.into());
95 self
96 }
97
98 pub fn date(mut self, date: impl Into<String>) -> Self {
100 self.date = Some(date.into());
101 self
102 }
103}
104
105pub trait DailyStockPricesApi: JQuantsPlanClient {
107 type Response: DeserializeOwned + fmt::Debug + Clone;
109
110 fn get_daily_stock_prices(&self) -> DailyStockPricesBuilder<Self::Response> {
114 DailyStockPricesBuilder::new(self.get_api_client().clone())
115 }
116}
117
118pub type DailyStockPricesFreePlanResponse = DailyStockPricesStandardPlanResponse;
122
123pub type DailyStockPricesLightPlanResponse = DailyStockPricesStandardPlanResponse;
127
128#[derive(Debug, Clone, PartialEq, Deserialize)]
132pub struct DailyStockPricesStandardPlanResponse {
133 pub daily_quotes: Vec<DailyQuoteStandardPlanItem>,
135
136 pub pagination_key: Option<String>,
138}
139impl HasPaginationKey for DailyStockPricesStandardPlanResponse {
140 fn get_pagination_key(&self) -> Option<&str> {
141 self.pagination_key.as_deref()
142 }
143}
144impl MergePage for DailyStockPricesStandardPlanResponse {
145 fn merge_page(
146 page: Result<Vec<Self>, crate::JQuantsError>,
147 ) -> Result<Self, crate::JQuantsError> {
148 let mut page = page?;
149 let mut merged = page.pop().unwrap();
150 for p in page {
151 merged.daily_quotes.extend(p.daily_quotes);
152 }
153 merged.pagination_key = None;
154
155 Ok(merged)
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Deserialize)]
163pub struct DailyStockPricesPremiumPlanResponse {
164 pub daily_quotes: Vec<DailyQuotePremiumPlanItem>,
166
167 pub pagination_key: Option<String>,
169}
170impl HasPaginationKey for DailyStockPricesPremiumPlanResponse {
171 fn get_pagination_key(&self) -> Option<&str> {
172 self.pagination_key.as_deref()
173 }
174}
175impl MergePage for DailyStockPricesPremiumPlanResponse {
176 fn merge_page(
177 page: Result<Vec<Self>, crate::JQuantsError>,
178 ) -> Result<Self, crate::JQuantsError> {
179 let mut page = page?;
180 let mut merged = page.pop().unwrap();
181 for p in page {
182 merged.daily_quotes.extend(p.daily_quotes);
183 }
184 merged.pagination_key = None;
185
186 Ok(merged)
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Deserialize)]
192pub struct DailyQuoteStandardPlanItem {
193 #[serde(flatten)]
195 pub common: DailyQuoteCommonItem,
196}
197
198#[derive(Debug, Clone, PartialEq, Deserialize)]
200pub struct DailyQuotePremiumPlanItem {
201 #[serde(flatten)]
203 pub common: DailyQuoteCommonItem,
204
205 #[serde(rename = "MorningOpen")]
207 pub morning_open: Option<f64>,
208
209 #[serde(rename = "MorningHigh")]
211 pub morning_high: Option<f64>,
212
213 #[serde(rename = "MorningLow")]
215 pub morning_low: Option<f64>,
216
217 #[serde(rename = "MorningClose")]
219 pub morning_close: Option<f64>,
220
221 #[serde(rename = "MorningUpperLimit")]
223 pub morning_upper_limit: PriceLimit,
224
225 #[serde(rename = "MorningLowerLimit")]
227 pub morning_lower_limit: PriceLimit,
228
229 #[serde(rename = "MorningVolume")]
231 pub morning_volume: Option<f64>,
232
233 #[serde(rename = "MorningTurnoverValue")]
235 pub morning_turnover_value: Option<f64>,
236
237 #[serde(rename = "MorningAdjustmentOpen")]
239 pub morning_adjustment_open: Option<f64>,
240
241 #[serde(rename = "MorningAdjustmentHigh")]
243 pub morning_adjustment_high: Option<f64>,
244
245 #[serde(rename = "MorningAdjustmentLow")]
247 pub morning_adjustment_low: Option<f64>,
248
249 #[serde(rename = "MorningAdjustmentClose")]
251 pub morning_adjustment_close: Option<f64>,
252
253 #[serde(rename = "MorningAdjustmentVolume")]
255 pub morning_adjustment_volume: Option<f64>,
256
257 #[serde(rename = "AfternoonOpen")]
259 pub afternoon_open: Option<f64>,
260
261 #[serde(rename = "AfternoonHigh")]
263 pub afternoon_high: Option<f64>,
264
265 #[serde(rename = "AfternoonLow")]
267 pub afternoon_low: Option<f64>,
268
269 #[serde(rename = "AfternoonClose")]
271 pub afternoon_close: Option<f64>,
272
273 #[serde(rename = "AfternoonUpperLimit")]
275 pub afternoon_upper_limit: PriceLimit,
276
277 #[serde(rename = "AfternoonLowerLimit")]
279 pub afternoon_lower_limit: PriceLimit,
280
281 #[serde(rename = "AfternoonVolume")]
283 pub afternoon_volume: Option<f64>,
284
285 #[serde(rename = "AfternoonTurnoverValue")]
287 pub afternoon_turnover_value: Option<f64>,
288
289 #[serde(rename = "AfternoonAdjustmentOpen")]
291 pub afternoon_adjustment_open: Option<f64>,
292
293 #[serde(rename = "AfternoonAdjustmentHigh")]
295 pub afternoon_adjustment_high: Option<f64>,
296
297 #[serde(rename = "AfternoonAdjustmentLow")]
299 pub afternoon_adjustment_low: Option<f64>,
300
301 #[serde(rename = "AfternoonAdjustmentClose")]
303 pub afternoon_adjustment_close: Option<f64>,
304
305 #[serde(rename = "AfternoonAdjustmentVolume")]
307 pub afternoon_adjustment_volume: Option<f64>,
308}
309
310#[derive(Debug, Clone, PartialEq, Deserialize)]
312pub struct DailyQuoteCommonItem {
313 #[serde(rename = "Date")]
315 pub date: String,
316
317 #[serde(rename = "Code")]
319 pub code: String,
320
321 #[serde(rename = "Open")]
323 pub open: Option<f64>,
324
325 #[serde(rename = "High")]
327 pub high: Option<f64>,
328
329 #[serde(rename = "Low")]
331 pub low: Option<f64>,
332
333 #[serde(rename = "Close")]
335 pub close: Option<f64>,
336
337 #[serde(rename = "UpperLimit")]
339 pub upper_limit: PriceLimit,
340
341 #[serde(rename = "LowerLimit")]
343 pub lower_limit: PriceLimit,
344
345 #[serde(rename = "Volume")]
347 pub volume: Option<f64>,
348
349 #[serde(rename = "TurnoverValue")]
351 pub turnover_value: Option<f64>,
352
353 #[serde(rename = "AdjustmentFactor")]
355 pub adjustment_factor: f64,
356
357 #[serde(rename = "AdjustmentOpen")]
359 pub adjustment_open: Option<f64>,
360
361 #[serde(rename = "AdjustmentHigh")]
363 pub adjustment_high: Option<f64>,
364
365 #[serde(rename = "AdjustmentLow")]
367 pub adjustment_low: Option<f64>,
368
369 #[serde(rename = "AdjustmentClose")]
371 pub adjustment_close: Option<f64>,
372
373 #[serde(rename = "AdjustmentVolume")]
375 pub adjustment_volume: Option<f64>,
376}
377
378#[cfg(test)]
379mod tests {
380 use crate::{
381 api::daily_stock_prices::{
382 DailyQuoteCommonItem, DailyQuotePremiumPlanItem, DailyQuoteStandardPlanItem,
383 DailyStockPricesPremiumPlanResponse, DailyStockPricesStandardPlanResponse,
384 },
385 PriceLimit,
386 };
387
388 #[test]
389 fn test_deserialize_daily_stock_prices_standard_plan_response() {
390 let json = r#"
391 {
392 "daily_quotes": [
393 {
394 "Date": "2023-03-24",
395 "Code": "86970",
396 "Open": 2047.0,
397 "High": 2069.0,
398 "Low": 2035.0,
399 "Close": 2045.0,
400 "UpperLimit": "0",
401 "LowerLimit": "0",
402 "Volume": 2202500.0,
403 "TurnoverValue": 4507051850.0,
404 "AdjustmentFactor": 1.0,
405 "AdjustmentOpen": 2047.0,
406 "AdjustmentHigh": 2069.0,
407 "AdjustmentLow": 2035.0,
408 "AdjustmentClose": 2045.0,
409 "AdjustmentVolume": 2202500.0
410 }
411 ],
412 "pagination_key": "value1.value2."
413 }
414 "#;
415
416 let response: DailyStockPricesStandardPlanResponse = serde_json::from_str(json).unwrap();
417 let expected_response = DailyStockPricesStandardPlanResponse {
418 daily_quotes: vec![DailyQuoteStandardPlanItem {
419 common: DailyQuoteCommonItem {
420 date: "2023-03-24".to_string(),
421 code: "86970".to_string(),
422 open: Some(2047.0),
423 high: Some(2069.0),
424 low: Some(2035.0),
425 close: Some(2045.0),
426 upper_limit: PriceLimit::NotHit,
427 lower_limit: PriceLimit::NotHit,
428 volume: Some(2202500.0),
429 turnover_value: Some(4507051850.0),
430 adjustment_factor: 1.0,
431 adjustment_open: Some(2047.0),
432 adjustment_high: Some(2069.0),
433 adjustment_low: Some(2035.0),
434 adjustment_close: Some(2045.0),
435 adjustment_volume: Some(2202500.0),
436 },
437 }],
438 pagination_key: Some("value1.value2.".to_string()),
439 };
440
441 pretty_assertions::assert_eq!(response, expected_response);
442 }
443
444 #[test]
445 fn test_deserialize_daily_stock_prices_standard_plan_response_no_pagination_key() {
446 let json = r#"
447 {
448 "daily_quotes": [
449 {
450 "Date": "2023-03-24",
451 "Code": "86970",
452 "Open": 2047.0,
453 "High": 2069.0,
454 "Low": 2035.0,
455 "Close": 2045.0,
456 "UpperLimit": "0",
457 "LowerLimit": "0",
458 "Volume": 2202500.0,
459 "TurnoverValue": 4507051850.0,
460 "AdjustmentFactor": 1.0,
461 "AdjustmentOpen": 2047.0,
462 "AdjustmentHigh": 2069.0,
463 "AdjustmentLow": 2035.0,
464 "AdjustmentClose": 2045.0,
465 "AdjustmentVolume": 2202500.0
466 }
467 ]
468 }
469 "#;
470
471 let response: DailyStockPricesStandardPlanResponse = serde_json::from_str(json).unwrap();
472 let expected_response = DailyStockPricesStandardPlanResponse {
473 daily_quotes: vec![DailyQuoteStandardPlanItem {
474 common: DailyQuoteCommonItem {
475 date: "2023-03-24".to_string(),
476 code: "86970".to_string(),
477 open: Some(2047.0),
478 high: Some(2069.0),
479 low: Some(2035.0),
480 close: Some(2045.0),
481 upper_limit: PriceLimit::NotHit,
482 lower_limit: PriceLimit::NotHit,
483 volume: Some(2202500.0),
484 turnover_value: Some(4507051850.0),
485 adjustment_factor: 1.0,
486 adjustment_open: Some(2047.0),
487 adjustment_high: Some(2069.0),
488 adjustment_low: Some(2035.0),
489 adjustment_close: Some(2045.0),
490 adjustment_volume: Some(2202500.0),
491 },
492 }],
493 pagination_key: None,
494 };
495
496 pretty_assertions::assert_eq!(response, expected_response);
497 }
498
499 #[test]
500 fn test_deserialize_daily_stock_prices_premium_plan_response() {
501 let json = r#"
502 {
503 "daily_quotes": [
504 {
505 "Date": "2023-03-24",
506 "Code": "86970",
507 "Open": 2047.0,
508 "High": 2069.0,
509 "Low": 2035.0,
510 "Close": 2045.0,
511 "UpperLimit": "1",
512 "LowerLimit": "1",
513 "Volume": 2202500.0,
514 "TurnoverValue": 4507051850.0,
515 "AdjustmentFactor": 1.0,
516 "AdjustmentOpen": 2047.0,
517 "AdjustmentHigh": 2069.0,
518 "AdjustmentLow": 2035.0,
519 "AdjustmentClose": 2045.0,
520 "AdjustmentVolume": 2202500.0,
521 "MorningOpen": 2047.0,
522 "MorningHigh": 2069.0,
523 "MorningLow": 2040.0,
524 "MorningClose": 2045.5,
525 "MorningUpperLimit": "1",
526 "MorningLowerLimit": "1",
527 "MorningVolume": 1121200.0,
528 "MorningTurnoverValue": 2297525850.0,
529 "MorningAdjustmentOpen": 2047.0,
530 "MorningAdjustmentHigh": 2069.0,
531 "MorningAdjustmentLow": 2040.0,
532 "MorningAdjustmentClose": 2045.5,
533 "MorningAdjustmentVolume": 1121200.0,
534 "AfternoonOpen": 2047.0,
535 "AfternoonHigh": 2047.0,
536 "AfternoonLow": 2035.0,
537 "AfternoonClose": 2045.0,
538 "AfternoonUpperLimit": "1",
539 "AfternoonLowerLimit": "1",
540 "AfternoonVolume": 1081300.0,
541 "AfternoonTurnoverValue": 2209526000.0,
542 "AfternoonAdjustmentOpen": 2047.0,
543 "AfternoonAdjustmentHigh": 2047.0,
544 "AfternoonAdjustmentLow": 2035.0,
545 "AfternoonAdjustmentClose": 2045.0,
546 "AfternoonAdjustmentVolume": 1081300.0
547 }
548 ],
549 "pagination_key": "value1.value2."
550 }
551 "#;
552
553 let response: DailyStockPricesPremiumPlanResponse = serde_json::from_str(json).unwrap();
554 let expected_response = DailyStockPricesPremiumPlanResponse {
555 daily_quotes: vec![DailyQuotePremiumPlanItem {
556 common: DailyQuoteCommonItem {
557 date: "2023-03-24".to_string(),
558 code: "86970".to_string(),
559 open: Some(2047.0),
560 high: Some(2069.0),
561 low: Some(2035.0),
562 close: Some(2045.0),
563 upper_limit: PriceLimit::Hit,
564 lower_limit: PriceLimit::Hit,
565 volume: Some(2202500.0),
566 turnover_value: Some(4507051850.0),
567 adjustment_factor: 1.0,
568 adjustment_open: Some(2047.0),
569 adjustment_high: Some(2069.0),
570 adjustment_low: Some(2035.0),
571 adjustment_close: Some(2045.0),
572 adjustment_volume: Some(2202500.0),
573 },
574 morning_open: Some(2047.0),
575 morning_high: Some(2069.0),
576 morning_low: Some(2040.0),
577 morning_close: Some(2045.5),
578 morning_upper_limit: PriceLimit::Hit,
579 morning_lower_limit: PriceLimit::Hit,
580 morning_volume: Some(1121200.0),
581 morning_turnover_value: Some(2297525850.0),
582 morning_adjustment_open: Some(2047.0),
583 morning_adjustment_high: Some(2069.0),
584 morning_adjustment_low: Some(2040.0),
585 morning_adjustment_close: Some(2045.5),
586 morning_adjustment_volume: Some(1121200.0),
587 afternoon_open: Some(2047.0),
588 afternoon_high: Some(2047.0),
589 afternoon_low: Some(2035.0),
590 afternoon_close: Some(2045.0),
591 afternoon_upper_limit: PriceLimit::Hit,
592 afternoon_lower_limit: PriceLimit::Hit,
593 afternoon_volume: Some(1081300.0),
594 afternoon_turnover_value: Some(2209526000.0),
595 afternoon_adjustment_open: Some(2047.0),
596 afternoon_adjustment_high: Some(2047.0),
597 afternoon_adjustment_low: Some(2035.0),
598 afternoon_adjustment_close: Some(2045.0),
599 afternoon_adjustment_volume: Some(1081300.0),
600 }],
601 pagination_key: Some("value1.value2.".to_string()),
602 };
603
604 pretty_assertions::assert_eq!(response, expected_response);
605 }
606
607 #[test]
608 fn test_deserialize_daily_stock_prices_premium_plan_response_no_data() {
609 let json = r#"
610 {
611 "daily_quotes": [
612 {
613 "Date": "2023-03-24",
614 "Code": "86970",
615 "Open": null,
616 "High": null,
617 "Low": null,
618 "Close": null,
619 "UpperLimit": "0",
620 "LowerLimit": "0",
621 "Volume": null,
622 "TurnoverValue": null,
623 "AdjustmentFactor": 1.0,
624 "AdjustmentOpen": null,
625 "AdjustmentHigh": null,
626 "AdjustmentLow": null,
627 "AdjustmentClose": null,
628 "AdjustmentVolume": null,
629 "MorningOpen": null,
630 "MorningHigh": null,
631 "MorningLow": null,
632 "MorningClose": null,
633 "MorningUpperLimit": "0",
634 "MorningLowerLimit": "0",
635 "MorningVolume": null,
636 "MorningTurnoverValue": null,
637 "MorningAdjustmentOpen": null,
638 "MorningAdjustmentHigh": null,
639 "MorningAdjustmentLow": null,
640 "MorningAdjustmentClose": null,
641 "MorningAdjustmentVolume": null,
642 "AfternoonOpen": null,
643 "AfternoonHigh": null,
644 "AfternoonLow": null,
645 "AfternoonClose": null,
646 "AfternoonUpperLimit": "0",
647 "AfternoonLowerLimit": "0",
648 "AfternoonVolume": null,
649 "AfternoonTurnoverValue": null,
650 "AfternoonAdjustmentOpen": null,
651 "AfternoonAdjustmentHigh": null,
652 "AfternoonAdjustmentLow": null,
653 "AfternoonAdjustmentClose": null,
654 "AfternoonAdjustmentVolume": null
655 }
656 ],
657 "pagination_key": "value1.value2."
658 }
659 "#;
660
661 let response: DailyStockPricesPremiumPlanResponse = serde_json::from_str(json).unwrap();
662 let expected_response = DailyStockPricesPremiumPlanResponse {
663 daily_quotes: vec![DailyQuotePremiumPlanItem {
664 common: DailyQuoteCommonItem {
665 date: "2023-03-24".to_string(),
666 code: "86970".to_string(),
667 open: None,
668 high: None,
669 low: None,
670 close: None,
671 upper_limit: PriceLimit::NotHit,
672 lower_limit: PriceLimit::NotHit,
673 volume: None,
674 turnover_value: None,
675 adjustment_factor: 1.0,
676 adjustment_open: None,
677 adjustment_high: None,
678 adjustment_low: None,
679 adjustment_close: None,
680 adjustment_volume: None,
681 },
682 morning_open: None,
683 morning_high: None,
684 morning_low: None,
685 morning_close: None,
686 morning_upper_limit: PriceLimit::NotHit,
687 morning_lower_limit: PriceLimit::NotHit,
688 morning_volume: None,
689 morning_turnover_value: None,
690 morning_adjustment_open: None,
691 morning_adjustment_high: None,
692 morning_adjustment_low: None,
693 morning_adjustment_close: None,
694 morning_adjustment_volume: None,
695 afternoon_open: None,
696 afternoon_high: None,
697 afternoon_low: None,
698 afternoon_close: None,
699 afternoon_upper_limit: PriceLimit::NotHit,
700 afternoon_lower_limit: PriceLimit::NotHit,
701 afternoon_volume: None,
702 afternoon_turnover_value: None,
703 afternoon_adjustment_open: None,
704 afternoon_adjustment_high: None,
705 afternoon_adjustment_low: None,
706 afternoon_adjustment_close: None,
707 afternoon_adjustment_volume: None,
708 }],
709 pagination_key: Some("value1.value2.".to_string()),
710 };
711
712 pretty_assertions::assert_eq!(response, expected_response);
713 }
714
715 #[test]
716 fn test_deserialize_daily_stock_prices_premium_plan_response_no_pagination_key() {
717 let json = r#"
718 {
719 "daily_quotes": [
720 {
721 "Date": "2023-03-24",
722 "Code": "86970",
723 "Open": 2047.0,
724 "High": 2069.0,
725 "Low": 2035.0,
726 "Close": 2045.0,
727 "UpperLimit": "0",
728 "LowerLimit": "0",
729 "Volume": 2202500.0,
730 "TurnoverValue": 4507051850.0,
731 "AdjustmentFactor": 1.0,
732 "AdjustmentOpen": 2047.0,
733 "AdjustmentHigh": 2069.0,
734 "AdjustmentLow": 2035.0,
735 "AdjustmentClose": 2045.0,
736 "AdjustmentVolume": 2202500.0,
737 "MorningOpen": 2047.0,
738 "MorningHigh": 2069.0,
739 "MorningLow": 2040.0,
740 "MorningClose": 2045.5,
741 "MorningUpperLimit": "0",
742 "MorningLowerLimit": "0",
743 "MorningVolume": 1121200.0,
744 "MorningTurnoverValue": 2297525850.0,
745 "MorningAdjustmentOpen": 2047.0,
746 "MorningAdjustmentHigh": 2069.0,
747 "MorningAdjustmentLow": 2040.0,
748 "MorningAdjustmentClose": 2045.5,
749 "MorningAdjustmentVolume": 1121200.0,
750 "AfternoonOpen": 2047.0,
751 "AfternoonHigh": 2047.0,
752 "AfternoonLow": 2035.0,
753 "AfternoonClose": 2045.0,
754 "AfternoonUpperLimit": "0",
755 "AfternoonLowerLimit": "0",
756 "AfternoonVolume": 1081300.0,
757 "AfternoonTurnoverValue": 2209526000.0,
758 "AfternoonAdjustmentOpen": 2047.0,
759 "AfternoonAdjustmentHigh": 2047.0,
760 "AfternoonAdjustmentLow": 2035.0,
761 "AfternoonAdjustmentClose": 2045.0,
762 "AfternoonAdjustmentVolume": 1081300.0
763 }
764 ]
765 }
766 "#;
767
768 let response: DailyStockPricesPremiumPlanResponse = serde_json::from_str(json).unwrap();
769 let expected_response = DailyStockPricesPremiumPlanResponse {
770 daily_quotes: vec![DailyQuotePremiumPlanItem {
771 common: DailyQuoteCommonItem {
772 date: "2023-03-24".to_string(),
773 code: "86970".to_string(),
774 open: Some(2047.0),
775 high: Some(2069.0),
776 low: Some(2035.0),
777 close: Some(2045.0),
778 upper_limit: PriceLimit::NotHit,
779 lower_limit: PriceLimit::NotHit,
780 volume: Some(2202500.0),
781 turnover_value: Some(4507051850.0),
782 adjustment_factor: 1.0,
783 adjustment_open: Some(2047.0),
784 adjustment_high: Some(2069.0),
785 adjustment_low: Some(2035.0),
786 adjustment_close: Some(2045.0),
787 adjustment_volume: Some(2202500.0),
788 },
789 morning_open: Some(2047.0),
790 morning_high: Some(2069.0),
791 morning_low: Some(2040.0),
792 morning_close: Some(2045.5),
793 morning_upper_limit: PriceLimit::NotHit,
794 morning_lower_limit: PriceLimit::NotHit,
795 morning_volume: Some(1121200.0),
796 morning_turnover_value: Some(2297525850.0),
797 morning_adjustment_open: Some(2047.0),
798 morning_adjustment_high: Some(2069.0),
799 morning_adjustment_low: Some(2040.0),
800 morning_adjustment_close: Some(2045.5),
801 morning_adjustment_volume: Some(1121200.0),
802 afternoon_open: Some(2047.0),
803 afternoon_high: Some(2047.0),
804 afternoon_low: Some(2035.0),
805 afternoon_close: Some(2045.0),
806 afternoon_upper_limit: PriceLimit::NotHit,
807 afternoon_lower_limit: PriceLimit::NotHit,
808 afternoon_volume: Some(1081300.0),
809 afternoon_turnover_value: Some(2209526000.0),
810 afternoon_adjustment_open: Some(2047.0),
811 afternoon_adjustment_high: Some(2047.0),
812 afternoon_adjustment_low: Some(2035.0),
813 afternoon_adjustment_close: Some(2045.0),
814 afternoon_adjustment_volume: Some(1081300.0),
815 }],
816 pagination_key: None,
817 };
818
819 pretty_assertions::assert_eq!(response, expected_response);
820 }
821}