use crate::model::{AssetBalance, Order};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PriceLevel {
pub price: f64,
pub quantity: f64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MarketDepthMessage {
pub timestamp: i64,
pub bids: Vec<PriceLevel>,
pub asks: Vec<PriceLevel>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MarketPriceMessage {
pub price: f64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Trade {
pub order_id: String,
pub timestamp: String,
pub symbol: String,
pub price: f64,
pub amount: f64,
pub side: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OhlcMessage {
#[serde(rename = "t")]
pub timestamp: i32,
#[serde(rename = "s")]
pub symbol: String,
#[serde(rename = "o")]
pub open: f64,
#[serde(rename = "h")]
pub high: f64,
#[serde(rename = "l")]
pub low: f64,
#[serde(rename = "c")]
pub close: f64,
#[serde(rename = "v")]
pub volume: f64,
}
#[derive(Debug, Clone)]
pub enum MarketStreamMessage {
Depth(MarketDepthMessage),
Price(MarketPriceMessage),
RecentTrades(Vec<Trade>),
Ohlc(OhlcMessage),
Unknown(String),
}
impl MarketStreamMessage {
pub fn is_depth(&self) -> bool {
matches!(self, MarketStreamMessage::Depth(_))
}
pub fn is_price(&self) -> bool {
matches!(self, MarketStreamMessage::Price(_))
}
pub fn is_recent_trades(&self) -> bool {
matches!(self, MarketStreamMessage::RecentTrades(_))
}
pub fn is_ohlc(&self) -> bool {
matches!(self, MarketStreamMessage::Ohlc(_))
}
pub fn is_unknown(&self) -> bool {
matches!(self, MarketStreamMessage::Unknown(_))
}
pub fn as_depth(&self) -> Option<&MarketDepthMessage> {
match self {
MarketStreamMessage::Depth(msg) => Some(msg),
_ => None,
}
}
pub fn as_price(&self) -> Option<&MarketPriceMessage> {
match self {
MarketStreamMessage::Price(msg) => Some(msg),
_ => None,
}
}
pub fn as_recent_trades(&self) -> Option<&Vec<Trade>> {
match self {
MarketStreamMessage::RecentTrades(trades) => Some(trades),
_ => None,
}
}
pub fn as_ohlc(&self) -> Option<&OhlcMessage> {
match self {
MarketStreamMessage::Ohlc(msg) => Some(msg),
_ => None,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum StreamType {
#[serde(rename = "Account")]
Account,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum StreamSubType {
#[serde(rename = "balance")]
Balance,
#[serde(rename = "order_info")]
OrderInfo,
#[serde(rename = "dlta_points")]
DltaPoints,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct StreamMessageBase {
#[serde(rename = "type")]
pub msg_type: StreamType,
pub sub_type: StreamSubType,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AccountBalanceMessage {
#[serde(rename = "type")]
pub msg_type: StreamType,
pub sub_type: StreamSubType,
pub balance: Vec<AssetBalance>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OrderInfoMessage {
#[serde(rename = "type")]
pub msg_type: StreamType,
pub sub_type: StreamSubType,
pub order: Order,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DltaPointsData {
pub delta: String,
pub new_total: String,
pub season_points: String,
pub source_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_ref: Option<String>,
pub league: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DltaPointsMessage {
#[serde(rename = "type")]
pub msg_type: StreamType,
pub sub_type: StreamSubType,
pub dlta_points: DltaPointsData,
}
#[derive(Debug, Clone)]
pub enum StreamMessage {
Balance(AccountBalanceMessage),
OrderInfo(OrderInfoMessage),
DltaPoints(DltaPointsMessage),
Unknown(String),
}
impl StreamMessage {
pub fn from_json(json: &str) -> Self {
let base: Result<StreamMessageBase, _> = serde_json::from_str(json);
match base {
Ok(base) => match base.sub_type {
StreamSubType::Balance => {
match serde_json::from_str::<AccountBalanceMessage>(json) {
Ok(msg) => StreamMessage::Balance(msg),
Err(_) => StreamMessage::Unknown(json.to_string()),
}
}
StreamSubType::OrderInfo => {
match serde_json::from_str::<OrderInfoMessage>(json) {
Ok(msg) => StreamMessage::OrderInfo(msg),
Err(_) => StreamMessage::Unknown(json.to_string()),
}
}
StreamSubType::DltaPoints => {
match serde_json::from_str::<DltaPointsMessage>(json) {
Ok(msg) => StreamMessage::DltaPoints(msg),
Err(_) => StreamMessage::Unknown(json.to_string()),
}
}
},
Err(_) => StreamMessage::Unknown(json.to_string()),
}
}
pub fn is_balance(&self) -> bool {
matches!(self, StreamMessage::Balance(_))
}
pub fn is_order_info(&self) -> bool {
matches!(self, StreamMessage::OrderInfo(_))
}
pub fn is_dlta_points(&self) -> bool {
matches!(self, StreamMessage::DltaPoints(_))
}
pub fn is_unknown(&self) -> bool {
matches!(self, StreamMessage::Unknown(_))
}
pub fn as_balance(&self) -> Option<&AccountBalanceMessage> {
match self {
StreamMessage::Balance(msg) => Some(msg),
_ => None,
}
}
pub fn as_order_info(&self) -> Option<&OrderInfoMessage> {
match self {
StreamMessage::OrderInfo(msg) => Some(msg),
_ => None,
}
}
pub fn as_dlta_points(&self) -> Option<&DltaPointsMessage> {
match self {
StreamMessage::DltaPoints(msg) => Some(msg),
_ => None,
}
}
}