use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum Interval {
#[serde(rename = "1")]
Min1 = 1,
#[serde(rename = "5")]
Min5 = 5,
#[serde(rename = "15")]
Min15 = 15,
#[serde(rename = "30")]
Min30 = 30,
#[serde(rename = "60")]
Hour1 = 60,
#[serde(rename = "240")]
Hour4 = 240,
#[serde(rename = "1440")]
Day1 = 1440,
#[serde(rename = "10080")]
Week1 = 10080,
#[serde(rename = "21600")]
Day15 = 21600,
}
impl Interval {
pub fn minutes(&self) -> u32 {
*self as u32
}
pub fn to_api_string(&self) -> String {
self.minutes().to_string()
}
}
impl std::fmt::Display for Interval {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Interval::Min1 => write!(f, "1m"),
Interval::Min5 => write!(f, "5m"),
Interval::Min15 => write!(f, "15m"),
Interval::Min30 => write!(f, "30m"),
Interval::Hour1 => write!(f, "1h"),
Interval::Hour4 => write!(f, "4h"),
Interval::Day1 => write!(f, "1d"),
Interval::Week1 => write!(f, "1w"),
Interval::Day15 => write!(f, "15d"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OHLC {
pub symbol: String,
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub vwap: f64,
pub volume: f64,
pub count: i64,
pub interval: u32,
pub timestamp: String,
pub interval_begin: String,
}
fn deserialize_number<'de, D>(deserializer: D) -> Result<f64, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{self, Visitor};
struct NumberVisitor;
impl<'de> Visitor<'de> for NumberVisitor {
type Value = f64;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a number or string representation of a number")
}
fn visit_f64<E>(self, value: f64) -> Result<f64, E> {
Ok(value)
}
fn visit_i64<E>(self, value: i64) -> Result<f64, E> {
Ok(value as f64)
}
fn visit_u64<E>(self, value: u64) -> Result<f64, E> {
Ok(value as f64)
}
fn visit_str<E>(self, value: &str) -> Result<f64, E>
where
E: de::Error,
{
value.parse::<f64>().map_err(de::Error::custom)
}
}
deserializer.deserialize_any(NumberVisitor)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OHLCDataRaw {
pub symbol: String,
#[serde(deserialize_with = "deserialize_number")]
pub open: f64,
#[serde(deserialize_with = "deserialize_number")]
pub high: f64,
#[serde(deserialize_with = "deserialize_number")]
pub low: f64,
#[serde(deserialize_with = "deserialize_number")]
pub close: f64,
#[serde(deserialize_with = "deserialize_number")]
pub vwap: f64,
#[serde(deserialize_with = "deserialize_number")]
pub volume: f64,
#[serde(rename = "trades")]
pub count: i64,
pub interval: u32,
pub timestamp: String,
#[serde(default)]
pub interval_begin: String,
}
impl OHLCDataRaw {
pub fn to_ohlc(&self) -> OHLC {
OHLC {
symbol: self.symbol.clone(),
open: self.open,
high: self.high,
low: self.low,
close: self.close,
vwap: self.vwap,
volume: self.volume,
count: self.count,
interval: self.interval,
timestamp: self.timestamp.clone(),
interval_begin: self.interval_begin.clone(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OHLCUpdate {
#[serde(default)]
pub channel: String,
#[serde(rename = "type")]
pub update_type: String,
pub data: Vec<OHLCDataRaw>,
}