ccxt_exchanges/binance/parser/
ohlcv.rs

1use ccxt_core::{
2    Result,
3    error::{Error, ParseError},
4    types::OHLCV,
5};
6use serde_json::Value;
7
8/// Parse OHLCV (candlestick/kline) data from Binance market API.
9pub fn parse_ohlcv(data: &Value) -> Result<ccxt_core::types::OHLCV> {
10    if let Some(array) = data.as_array() {
11        if array.len() < 6 {
12            return Err(Error::from(ParseError::invalid_format(
13                "data",
14                "OHLCV array length insufficient",
15            )));
16        }
17
18        let timestamp = array[0]
19            .as_i64()
20            .ok_or_else(|| Error::from(ParseError::invalid_format("data", "无效的时间戳")))?;
21
22        let open = array[1]
23            .as_str()
24            .and_then(|s| s.parse::<f64>().ok())
25            .or_else(|| array[1].as_f64())
26            .ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid open price")))?;
27
28        let high = array[2]
29            .as_str()
30            .and_then(|s| s.parse::<f64>().ok())
31            .or_else(|| array[2].as_f64())
32            .ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid high price")))?;
33
34        let low = array[3]
35            .as_str()
36            .and_then(|s| s.parse::<f64>().ok())
37            .or_else(|| array[3].as_f64())
38            .ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid low price")))?;
39
40        let close = array[4]
41            .as_str()
42            .and_then(|s| s.parse::<f64>().ok())
43            .or_else(|| array[4].as_f64())
44            .ok_or_else(|| {
45                Error::from(ParseError::invalid_format("data", "Invalid close price"))
46            })?;
47
48        let volume = array[5]
49            .as_str()
50            .and_then(|s| s.parse::<f64>().ok())
51            .or_else(|| array[5].as_f64())
52            .ok_or_else(|| Error::from(ParseError::invalid_format("data", "Invalid volume")))?;
53
54        Ok(OHLCV::new(timestamp, open, high, low, close, volume))
55    } else {
56        Err(Error::from(ParseError::invalid_format(
57            "data",
58            "OHLCV data must be in array format",
59        )))
60    }
61}
62
63/// Parse multiple OHLCV (candlestick/kline) data entries from Binance market API.
64pub fn parse_ohlcvs(data: &Value) -> Result<Vec<ccxt_core::types::OHLCV>> {
65    if let Some(array) = data.as_array() {
66        array.iter().map(|item| parse_ohlcv(item)).collect()
67    } else {
68        Err(Error::from(ParseError::invalid_format(
69            "data",
70            "OHLCV data list must be in array format",
71        )))
72    }
73}
74
75/// Parse WebSocket OHLCV (candlestick/kline) data from Binance streams.
76pub fn parse_ws_ohlcv(data: &Value) -> Result<OHLCV> {
77    let kline = data["k"]
78        .as_object()
79        .ok_or_else(|| Error::from(ParseError::missing_field("k")))?;
80
81    let timestamp = kline
82        .get("t")
83        .and_then(serde_json::Value::as_i64)
84        .ok_or_else(|| Error::from(ParseError::missing_field("t")))?;
85
86    let open = kline
87        .get("o")
88        .and_then(serde_json::Value::as_str)
89        .and_then(|s| s.parse::<f64>().ok())
90        .ok_or_else(|| Error::from(ParseError::missing_field("o")))?;
91
92    let high = kline
93        .get("h")
94        .and_then(serde_json::Value::as_str)
95        .and_then(|s| s.parse::<f64>().ok())
96        .ok_or_else(|| Error::from(ParseError::missing_field("h")))?;
97
98    let low = kline
99        .get("l")
100        .and_then(serde_json::Value::as_str)
101        .and_then(|s| s.parse::<f64>().ok())
102        .ok_or_else(|| Error::from(ParseError::missing_field("l")))?;
103
104    let close = kline
105        .get("c")
106        .and_then(serde_json::Value::as_str)
107        .and_then(|s| s.parse::<f64>().ok())
108        .ok_or_else(|| Error::from(ParseError::missing_field("c")))?;
109
110    let volume = kline
111        .get("v")
112        .and_then(serde_json::Value::as_str)
113        .and_then(|s| s.parse::<f64>().ok())
114        .ok_or_else(|| Error::from(ParseError::missing_field("v")))?;
115
116    Ok(OHLCV {
117        timestamp,
118        open,
119        high,
120        low,
121        close,
122        volume,
123    })
124}