1use serde::{Deserialize, Serialize};
4
5use super::{
6 shared::{
7 traits::{
8 builder::JQuantsBuilder,
9 pagination::{HasPaginationKey, MergePage, Paginatable},
10 },
11 types::issue_type::IssueType,
12 },
13 JQuantsApiClient, JQuantsPlanClient,
14};
15
16#[derive(Clone, Serialize)]
18pub struct WeeklyMarginTradingOutstandingsBuilder {
19 #[serde(skip)]
20 client: JQuantsApiClient,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 code: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 date: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 from: Option<String>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 to: Option<String>,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pagination_key: Option<String>,
38}
39
40impl JQuantsBuilder<WeeklyMarginTradingOutstandingsResponse>
41 for WeeklyMarginTradingOutstandingsBuilder
42{
43 async fn send(self) -> Result<WeeklyMarginTradingOutstandingsResponse, crate::JQuantsError> {
44 self.send_ref().await
45 }
46
47 async fn send_ref(
48 &self,
49 ) -> Result<WeeklyMarginTradingOutstandingsResponse, crate::JQuantsError> {
50 self.client
51 .inner
52 .get("markets/weekly_margin_interest", self)
53 .await
54 }
55}
56
57impl Paginatable<WeeklyMarginTradingOutstandingsResponse>
58 for WeeklyMarginTradingOutstandingsBuilder
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 WeeklyMarginTradingOutstandingsBuilder {
67 pub(crate) fn new(client: JQuantsApiClient) -> Self {
69 Self {
70 client,
71 code: None,
72 date: None,
73 from: None,
74 to: None,
75 pagination_key: None,
76 }
77 }
78
79 pub fn code(mut self, code: impl Into<String>) -> Self {
81 self.code = Some(code.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 pub fn from(mut self, from: impl Into<String>) -> Self {
93 self.from = Some(from.into());
94 self
95 }
96
97 pub fn to(mut self, to: impl Into<String>) -> Self {
99 self.to = Some(to.into());
100 self
101 }
102}
103
104pub trait WeeklyMarginTradingOutstandingsApi: JQuantsPlanClient {
106 fn get_weekly_margin_trading_outstandings(&self) -> WeeklyMarginTradingOutstandingsBuilder {
110 WeeklyMarginTradingOutstandingsBuilder::new(self.get_api_client().clone())
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Deserialize)]
118pub struct WeeklyMarginTradingOutstandingsResponse {
119 pub weekly_margin_interest: Vec<WeeklyMarginTradingOutstandingItem>,
121 pub pagination_key: Option<String>,
123}
124
125impl HasPaginationKey for WeeklyMarginTradingOutstandingsResponse {
126 fn get_pagination_key(&self) -> Option<&str> {
127 self.pagination_key.as_deref()
128 }
129}
130
131impl MergePage for WeeklyMarginTradingOutstandingsResponse {
132 fn merge_page(
133 page: Result<Vec<Self>, crate::JQuantsError>,
134 ) -> Result<Self, crate::JQuantsError> {
135 let mut page = page?;
136 let mut merged = page.pop().unwrap();
137 for p in page {
138 merged
139 .weekly_margin_interest
140 .extend(p.weekly_margin_interest);
141 }
142 merged.pagination_key = None;
143
144 Ok(merged)
145 }
146}
147
148#[derive(Debug, Clone, PartialEq, Deserialize)]
150pub struct WeeklyMarginTradingOutstandingItem {
151 #[serde(rename = "Date")]
153 pub date: String,
154
155 #[serde(rename = "Code")]
157 pub code: String,
158
159 #[serde(rename = "ShortMarginTradeVolume")]
161 pub short_margin_trade_volume: f64,
162
163 #[serde(rename = "LongMarginTradeVolume")]
165 pub long_margin_trade_volume: f64,
166
167 #[serde(rename = "ShortNegotiableMarginTradeVolume")]
169 pub short_negotiable_margin_trade_volume: f64,
170
171 #[serde(rename = "LongNegotiableMarginTradeVolume")]
173 pub long_negotiable_margin_trade_volume: f64,
174
175 #[serde(rename = "ShortStandardizedMarginTradeVolume")]
177 pub short_standardized_margin_trade_volume: f64,
178
179 #[serde(rename = "LongStandardizedMarginTradeVolume")]
181 pub long_standardized_margin_trade_volume: f64,
182
183 #[serde(rename = "IssueType")]
185 pub issue_type: IssueType,
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn test_deserialize_weekly_margin_trading_outstandings_response() {
194 let json = r#"
195 {
196 "weekly_margin_interest": [
197 {
198 "Date": "2023-02-17",
199 "Code": "13010",
200 "ShortMarginTradeVolume": 4100.0,
201 "LongMarginTradeVolume": 27600.0,
202 "ShortNegotiableMarginTradeVolume": 1300.0,
203 "LongNegotiableMarginTradeVolume": 7600.0,
204 "ShortStandardizedMarginTradeVolume": 2800.0,
205 "LongStandardizedMarginTradeVolume": 20000.0,
206 "IssueType": "2"
207 }
208 ],
209 "pagination_key": "value1.value2."
210 }
211 "#;
212
213 let response: WeeklyMarginTradingOutstandingsResponse = serde_json::from_str(json).unwrap();
214 let expected_response = WeeklyMarginTradingOutstandingsResponse {
215 weekly_margin_interest: vec![WeeklyMarginTradingOutstandingItem {
216 date: "2023-02-17".to_string(),
217 code: "13010".to_string(),
218 short_margin_trade_volume: 4100.0,
219 long_margin_trade_volume: 27600.0,
220 short_negotiable_margin_trade_volume: 1300.0,
221 long_negotiable_margin_trade_volume: 7600.0,
222 short_standardized_margin_trade_volume: 2800.0,
223 long_standardized_margin_trade_volume: 20000.0,
224 issue_type: IssueType::Loan, }],
226 pagination_key: Some("value1.value2.".to_string()),
227 };
228
229 pretty_assertions::assert_eq!(response, expected_response);
230 }
231
232 #[test]
233 fn test_deserialize_weekly_margin_trading_outstandings_response_no_pagination_key() {
234 let json = r#"
235 {
236 "weekly_margin_interest": [
237 {
238 "Date": "2023-02-17",
239 "Code": "13010",
240 "ShortMarginTradeVolume": 4100.0,
241 "LongMarginTradeVolume": 27600.0,
242 "ShortNegotiableMarginTradeVolume": 1300.0,
243 "LongNegotiableMarginTradeVolume": 7600.0,
244 "ShortStandardizedMarginTradeVolume": 2800.0,
245 "LongStandardizedMarginTradeVolume": 20000.0,
246 "IssueType": "2"
247 }
248 ]
249 }
250 "#;
251
252 let response: WeeklyMarginTradingOutstandingsResponse = serde_json::from_str(json).unwrap();
253 let expected_response = WeeklyMarginTradingOutstandingsResponse {
254 weekly_margin_interest: vec![WeeklyMarginTradingOutstandingItem {
255 date: "2023-02-17".to_string(),
256 code: "13010".to_string(),
257 short_margin_trade_volume: 4100.0,
258 long_margin_trade_volume: 27600.0,
259 short_negotiable_margin_trade_volume: 1300.0,
260 long_negotiable_margin_trade_volume: 7600.0,
261 short_standardized_margin_trade_volume: 2800.0,
262 long_standardized_margin_trade_volume: 20000.0,
263 issue_type: IssueType::Loan, }],
265 pagination_key: None,
266 };
267
268 pretty_assertions::assert_eq!(response, expected_response);
269 }
270
271 #[test]
272 fn test_deserialize_weekly_margin_trading_outstandings_response_multiple_items() {
273 let json = r#"
274 {
275 "weekly_margin_interest": [
276 {
277 "Date": "2023-02-10",
278 "Code": "13010",
279 "ShortMarginTradeVolume": 4000.0,
280 "LongMarginTradeVolume": 27000.0,
281 "ShortNegotiableMarginTradeVolume": 1200.0,
282 "LongNegotiableMarginTradeVolume": 7500.0,
283 "ShortStandardizedMarginTradeVolume": 2800.0,
284 "LongStandardizedMarginTradeVolume": 19500.0,
285 "IssueType": "2"
286 },
287 {
288 "Date": "2023-02-17",
289 "Code": "13010",
290 "ShortMarginTradeVolume": 4100.0,
291 "LongMarginTradeVolume": 27600.0,
292 "ShortNegotiableMarginTradeVolume": 1300.0,
293 "LongNegotiableMarginTradeVolume": 7600.0,
294 "ShortStandardizedMarginTradeVolume": 2800.0,
295 "LongStandardizedMarginTradeVolume": 20000.0,
296 "IssueType": "2"
297 }
298 ],
299 "pagination_key": "value1.value2."
300 }
301 "#;
302
303 let response: WeeklyMarginTradingOutstandingsResponse = serde_json::from_str(json).unwrap();
304 let expected_response = WeeklyMarginTradingOutstandingsResponse {
305 weekly_margin_interest: vec![
306 WeeklyMarginTradingOutstandingItem {
307 date: "2023-02-10".to_string(),
308 code: "13010".to_string(),
309 short_margin_trade_volume: 4000.0,
310 long_margin_trade_volume: 27000.0,
311 short_negotiable_margin_trade_volume: 1200.0,
312 long_negotiable_margin_trade_volume: 7500.0,
313 short_standardized_margin_trade_volume: 2800.0,
314 long_standardized_margin_trade_volume: 19500.0,
315 issue_type: IssueType::Loan, },
317 WeeklyMarginTradingOutstandingItem {
318 date: "2023-02-17".to_string(),
319 code: "13010".to_string(),
320 short_margin_trade_volume: 4100.0,
321 long_margin_trade_volume: 27600.0,
322 short_negotiable_margin_trade_volume: 1300.0,
323 long_negotiable_margin_trade_volume: 7600.0,
324 short_standardized_margin_trade_volume: 2800.0,
325 long_standardized_margin_trade_volume: 20000.0,
326 issue_type: IssueType::Loan, },
328 ],
329 pagination_key: Some("value1.value2.".to_string()),
330 };
331
332 pretty_assertions::assert_eq!(response, expected_response);
333 }
334
335 #[test]
336 fn test_deserialize_weekly_margin_trading_outstandings_response_no_data() {
337 let json = r#"
338 {
339 "weekly_margin_interest": []
340 }
341 "#;
342
343 let response: WeeklyMarginTradingOutstandingsResponse = serde_json::from_str(json).unwrap();
344 let expected_response = WeeklyMarginTradingOutstandingsResponse {
345 weekly_margin_interest: vec![],
346 pagination_key: None,
347 };
348
349 pretty_assertions::assert_eq!(response, expected_response);
350 }
351}