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 SmaResponse {
pub symbol: String,
#[serde(rename = "type")]
pub data_type: String,
pub exchange: String,
pub market: String,
pub timeframe: String,
pub period: u32,
pub data: Vec<SmaDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct SmaDataPoint {
pub date: String,
pub sma: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct RsiResponse {
pub symbol: String,
#[serde(rename = "type")]
pub data_type: String,
pub exchange: String,
pub market: String,
pub timeframe: String,
pub period: u32,
pub data: Vec<RsiDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct RsiDataPoint {
pub date: String,
pub rsi: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct KdjResponse {
pub symbol: String,
#[serde(rename = "type")]
pub data_type: String,
pub exchange: String,
pub market: String,
pub timeframe: String,
pub period: u32,
pub data: Vec<KdjDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct KdjDataPoint {
pub date: String,
pub k: f64,
pub d: f64,
pub j: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct MacdResponse {
pub symbol: String,
#[serde(rename = "type")]
pub data_type: String,
pub exchange: String,
pub market: String,
pub timeframe: String,
pub fast: u32,
pub slow: u32,
pub signal: u32,
pub data: Vec<MacdDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct MacdDataPoint {
pub date: String,
pub macd: f64,
#[serde(rename = "signal")]
pub signal_value: f64,
pub histogram: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct BbResponse {
pub symbol: String,
#[serde(rename = "type")]
pub data_type: String,
pub exchange: String,
pub market: String,
pub timeframe: String,
pub period: u32,
pub stddev: f64,
pub data: Vec<BbDataPoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
#[cfg_attr(feature = "js", napi_derive::napi(object))]
pub struct BbDataPoint {
pub date: String,
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sma_response_deserialization() {
let json = r#"{
"symbol": "2330",
"type": "EQUITY",
"exchange": "TWSE",
"market": "TSE",
"timeframe": "D",
"period": 20,
"data": [
{"date": "2024-01-15", "sma": 580.5},
{"date": "2024-01-16", "sma": 581.2}
]
}"#;
let response: SmaResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.symbol, "2330");
assert_eq!(response.data_type, "EQUITY");
assert_eq!(response.period, 20);
assert_eq!(response.data.len(), 2);
assert_eq!(response.data[0].sma, 580.5);
}
#[test]
fn test_rsi_response_deserialization() {
let json = r#"{
"symbol": "2330",
"type": "EQUITY",
"exchange": "TWSE",
"market": "TSE",
"timeframe": "D",
"period": 14,
"data": [
{"date": "2024-01-15", "rsi": 65.5},
{"date": "2024-01-16", "rsi": 68.2}
]
}"#;
let response: RsiResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.symbol, "2330");
assert_eq!(response.period, 14);
assert_eq!(response.data.len(), 2);
assert_eq!(response.data[0].rsi, 65.5);
}
#[test]
fn test_kdj_response_deserialization() {
let json = r#"{
"symbol": "2330",
"type": "EQUITY",
"exchange": "TWSE",
"market": "TSE",
"timeframe": "D",
"period": 9,
"data": [
{"date": "2024-01-15", "k": 75.5, "d": 70.2, "j": 86.1},
{"date": "2024-01-16", "k": 78.3, "d": 72.8, "j": 89.3}
]
}"#;
let response: KdjResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.symbol, "2330");
assert_eq!(response.period, 9);
assert_eq!(response.data.len(), 2);
assert_eq!(response.data[0].k, 75.5);
assert_eq!(response.data[0].d, 70.2);
assert_eq!(response.data[0].j, 86.1);
}
#[test]
fn test_macd_response_deserialization() {
let json = r#"{
"symbol": "2330",
"type": "EQUITY",
"exchange": "TWSE",
"market": "TSE",
"timeframe": "D",
"fast": 12,
"slow": 26,
"signal": 9,
"data": [
{"date": "2024-01-15", "macd": 5.5, "signal": 4.2, "histogram": 1.3},
{"date": "2024-01-16", "macd": 6.2, "signal": 4.8, "histogram": 1.4}
]
}"#;
let response: MacdResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.symbol, "2330");
assert_eq!(response.fast, 12);
assert_eq!(response.slow, 26);
assert_eq!(response.signal, 9);
assert_eq!(response.data.len(), 2);
assert_eq!(response.data[0].macd, 5.5);
assert_eq!(response.data[0].signal_value, 4.2);
assert_eq!(response.data[0].histogram, 1.3);
}
#[test]
fn test_bb_response_deserialization() {
let json = r#"{
"symbol": "2330",
"type": "EQUITY",
"exchange": "TWSE",
"market": "TSE",
"timeframe": "D",
"period": 20,
"stddev": 2.0,
"data": [
{"date": "2024-01-15", "upper": 600.5, "middle": 580.0, "lower": 559.5},
{"date": "2024-01-16", "upper": 602.2, "middle": 581.0, "lower": 559.8}
]
}"#;
let response: BbResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.symbol, "2330");
assert_eq!(response.period, 20);
assert_eq!(response.stddev, 2.0);
assert_eq!(response.data.len(), 2);
assert_eq!(response.data[0].upper, 600.5);
assert_eq!(response.data[0].middle, 580.0);
assert_eq!(response.data[0].lower, 559.5);
}
}