use serde::Deserialize;
use crate::client::AkShareClient;
use crate::error::{Error, Result};
#[derive(Debug, Deserialize)]
struct SseQueryEnvelope {
result: Option<Vec<serde_json::Value>>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct OptionRiskIndicatorRow {
pub trade_date: String,
pub security_id: String,
pub contract_id: String,
pub contract_symbol: String,
pub delta: f64,
pub theta: f64,
pub gamma: f64,
pub vega: f64,
pub rho: f64,
pub implied_volatility: f64,
}
impl AkShareClient {
pub async fn option_risk_indicator_sse(
&self,
date: &str,
) -> Result<Vec<OptionRiskIndicatorRow>> {
let url = "http://query.sse.com.cn/commonQuery.do";
let resp: SseQueryEnvelope = self
.get(url)
.query(&[
("isPagination", "false"),
("trade_date", date),
("sqlId", "SSE_ZQPZ_YSP_GGQQZSXT_YSHQ_QQFXZB_DATE_L"),
("contractSymbol", ""),
])
.header("Referer", "http://www.sse.com.cn/")
.send()
.await
.map_err(Error::from)?
.json()
.await
.map_err(Error::from)?;
let data = resp.result.unwrap_or_default();
let mut rows = Vec::with_capacity(data.len());
for item in &data {
rows.push(OptionRiskIndicatorRow {
trade_date: json_str(item, "TRADE_DATE"),
security_id: json_str(item, "SECURITY_ID"),
contract_id: json_str(item, "CONTRACT_ID"),
contract_symbol: json_str(item, "CONTRACT_SYMBOL"),
delta: json_f64(item, "DELTA_VALUE"),
theta: json_f64(item, "THETA_VALUE"),
gamma: json_f64(item, "GAMMA_VALUE"),
vega: json_f64(item, "VEGA_VALUE"),
rho: json_f64(item, "RHO_VALUE"),
implied_volatility: json_f64(item, "IMPLC_VOLATLTY"),
});
}
Ok(rows)
}
}
fn json_str(v: &serde_json::Value, key: &str) -> String {
v.get(key)
.and_then(|x| x.as_str())
.unwrap_or("")
.to_string()
}
fn json_f64(v: &serde_json::Value, key: &str) -> f64 {
match v.get(key) {
Some(serde_json::Value::Number(n)) => n.as_f64().unwrap_or(0.0),
Some(serde_json::Value::String(s)) => s.trim().parse::<f64>().unwrap_or(0.0),
_ => 0.0,
}
}