use serde::{Deserialize, Serialize};
use super::{
shared::traits::{
builder::JQuantsBuilder,
pagination::{HasPaginationKey, MergePage, Paginatable},
},
JQuantsApiClient, JQuantsPlanClient,
};
#[derive(Clone, Serialize)]
pub struct BreakdownTradingDataBuilder {
#[serde(skip)]
client: JQuantsApiClient,
#[serde(skip_serializing_if = "Option::is_none")]
code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
from: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pagination_key: Option<String>,
}
impl JQuantsBuilder<BreakdownTradingDataResponse> for BreakdownTradingDataBuilder {
async fn send(self) -> Result<BreakdownTradingDataResponse, crate::JQuantsError> {
self.send_ref().await
}
async fn send_ref(&self) -> Result<BreakdownTradingDataResponse, crate::JQuantsError> {
self.client.inner.get("markets/breakdown", self).await
}
}
impl Paginatable<BreakdownTradingDataResponse> for BreakdownTradingDataBuilder {
fn pagination_key(mut self, pagination_key: impl Into<String>) -> Self {
self.pagination_key = Some(pagination_key.into());
self
}
}
impl BreakdownTradingDataBuilder {
pub(crate) fn new(client: JQuantsApiClient) -> Self {
Self {
client,
code: None,
from: None,
to: None,
date: None,
pagination_key: None,
}
}
pub fn code(mut self, code: impl Into<String>) -> Self {
self.code = Some(code.into());
self
}
pub fn from(mut self, from: impl Into<String>) -> Self {
self.from = Some(from.into());
self
}
pub fn to(mut self, to: impl Into<String>) -> Self {
self.to = Some(to.into());
self
}
pub fn date(mut self, date: impl Into<String>) -> Self {
self.date = Some(date.into());
self
}
}
pub trait BreakdownTradingDataApi: JQuantsPlanClient {
fn get_breakdown_trading_data(&self) -> BreakdownTradingDataBuilder {
BreakdownTradingDataBuilder::new(self.get_api_client().clone())
}
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct BreakdownTradingDataResponse {
pub breakdown: Vec<BreakdownTradingDataItem>,
pub pagination_key: Option<String>,
}
impl HasPaginationKey for BreakdownTradingDataResponse {
fn get_pagination_key(&self) -> Option<&str> {
self.pagination_key.as_deref()
}
}
impl MergePage for BreakdownTradingDataResponse {
fn merge_page(
page: Result<Vec<Self>, crate::JQuantsError>,
) -> Result<Self, crate::JQuantsError> {
let mut page = page?;
let mut merged = page.pop().unwrap();
for p in page {
merged.breakdown.extend(p.breakdown);
}
merged.pagination_key = None;
Ok(merged)
}
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct BreakdownTradingDataItem {
#[serde(rename = "Date")]
pub date: String,
#[serde(rename = "Code")]
pub code: String,
#[serde(rename = "LongSellValue")]
pub long_sell_value: f64,
#[serde(rename = "ShortSellWithoutMarginValue")]
pub short_sell_without_margin_value: f64,
#[serde(rename = "MarginSellNewValue")]
pub margin_sell_new_value: f64,
#[serde(rename = "MarginSellCloseValue")]
pub margin_sell_close_value: f64,
#[serde(rename = "LongBuyValue")]
pub long_buy_value: f64,
#[serde(rename = "MarginBuyNewValue")]
pub margin_buy_new_value: f64,
#[serde(rename = "MarginBuyCloseValue")]
pub margin_buy_close_value: f64,
#[serde(rename = "LongSellVolume")]
pub long_sell_volume: f64,
#[serde(rename = "ShortSellWithoutMarginVolume")]
pub short_sell_without_margin_volume: f64,
#[serde(rename = "MarginSellNewVolume")]
pub margin_sell_new_volume: f64,
#[serde(rename = "MarginSellCloseVolume")]
pub margin_sell_close_volume: f64,
#[serde(rename = "LongBuyVolume")]
pub long_buy_volume: f64,
#[serde(rename = "MarginBuyNewVolume")]
pub margin_buy_new_volume: f64,
#[serde(rename = "MarginBuyCloseVolume")]
pub margin_buy_close_volume: f64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize_breakdown_trading_data_response() {
let json = r#"
{
"breakdown": [
{
"Date": "2015-04-01",
"Code": "13010",
"LongSellValue": 115164000.0,
"ShortSellWithoutMarginValue": 93561000.0,
"MarginSellNewValue": 6412000.0,
"MarginSellCloseValue": 23009000.0,
"LongBuyValue": 185114000.0,
"MarginBuyNewValue": 35568000.0,
"MarginBuyCloseValue": 17464000.0,
"LongSellVolume": 415000.0,
"ShortSellWithoutMarginVolume": 337000.0,
"MarginSellNewVolume": 23000.0,
"MarginSellCloseVolume": 83000.0,
"LongBuyVolume": 667000.0,
"MarginBuyNewVolume": 128000.0,
"MarginBuyCloseVolume": 63000.0
}
],
"pagination_key": "value1.value2."
}
"#;
let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
let expected_response = BreakdownTradingDataResponse {
breakdown: vec![BreakdownTradingDataItem {
date: "2015-04-01".to_string(),
code: "13010".to_string(),
long_sell_value: 115164000.0,
short_sell_without_margin_value: 93561000.0,
margin_sell_new_value: 6412000.0,
margin_sell_close_value: 23009000.0,
long_buy_value: 185114000.0,
margin_buy_new_value: 35568000.0,
margin_buy_close_value: 17464000.0,
long_sell_volume: 415000.0,
short_sell_without_margin_volume: 337000.0,
margin_sell_new_volume: 23000.0,
margin_sell_close_volume: 83000.0,
long_buy_volume: 667000.0,
margin_buy_new_volume: 128000.0,
margin_buy_close_volume: 63000.0,
}],
pagination_key: Some("value1.value2.".to_string()),
};
pretty_assertions::assert_eq!(response, expected_response);
}
#[test]
fn test_deserialize_breakdown_trading_data_response_no_pagination_key() {
let json = r#"
{
"breakdown": [
{
"Date": "2015-04-01",
"Code": "13010",
"LongSellValue": 115164000.0,
"ShortSellWithoutMarginValue": 93561000.0,
"MarginSellNewValue": 6412000.0,
"MarginSellCloseValue": 23009000.0,
"LongBuyValue": 185114000.0,
"MarginBuyNewValue": 35568000.0,
"MarginBuyCloseValue": 17464000.0,
"LongSellVolume": 415000.0,
"ShortSellWithoutMarginVolume": 337000.0,
"MarginSellNewVolume": 23000.0,
"MarginSellCloseVolume": 83000.0,
"LongBuyVolume": 667000.0,
"MarginBuyNewVolume": 128000.0,
"MarginBuyCloseVolume": 63000.0
}
]
}
"#;
let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
let expected_response = BreakdownTradingDataResponse {
breakdown: vec![BreakdownTradingDataItem {
date: "2015-04-01".to_string(),
code: "13010".to_string(),
long_sell_value: 115164000.0,
short_sell_without_margin_value: 93561000.0,
margin_sell_new_value: 6412000.0,
margin_sell_close_value: 23009000.0,
long_buy_value: 185114000.0,
margin_buy_new_value: 35568000.0,
margin_buy_close_value: 17464000.0,
long_sell_volume: 415000.0,
short_sell_without_margin_volume: 337000.0,
margin_sell_new_volume: 23000.0,
margin_sell_close_volume: 83000.0,
long_buy_volume: 667000.0,
margin_buy_new_volume: 128000.0,
margin_buy_close_volume: 63000.0,
}],
pagination_key: None,
};
pretty_assertions::assert_eq!(response, expected_response);
}
#[test]
fn test_deserialize_breakdown_trading_data_response_multiple_items() {
let json = r#"
{
"breakdown": [
{
"Date": "2015-03-25",
"Code": "13010",
"LongSellValue": 110000000.0,
"ShortSellWithoutMarginValue": 90000000.0,
"MarginSellNewValue": 6000000.0,
"MarginSellCloseValue": 22000000.0,
"LongBuyValue": 180000000.0,
"MarginBuyNewValue": 35000000.0,
"MarginBuyCloseValue": 17000000.0,
"LongSellVolume": 400000.0,
"ShortSellWithoutMarginVolume": 330000.0,
"MarginSellNewVolume": 22000.0,
"MarginSellCloseVolume": 82000.0,
"LongBuyVolume": 660000.0,
"MarginBuyNewVolume": 125000.0,
"MarginBuyCloseVolume": 62000.0
},
{
"Date": "2015-04-01",
"Code": "13010",
"LongSellValue": 115164000.0,
"ShortSellWithoutMarginValue": 93561000.0,
"MarginSellNewValue": 6412000.0,
"MarginSellCloseValue": 23009000.0,
"LongBuyValue": 185114000.0,
"MarginBuyNewValue": 35568000.0,
"MarginBuyCloseValue": 17464000.0,
"LongSellVolume": 415000.0,
"ShortSellWithoutMarginVolume": 337000.0,
"MarginSellNewVolume": 23000.0,
"MarginSellCloseVolume": 83000.0,
"LongBuyVolume": 667000.0,
"MarginBuyNewVolume": 128000.0,
"MarginBuyCloseVolume": 63000.0
}
],
"pagination_key": "value1.value2."
}
"#;
let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
let expected_response = BreakdownTradingDataResponse {
breakdown: vec![
BreakdownTradingDataItem {
date: "2015-03-25".to_string(),
code: "13010".to_string(),
long_sell_value: 110000000.0,
short_sell_without_margin_value: 90000000.0,
margin_sell_new_value: 6000000.0,
margin_sell_close_value: 22000000.0,
long_buy_value: 180000000.0,
margin_buy_new_value: 35000000.0,
margin_buy_close_value: 17000000.0,
long_sell_volume: 400000.0,
short_sell_without_margin_volume: 330000.0,
margin_sell_new_volume: 22000.0,
margin_sell_close_volume: 82000.0,
long_buy_volume: 660000.0,
margin_buy_new_volume: 125000.0,
margin_buy_close_volume: 62000.0,
},
BreakdownTradingDataItem {
date: "2015-04-01".to_string(),
code: "13010".to_string(),
long_sell_value: 115164000.0,
short_sell_without_margin_value: 93561000.0,
margin_sell_new_value: 6412000.0,
margin_sell_close_value: 23009000.0,
long_buy_value: 185114000.0,
margin_buy_new_value: 35568000.0,
margin_buy_close_value: 17464000.0,
long_sell_volume: 415000.0,
short_sell_without_margin_volume: 337000.0,
margin_sell_new_volume: 23000.0,
margin_sell_close_volume: 83000.0,
long_buy_volume: 667000.0,
margin_buy_new_volume: 128000.0,
margin_buy_close_volume: 63000.0,
},
],
pagination_key: Some("value1.value2.".to_string()),
};
pretty_assertions::assert_eq!(response, expected_response);
}
#[test]
fn test_deserialize_breakdown_trading_data_response_no_data() {
let json = r#"
{
"breakdown": []
}
"#;
let response: BreakdownTradingDataResponse = serde_json::from_str(json).unwrap();
let expected_response = BreakdownTradingDataResponse {
breakdown: vec![],
pagination_key: None,
};
pretty_assertions::assert_eq!(response, expected_response);
}
}