use ccxt_core::{
Result,
error::{Error, ParseError},
types::OHLCV,
};
use serde_json::Value;
pub fn parse_ohlcv(data: &Value) -> Result<ccxt_core::types::OHLCV> {
if let Some(array) = data.as_array() {
if array.len() < 6 {
return Err(Error::from(ParseError::invalid_format(
"data",
"OHLCV array length insufficient",
)));
}
let timestamp = array[0]
.as_i64()
.ok_or_else(|| Error::from(ParseError::invalid_format("data", "无效的时间戳")))?;
let open = array[1]
.as_str()
.and_then(|s| s.parse::<f64>().ok())
.or_else(|| array[1].as_f64())
.ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid open price")))?;
let high = array[2]
.as_str()
.and_then(|s| s.parse::<f64>().ok())
.or_else(|| array[2].as_f64())
.ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid high price")))?;
let low = array[3]
.as_str()
.and_then(|s| s.parse::<f64>().ok())
.or_else(|| array[3].as_f64())
.ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid low price")))?;
let close = array[4]
.as_str()
.and_then(|s| s.parse::<f64>().ok())
.or_else(|| array[4].as_f64())
.ok_or_else(|| {
Error::from(ParseError::invalid_format("data", "Invalid close price"))
})?;
let volume = array[5]
.as_str()
.and_then(|s| s.parse::<f64>().ok())
.or_else(|| array[5].as_f64())
.ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid volume")))?;
Ok(OHLCV::new(timestamp, open, high, low, close, volume))
} else {
Err(Error::from(ParseError::invalid_format(
"data",
"OHLCV data must be in array format",
)))
}
}
pub fn parse_ohlcvs(data: &Value) -> Result<Vec<ccxt_core::types::OHLCV>> {
if let Some(array) = data.as_array() {
array.iter().map(|item| parse_ohlcv(item)).collect()
} else {
Err(Error::from(ParseError::invalid_format(
"data",
"OHLCV data list must be in array format",
)))
}
}
pub fn parse_ws_ohlcv(data: &Value) -> Result<OHLCV> {
let kline = data["k"]
.as_object()
.ok_or_else(|| Error::from(ParseError::missing_field("k")))?;
let timestamp = kline
.get("t")
.and_then(serde_json::Value::as_i64)
.ok_or_else(|| Error::from(ParseError::missing_field("t")))?;
let open = kline
.get("o")
.and_then(serde_json::Value::as_str)
.and_then(|s| s.parse::<f64>().ok())
.ok_or_else(|| Error::from(ParseError::missing_field("o")))?;
let high = kline
.get("h")
.and_then(serde_json::Value::as_str)
.and_then(|s| s.parse::<f64>().ok())
.ok_or_else(|| Error::from(ParseError::missing_field("h")))?;
let low = kline
.get("l")
.and_then(serde_json::Value::as_str)
.and_then(|s| s.parse::<f64>().ok())
.ok_or_else(|| Error::from(ParseError::missing_field("l")))?;
let close = kline
.get("c")
.and_then(serde_json::Value::as_str)
.and_then(|s| s.parse::<f64>().ok())
.ok_or_else(|| Error::from(ParseError::missing_field("c")))?;
let volume = kline
.get("v")
.and_then(serde_json::Value::as_str)
.and_then(|s| s.parse::<f64>().ok())
.ok_or_else(|| Error::from(ParseError::missing_field("v")))?;
Ok(OHLCV {
timestamp,
open,
high,
low,
close,
volume,
})
}