use serde::Deserialize;
use crate::client::AkShareClient;
use crate::error::{Error, Result};
impl AkShareClient {
pub async fn index_yw(&self, symbol: &str) -> Result<Vec<YwIndexPoint>> {
match symbol {
"月景气指数" => self.index_yw_bi().await,
"周价格指数" => self.index_yw_price("piweek").await,
"月价格指数" => self.index_yw_price("month").await,
_ => Err(Error::invalid_input(format!(
"unsupported YW symbol: {symbol}"
))),
}
}
async fn index_yw_bi(&self) -> Result<Vec<YwIndexPoint>> {
#[derive(Deserialize)]
struct Envelope {
data: Option<Vec<YwBiRow>>,
}
#[derive(Deserialize)]
struct YwBiRow {
#[serde(default)]
indextimeno: String,
#[serde(default)]
totalindex: Option<f64>,
#[serde(default)]
scopeindex: Option<f64>,
#[serde(default)]
benifitindex: Option<f64>,
#[serde(default)]
confidentindex: Option<f64>,
}
let response = self
.get("https://apiserver.chinagoods.com/yiwuindex/v1/active/industry/class/history/bi")
.query(&[("gcCode", "")])
.send()
.await
.map_err(Error::from)?
.error_for_status()
.map_err(Error::from)?;
let payload: Envelope = response.json().await.map_err(Error::from)?;
let rows = payload.data.unwrap_or_default();
let points: Vec<YwIndexPoint> = rows
.into_iter()
.map(|r| YwIndexPoint {
period: r.indextimeno,
index_type: "月景气指数".to_string(),
value1: r.totalindex.unwrap_or(0.0),
value2: r.scopeindex.unwrap_or(0.0),
value3: r.benifitindex.unwrap_or(0.0),
value4: r.confidentindex.unwrap_or(0.0),
value5: 0.0,
})
.collect();
if points.is_empty() {
return Err(Error::not_found("chinagoods returned no YW bi data"));
}
Ok(points)
}
async fn index_yw_price(&self, path: &str) -> Result<Vec<YwIndexPoint>> {
#[derive(Deserialize)]
struct Envelope {
data: Option<Vec<serde_json::Value>>,
}
let url = format!(
"https://apiserver.chinagoods.com/yiwuindex/v1/active/industry/class/history/{path}"
);
let response = self
.get(&url)
.query(&[("gcCode", "")])
.send()
.await
.map_err(Error::from)?
.error_for_status()
.map_err(Error::from)?;
let payload: Envelope = response.json().await.map_err(Error::from)?;
let data = payload.data.unwrap_or_default();
let points: Vec<YwIndexPoint> = data
.into_iter()
.filter_map(|row| {
let obj = row.as_object()?;
let period = obj.get("indextimeno")?.as_str()?.to_string();
let v1 = obj.get("totalpriceindex")?.as_f64().unwrap_or(0.0);
let v2 = obj.get("stockdealpriceindex")?.as_f64().unwrap_or(0.0);
let v3 = obj.get("netdealpriceindex")?.as_f64().unwrap_or(0.0);
let v4 = obj.get("orderdealpriceindex")?.as_f64().unwrap_or(0.0);
let v5 = obj.get("outdealpriceindex")?.as_f64().unwrap_or(0.0);
Some(YwIndexPoint {
period,
index_type: if path == "piweek" {
"周价格指数".to_string()
} else {
"月价格指数".to_string()
},
value1: v1,
value2: v2,
value3: v3,
value4: v4,
value5: v5,
})
})
.collect();
if points.is_empty() {
return Err(Error::not_found("chinagoods returned no YW price data"));
}
Ok(points)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct YwIndexPoint {
pub period: String,
pub index_type: String,
pub value1: f64,
pub value2: f64,
pub value3: f64,
pub value4: f64,
pub value5: f64,
}
#[cfg(test)]
mod tests {
#[test]
fn test_placeholder() {
}
}