#![allow(dead_code)]
use serde::Deserialize;
use crate::client::AkShareClient;
use crate::error::{Error, Result};
use crate::types::MacroDataPoint;
#[derive(Debug, Deserialize)]
struct EmDatacenterResp {
result: Option<EmResult>,
}
#[derive(Debug, Deserialize)]
struct EmResult {
#[serde(default)]
data: Vec<serde_json::Value>,
#[serde(default)]
pages: u32,
}
impl AkShareClient {
pub async fn rate_interbank(
&self,
market: &str,
symbol: &str,
indicator: &str,
) -> Result<Vec<MacroDataPoint>> {
let market_map = [
("上海银行同业拆借市场", "001"),
("中国银行同业拆借市场", "002"),
("伦敦银行同业拆借市场", "003"),
("欧洲银行同业拆借市场", "004"),
("香港银行同业拆借市场", "005"),
("新加坡银行同业拆借市场", "006"),
];
let currency_map = [
("Shibor人民币", "CNY"),
("Chibor人民币", "CNY"),
("Libor英镑", "GBP"),
("Libor欧元", "EUR"),
("Libor美元", "USD"),
("Libor日元", "JPY"),
("Euribor欧元", "EUR"),
("Hibor美元", "USD"),
("Hibor人民币", "CNH"),
("Hibor港币", "HKD"),
("Sibor星元", "SGD"),
("Sibor美元", "USD"),
];
let indicator_map = [
("隔夜", "001"),
("1周", "101"),
("2周", "102"),
("3周", "103"),
("1月", "201"),
("2月", "202"),
("3月", "203"),
("4月", "204"),
("5月", "205"),
("6月", "206"),
("7月", "207"),
("8月", "208"),
("9月", "209"),
("10月", "210"),
("11月", "211"),
("1年", "301"),
];
let market_code = market_map
.iter()
.find(|(k, _)| *k == market)
.map(|(_, v)| *v)
.ok_or_else(|| Error::invalid_input(format!("unknown market: {market}")))?;
let currency_code = currency_map
.iter()
.find(|(k, _)| *k == symbol)
.map(|(_, v)| *v)
.ok_or_else(|| Error::invalid_input(format!("unknown symbol: {symbol}")))?;
let indicator_code = indicator_map
.iter()
.find(|(k, _)| *k == indicator)
.map(|(_, v)| *v)
.ok_or_else(|| Error::invalid_input(format!("unknown indicator: {indicator}")))?;
let filter = format!(
r#"(MARKET_CODE="{market_code}")(CURRENCY_CODE="{currency_code}")(INDICATOR_ID="{indicator_code}")"#
);
let url = "https://datacenter-web.eastmoney.com/api/data/v1/get";
let resp: EmDatacenterResp = self
.get(url)
.query(&[
("reportName", "RPT_IMP_INTRESTRATEN"),
("columns", "REPORT_DATE,REPORT_PERIOD,IR_RATE,CHANGE_RATE"),
("filter", &filter),
("pageNumber", "1"),
("pageSize", "500"),
("sortTypes", "-1"),
("sortColumns", "REPORT_DATE"),
("source", "WEB"),
("client", "WEB"),
])
.send()
.await?
.json()
.await?;
let data = resp.result.map(|r| r.data).unwrap_or_default();
let mut items = Vec::new();
for v in &data {
let date = v
.get("REPORT_DATE")
.and_then(|x| x.as_str())
.unwrap_or("")
.to_string();
if date.is_empty() {
continue;
}
let rate = v
.get("IR_RATE")
.and_then(serde_json::Value::as_f64)
.unwrap_or(0.0);
items.push(MacroDataPoint {
date: date.get(..10).unwrap_or(&date).to_string(),
value: rate,
name: format!("{market} {symbol} {indicator}"),
});
}
Ok(items)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_em_datacenter_resp_structure() {
let json = r#"{
"result": {
"data": [
{
"REPORT_DATE": "2024-01-02 00:00:00",
"IR_RATE": 1.5,
"CHANGE_RATE": -0.01
}
],
"pages": 1
}
}"#;
let resp: EmDatacenterResp = serde_json::from_str(json).unwrap();
let data = resp.result.unwrap().data;
assert_eq!(data.len(), 1);
assert_eq!(
data[0].get("IR_RATE").and_then(serde_json::Value::as_f64),
Some(1.5)
);
}
}