use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct SnapshotQuotesResponse {
pub date: String,
pub time: String,
pub market: String,
pub data: Vec<SnapshotQuote>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct SnapshotQuote {
#[serde(rename = "type")]
pub data_type: Option<String>,
pub symbol: String,
pub name: Option<String>,
#[serde(rename = "openPrice")]
pub open_price: Option<f64>,
#[serde(rename = "highPrice")]
pub high_price: Option<f64>,
#[serde(rename = "lowPrice")]
pub low_price: Option<f64>,
#[serde(rename = "closePrice")]
pub close_price: Option<f64>,
pub change: Option<f64>,
#[serde(rename = "changePercent")]
pub change_percent: Option<f64>,
#[serde(rename = "tradeVolume")]
pub trade_volume: Option<i64>,
#[serde(rename = "tradeValue")]
pub trade_value: Option<f64>,
#[serde(rename = "lastUpdated")]
pub last_updated: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct MoversResponse {
pub date: String,
pub time: String,
pub market: String,
pub data: Vec<Mover>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct Mover {
#[serde(rename = "type")]
pub data_type: Option<String>,
pub symbol: String,
pub name: Option<String>,
#[serde(rename = "openPrice")]
pub open_price: Option<f64>,
#[serde(rename = "highPrice")]
pub high_price: Option<f64>,
#[serde(rename = "lowPrice")]
pub low_price: Option<f64>,
#[serde(rename = "closePrice")]
pub close_price: Option<f64>,
pub change: Option<f64>,
#[serde(rename = "changePercent")]
pub change_percent: Option<f64>,
#[serde(rename = "tradeVolume")]
pub trade_volume: Option<i64>,
#[serde(rename = "tradeValue")]
pub trade_value: Option<f64>,
#[serde(rename = "lastUpdated")]
pub last_updated: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct ActivesResponse {
pub date: String,
pub time: String,
pub market: String,
pub data: Vec<Active>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct Active {
#[serde(rename = "type")]
pub data_type: Option<String>,
pub symbol: String,
pub name: Option<String>,
#[serde(rename = "openPrice")]
pub open_price: Option<f64>,
#[serde(rename = "highPrice")]
pub high_price: Option<f64>,
#[serde(rename = "lowPrice")]
pub low_price: Option<f64>,
#[serde(rename = "closePrice")]
pub close_price: Option<f64>,
pub change: Option<f64>,
#[serde(rename = "changePercent")]
pub change_percent: Option<f64>,
#[serde(rename = "tradeVolume")]
pub trade_volume: Option<i64>,
#[serde(rename = "tradeValue")]
pub trade_value: Option<f64>,
#[serde(rename = "lastUpdated")]
pub last_updated: Option<i64>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_snapshot_quotes_response_deserialization() {
let json = r#"{
"date": "2024-01-15",
"time": "13:30:00",
"market": "TSE",
"data": [
{
"type": "EQUITY",
"symbol": "2330",
"name": "TSMC",
"openPrice": 580.0,
"highPrice": 585.0,
"lowPrice": 578.0,
"closePrice": 583.0,
"change": 3.0,
"changePercent": 0.52,
"tradeVolume": 10000000,
"tradeValue": 5815000000,
"lastUpdated": 1705302000000
}
]
}"#;
let response: SnapshotQuotesResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.date, "2024-01-15");
assert_eq!(response.time, "13:30:00");
assert_eq!(response.market, "TSE");
assert_eq!(response.data.len(), 1);
let quote = &response.data[0];
assert_eq!(quote.symbol, "2330");
assert_eq!(quote.data_type, Some("EQUITY".to_string()));
assert_eq!(quote.close_price, Some(583.0));
assert_eq!(quote.change, Some(3.0));
}
#[test]
fn test_movers_response_deserialization() {
let json = r#"{
"date": "2024-01-15",
"time": "13:30:00",
"market": "TSE",
"data": [
{
"type": "EQUITY",
"symbol": "3008",
"name": "LARGAN",
"openPrice": 2500.0,
"highPrice": 2600.0,
"lowPrice": 2480.0,
"closePrice": 2590.0,
"change": 90.0,
"changePercent": 3.6,
"tradeVolume": 500000,
"tradeValue": 1295000000,
"lastUpdated": 1705302000000
}
]
}"#;
let response: MoversResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.market, "TSE");
assert_eq!(response.data.len(), 1);
let mover = &response.data[0];
assert_eq!(mover.symbol, "3008");
assert_eq!(mover.change_percent, Some(3.6));
}
#[test]
fn test_actives_response_deserialization() {
let json = r#"{
"date": "2024-01-15",
"time": "13:30:00",
"market": "TSE",
"data": [
{
"type": "EQUITY",
"symbol": "2330",
"name": "TSMC",
"openPrice": 580.0,
"highPrice": 585.0,
"lowPrice": 578.0,
"closePrice": 583.0,
"change": 3.0,
"changePercent": 0.52,
"tradeVolume": 50000000,
"tradeValue": 29150000000,
"lastUpdated": 1705302000000
}
]
}"#;
let response: ActivesResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.market, "TSE");
assert_eq!(response.data.len(), 1);
let active = &response.data[0];
assert_eq!(active.symbol, "2330");
assert_eq!(active.trade_volume, Some(50000000));
}
#[test]
fn test_minimal_snapshot_quote() {
let json = r#"{
"symbol": "2330"
}"#;
let quote: SnapshotQuote = serde_json::from_str(json).unwrap();
assert_eq!(quote.symbol, "2330");
assert!(quote.name.is_none());
assert!(quote.close_price.is_none());
}
}