1use serde::{Deserialize, Serialize};
4
5use super::{
6 shared::traits::{
7 builder::JQuantsBuilder,
8 pagination::{HasPaginationKey, MergePage, Paginatable},
9 },
10 JQuantsApiClient, JQuantsPlanClient,
11};
12
13#[derive(Clone, Serialize)]
15pub struct BreakdownTradingDataBuilder {
16 #[serde(skip)]
17 client: JQuantsApiClient,
18
19 #[serde(skip_serializing_if = "Option::is_none")]
21 code: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 from: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 to: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 date: Option<String>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pagination_key: Option<String>,
35}
36
37impl JQuantsBuilder<BreakdownTradingDataResponse> for BreakdownTradingDataBuilder {
38 async fn send(self) -> Result<BreakdownTradingDataResponse, crate::JQuantsError> {
39 self.send_ref().await
40 }
41
42 async fn send_ref(&self) -> Result<BreakdownTradingDataResponse, crate::JQuantsError> {
43 self.client.inner.get("markets/breakdown", self).await
44 }
45}
46
47impl Paginatable<BreakdownTradingDataResponse> for BreakdownTradingDataBuilder {
48 fn pagination_key(mut self, pagination_key: impl Into<String>) -> Self {
49 self.pagination_key = Some(pagination_key.into());
50 self
51 }
52}
53
54impl BreakdownTradingDataBuilder {
55 pub(crate) fn new(client: JQuantsApiClient) -> Self {
57 Self {
58 client,
59 code: None,
60 from: None,
61 to: None,
62 date: None,
63 pagination_key: None,
64 }
65 }
66
67 pub fn code(mut self, code: impl Into<String>) -> Self {
69 self.code = Some(code.into());
70 self
71 }
72
73 pub fn from(mut self, from: impl Into<String>) -> Self {
75 self.from = Some(from.into());
76 self
77 }
78
79 pub fn to(mut self, to: impl Into<String>) -> Self {
81 self.to = Some(to.into());
82 self
83 }
84
85 pub fn date(mut self, date: impl Into<String>) -> Self {
87 self.date = Some(date.into());
88 self
89 }
90}
91
92pub trait BreakdownTradingDataApi: JQuantsPlanClient {
94 fn get_breakdown_trading_data(&self) -> BreakdownTradingDataBuilder {
98 BreakdownTradingDataBuilder::new(self.get_api_client().clone())
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Deserialize)]
106pub struct BreakdownTradingDataResponse {
107 pub breakdown: Vec<BreakdownTradingDataItem>,
109 pub pagination_key: Option<String>,
111}
112
113impl HasPaginationKey for BreakdownTradingDataResponse {
114 fn get_pagination_key(&self) -> Option<&str> {
115 self.pagination_key.as_deref()
116 }
117}
118
119impl MergePage for BreakdownTradingDataResponse {
120 fn merge_page(
121 page: Result<Vec<Self>, crate::JQuantsError>,
122 ) -> Result<Self, crate::JQuantsError> {
123 let mut page = page?;
124 let mut merged = page.pop().unwrap();
125 for p in page {
126 merged.breakdown.extend(p.breakdown);
127 }
128 merged.pagination_key = None;
129
130 Ok(merged)
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Deserialize)]
136pub struct BreakdownTradingDataItem {
137 #[serde(rename = "Date")]
139 pub date: String,
140
141 #[serde(rename = "Code")]
143 pub code: String,
144
145 #[serde(rename = "LongSellValue")]
147 pub long_sell_value: f64,
148
149 #[serde(rename = "ShortSellWithoutMarginValue")]
151 pub short_sell_without_margin_value: f64,
152
153 #[serde(rename = "MarginSellNewValue")]
155 pub margin_sell_new_value: f64,
156
157 #[serde(rename = "MarginSellCloseValue")]
159 pub margin_sell_close_value: f64,
160
161 #[serde(rename = "LongBuyValue")]
163 pub long_buy_value: f64,
164
165 #[serde(rename = "MarginBuyNewValue")]
167 pub margin_buy_new_value: f64,
168
169 #[serde(rename = "MarginBuyCloseValue")]
171 pub margin_buy_close_value: f64,
172
173 #[serde(rename = "LongSellVolume")]
175 pub long_sell_volume: f64,
176
177 #[serde(rename = "ShortSellWithoutMarginVolume")]
179 pub short_sell_without_margin_volume: f64,
180
181 #[serde(rename = "MarginSellNewVolume")]
183 pub margin_sell_new_volume: f64,
184
185 #[serde(rename = "MarginSellCloseVolume")]
187 pub margin_sell_close_volume: f64,
188
189 #[serde(rename = "LongBuyVolume")]
191 pub long_buy_volume: f64,
192
193 #[serde(rename = "MarginBuyNewVolume")]
195 pub margin_buy_new_volume: f64,
196
197 #[serde(rename = "MarginBuyCloseVolume")]
199 pub margin_buy_close_volume: f64,
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_deserialize_breakdown_trading_data_response() {
208 let json = r#"
209 {
210 "breakdown": [
211 {
212 "Date": "2015-04-01",
213 "Code": "13010",
214 "LongSellValue": 115164000.0,
215 "ShortSellWithoutMarginValue": 93561000.0,
216 "MarginSellNewValue": 6412000.0,
217 "MarginSellCloseValue": 23009000.0,
218 "LongBuyValue": 185114000.0,
219 "MarginBuyNewValue": 35568000.0,
220 "MarginBuyCloseValue": 17464000.0,
221 "LongSellVolume": 415000.0,
222 "ShortSellWithoutMarginVolume": 337000.0,
223 "MarginSellNewVolume": 23000.0,
224 "MarginSellCloseVolume": 83000.0,
225 "LongBuyVolume": 667000.0,
226 "MarginBuyNewVolume": 128000.0,
227 "MarginBuyCloseVolume": 63000.0
228 }
229 ],
230 "pagination_key": "value1.value2."
231 }
232 "#;
233
234 let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
235 let expected_response = BreakdownTradingDataResponse {
236 breakdown: vec![BreakdownTradingDataItem {
237 date: "2015-04-01".to_string(),
238 code: "13010".to_string(),
239 long_sell_value: 115164000.0,
240 short_sell_without_margin_value: 93561000.0,
241 margin_sell_new_value: 6412000.0,
242 margin_sell_close_value: 23009000.0,
243 long_buy_value: 185114000.0,
244 margin_buy_new_value: 35568000.0,
245 margin_buy_close_value: 17464000.0,
246 long_sell_volume: 415000.0,
247 short_sell_without_margin_volume: 337000.0,
248 margin_sell_new_volume: 23000.0,
249 margin_sell_close_volume: 83000.0,
250 long_buy_volume: 667000.0,
251 margin_buy_new_volume: 128000.0,
252 margin_buy_close_volume: 63000.0,
253 }],
254 pagination_key: Some("value1.value2.".to_string()),
255 };
256
257 pretty_assertions::assert_eq!(response, expected_response);
258 }
259
260 #[test]
261 fn test_deserialize_breakdown_trading_data_response_no_pagination_key() {
262 let json = r#"
263 {
264 "breakdown": [
265 {
266 "Date": "2015-04-01",
267 "Code": "13010",
268 "LongSellValue": 115164000.0,
269 "ShortSellWithoutMarginValue": 93561000.0,
270 "MarginSellNewValue": 6412000.0,
271 "MarginSellCloseValue": 23009000.0,
272 "LongBuyValue": 185114000.0,
273 "MarginBuyNewValue": 35568000.0,
274 "MarginBuyCloseValue": 17464000.0,
275 "LongSellVolume": 415000.0,
276 "ShortSellWithoutMarginVolume": 337000.0,
277 "MarginSellNewVolume": 23000.0,
278 "MarginSellCloseVolume": 83000.0,
279 "LongBuyVolume": 667000.0,
280 "MarginBuyNewVolume": 128000.0,
281 "MarginBuyCloseVolume": 63000.0
282 }
283 ]
284 }
285 "#;
286
287 let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
288 let expected_response = BreakdownTradingDataResponse {
289 breakdown: vec![BreakdownTradingDataItem {
290 date: "2015-04-01".to_string(),
291 code: "13010".to_string(),
292 long_sell_value: 115164000.0,
293 short_sell_without_margin_value: 93561000.0,
294 margin_sell_new_value: 6412000.0,
295 margin_sell_close_value: 23009000.0,
296 long_buy_value: 185114000.0,
297 margin_buy_new_value: 35568000.0,
298 margin_buy_close_value: 17464000.0,
299 long_sell_volume: 415000.0,
300 short_sell_without_margin_volume: 337000.0,
301 margin_sell_new_volume: 23000.0,
302 margin_sell_close_volume: 83000.0,
303 long_buy_volume: 667000.0,
304 margin_buy_new_volume: 128000.0,
305 margin_buy_close_volume: 63000.0,
306 }],
307 pagination_key: None,
308 };
309
310 pretty_assertions::assert_eq!(response, expected_response);
311 }
312
313 #[test]
314 fn test_deserialize_breakdown_trading_data_response_multiple_items() {
315 let json = r#"
316 {
317 "breakdown": [
318 {
319 "Date": "2015-03-25",
320 "Code": "13010",
321 "LongSellValue": 110000000.0,
322 "ShortSellWithoutMarginValue": 90000000.0,
323 "MarginSellNewValue": 6000000.0,
324 "MarginSellCloseValue": 22000000.0,
325 "LongBuyValue": 180000000.0,
326 "MarginBuyNewValue": 35000000.0,
327 "MarginBuyCloseValue": 17000000.0,
328 "LongSellVolume": 400000.0,
329 "ShortSellWithoutMarginVolume": 330000.0,
330 "MarginSellNewVolume": 22000.0,
331 "MarginSellCloseVolume": 82000.0,
332 "LongBuyVolume": 660000.0,
333 "MarginBuyNewVolume": 125000.0,
334 "MarginBuyCloseVolume": 62000.0
335 },
336 {
337 "Date": "2015-04-01",
338 "Code": "13010",
339 "LongSellValue": 115164000.0,
340 "ShortSellWithoutMarginValue": 93561000.0,
341 "MarginSellNewValue": 6412000.0,
342 "MarginSellCloseValue": 23009000.0,
343 "LongBuyValue": 185114000.0,
344 "MarginBuyNewValue": 35568000.0,
345 "MarginBuyCloseValue": 17464000.0,
346 "LongSellVolume": 415000.0,
347 "ShortSellWithoutMarginVolume": 337000.0,
348 "MarginSellNewVolume": 23000.0,
349 "MarginSellCloseVolume": 83000.0,
350 "LongBuyVolume": 667000.0,
351 "MarginBuyNewVolume": 128000.0,
352 "MarginBuyCloseVolume": 63000.0
353 }
354 ],
355 "pagination_key": "value1.value2."
356 }
357 "#;
358
359 let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
360 let expected_response = BreakdownTradingDataResponse {
361 breakdown: vec![
362 BreakdownTradingDataItem {
363 date: "2015-03-25".to_string(),
364 code: "13010".to_string(),
365 long_sell_value: 110000000.0,
366 short_sell_without_margin_value: 90000000.0,
367 margin_sell_new_value: 6000000.0,
368 margin_sell_close_value: 22000000.0,
369 long_buy_value: 180000000.0,
370 margin_buy_new_value: 35000000.0,
371 margin_buy_close_value: 17000000.0,
372 long_sell_volume: 400000.0,
373 short_sell_without_margin_volume: 330000.0,
374 margin_sell_new_volume: 22000.0,
375 margin_sell_close_volume: 82000.0,
376 long_buy_volume: 660000.0,
377 margin_buy_new_volume: 125000.0,
378 margin_buy_close_volume: 62000.0,
379 },
380 BreakdownTradingDataItem {
381 date: "2015-04-01".to_string(),
382 code: "13010".to_string(),
383 long_sell_value: 115164000.0,
384 short_sell_without_margin_value: 93561000.0,
385 margin_sell_new_value: 6412000.0,
386 margin_sell_close_value: 23009000.0,
387 long_buy_value: 185114000.0,
388 margin_buy_new_value: 35568000.0,
389 margin_buy_close_value: 17464000.0,
390 long_sell_volume: 415000.0,
391 short_sell_without_margin_volume: 337000.0,
392 margin_sell_new_volume: 23000.0,
393 margin_sell_close_volume: 83000.0,
394 long_buy_volume: 667000.0,
395 margin_buy_new_volume: 128000.0,
396 margin_buy_close_volume: 63000.0,
397 },
398 ],
399 pagination_key: Some("value1.value2.".to_string()),
400 };
401
402 pretty_assertions::assert_eq!(response, expected_response);
403 }
404
405 #[test]
406 fn test_deserialize_breakdown_trading_data_response_no_data() {
407 let json = r#"
408 {
409 "breakdown": []
410 }
411 "#;
412
413 let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
414 let expected_response = BreakdownTradingDataResponse {
415 breakdown: vec![],
416 pagination_key: None,
417 };
418
419 pretty_assertions::assert_eq!(response, expected_response);
420 }
421}