use crate::{
protocol::common::Timestamp,
types::trading::{BboCandle, Candle, CandleWidth},
InstrumentState,
};
use enumflags2::bitflags;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum MarketdataRequest<'a> {
Subscribe {
symbol: &'a str,
level: SubscriptionLevel,
},
Unsubscribe { symbol: &'a str },
#[serde(rename = "subscribe_candles")]
SubscribeCandles { symbol: &'a str, width: CandleWidth },
#[serde(rename = "unsubscribe_candles")]
UnsubscribeCandles { symbol: &'a str, width: CandleWidth },
#[serde(rename = "subscribe_bbo_candles")]
SubscribeBboCandles { symbol: &'a str, width: CandleWidth },
#[serde(rename = "unsubscribe_bbo_candles")]
UnsubscribeBboCandles { symbol: &'a str, width: CandleWidth },
}
#[bitflags]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum SubscriptionLevel {
#[serde(rename = "LEVEL_1")]
Level1 = 0b001,
#[serde(rename = "LEVEL_2")]
Level2 = 0b010,
#[serde(rename = "LEVEL_3")]
Level3 = 0b100,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "t")]
pub enum MarketdataEvent {
#[serde(rename = "h")]
Heartbeat(Timestamp),
#[serde(rename = "s")]
Ticker(Ticker),
#[serde(rename = "1")]
L1BookUpdate(L1BookUpdate),
#[serde(rename = "2")]
L2BookUpdate(L2BookUpdate),
#[serde(rename = "3")]
L3BookUpdate(L3BookUpdate),
#[serde(rename = "t")]
Trade(Trade),
#[serde(rename = "c")]
Candle(Candle),
#[serde(rename = "bc")]
BboCandle(BboCandle),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Ticker {
#[serde(flatten)]
pub timestamp: Timestamp,
#[serde(rename = "s")]
pub symbol: String,
#[serde(rename = "p")]
pub last_trade_price: Option<Decimal>,
#[serde(rename = "q")]
pub last_trade_quantity: u64,
#[serde(rename = "o")]
pub session_open_price: Option<Decimal>,
#[serde(rename = "l")]
pub session_low_price: Option<Decimal>,
#[serde(rename = "h")]
pub session_high_price: Option<Decimal>,
#[serde(rename = "v")]
pub total_volume: u64,
#[serde(rename = "oi")]
pub open_interest: u64,
#[serde(rename = "i")]
#[serde(default)]
pub instrument_state: InstrumentState,
#[serde(rename = "m")]
pub mark_price: Decimal,
#[serde(rename = "bp")]
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub bid_price: Option<Decimal>,
#[serde(rename = "ap")]
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub ask_price: Option<Decimal>,
#[serde(rename = "pl")]
pub price_band_lower_limit: Option<Decimal>,
#[serde(rename = "pu")]
pub price_band_upper_limit: Option<Decimal>,
#[serde(rename = "lsp")]
#[serde(default)]
pub last_settlement_price: Option<Decimal>,
#[serde(rename = "lst")]
#[serde(default)]
pub last_settlement_time: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BookUpdateData<Snapshot = (), Level = L2BookLevel> {
#[serde(flatten)]
pub timestamp: Timestamp,
#[serde(rename = "s")]
pub symbol: String,
#[serde(rename = "b")]
pub bids: Vec<Level>,
#[serde(rename = "a")]
pub asks: Vec<Level>,
#[serde(flatten)]
pub snapshot: Snapshot,
}
pub type L1BookUpdate = BookUpdateData<()>;
pub type L2BookUpdate = BookUpdateData<SnapshotFlag>;
pub type L3BookUpdate = BookUpdateData<SnapshotFlag, L3BookLevel>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SnapshotFlag {
#[serde(rename = "st")]
pub is_snapshot: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L2BookLevel {
#[serde(rename = "p")]
pub price: Decimal,
#[serde(rename = "q")]
pub quantity: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct L3BookLevel {
#[serde(rename = "p")]
pub price: Decimal,
#[serde(rename = "q")]
pub quantity: u64,
#[serde(rename = "o")]
pub order_quantities: Vec<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Trade {
#[serde(rename = "p")]
pub price: Decimal,
#[serde(rename = "q")]
pub quantity: u64,
#[serde(rename = "s")]
pub symbol: String,
#[serde(rename = "d")]
pub taker_side: crate::types::trading::Side,
#[serde(flatten)]
pub timestamp: Timestamp,
}