use serde::{Deserialize, Deserializer, Serialize};
fn deserialize_number_or_string<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
where
D: Deserializer<'de>,
{
struct NumberOrString;
impl<'de> serde::de::Visitor<'de> for NumberOrString {
type Value = String;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a number or string")
}
fn visit_f64<E: serde::de::Error>(self, v: f64) -> std::result::Result<String, E> {
Ok(v.to_string())
}
fn visit_u64<E: serde::de::Error>(self, v: u64) -> std::result::Result<String, E> {
Ok(v.to_string())
}
fn visit_i64<E: serde::de::Error>(self, v: i64) -> std::result::Result<String, E> {
Ok(v.to_string())
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> std::result::Result<String, E> {
Ok(v.to_owned())
}
fn visit_string<E: serde::de::Error>(self, v: String) -> std::result::Result<String, E> {
Ok(v)
}
}
deserializer.deserialize_any(NumberOrString)
}
#[derive(Debug, Clone, Deserialize)]
pub struct ApiMeta {
pub count: usize,
pub request_id: String,
pub next_cursor: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub(crate) struct ApiEnvelope<T> {
pub data: T,
pub meta: Option<ApiMeta>,
}
#[derive(Debug, Clone)]
pub struct CursorResponse<T> {
pub data: T,
pub next_cursor: Option<String>,
}
#[derive(Debug, Clone)]
pub enum Timestamp {
Millis(i64),
Iso(String),
DateTime(chrono::DateTime<chrono::Utc>),
}
impl Timestamp {
pub fn to_millis(&self) -> i64 {
match self {
Timestamp::Millis(ms) => *ms,
Timestamp::DateTime(dt) => dt.timestamp_millis(),
Timestamp::Iso(s) => chrono::DateTime::parse_from_rfc3339(s)
.map(|dt| dt.timestamp_millis())
.unwrap_or_else(|_| s.parse::<i64>().unwrap_or(0)),
}
}
}
impl From<i64> for Timestamp {
fn from(ms: i64) -> Self {
Timestamp::Millis(ms)
}
}
impl From<&str> for Timestamp {
fn from(s: &str) -> Self {
Timestamp::Iso(s.to_string())
}
}
impl From<String> for Timestamp {
fn from(s: String) -> Self {
Timestamp::Iso(s)
}
}
impl From<chrono::DateTime<chrono::Utc>> for Timestamp {
fn from(dt: chrono::DateTime<chrono::Utc>) -> Self {
Timestamp::DateTime(dt)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriceLevel {
pub px: String,
pub sz: String,
pub n: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderBook {
pub coin: String,
pub timestamp: String,
pub bids: Vec<PriceLevel>,
pub asks: Vec<PriceLevel>,
pub mid_price: Option<String>,
pub spread: Option<String>,
pub spread_bps: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Trade {
pub coin: String,
pub side: String,
pub price: String,
pub size: String,
pub timestamp: String,
pub tx_hash: Option<String>,
pub trade_id: Option<i64>,
pub order_id: Option<i64>,
pub crossed: Option<bool>,
pub fee: Option<String>,
pub fee_token: Option<String>,
pub closed_pnl: Option<String>,
pub direction: Option<String>,
pub start_position: Option<String>,
pub user_address: Option<String>,
pub maker_address: Option<String>,
pub taker_address: Option<String>,
pub builder_address: Option<String>,
pub builder_fee: Option<String>,
pub deployer_fee: Option<String>,
pub priority_gas: Option<f64>,
pub cloid: Option<String>,
pub twap_id: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Instrument {
pub name: String,
pub sz_decimals: i32,
pub max_leverage: Option<i32>,
pub only_isolated: Option<bool>,
pub instrument_type: Option<String>,
pub is_active: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LighterInstrument {
pub symbol: String,
pub market_id: i64,
pub market_type: Option<String>,
pub status: Option<String>,
pub taker_fee: Option<f64>,
pub maker_fee: Option<f64>,
pub liquidation_fee: Option<f64>,
pub min_base_amount: Option<f64>,
pub min_quote_amount: Option<f64>,
pub size_decimals: Option<i32>,
pub price_decimals: Option<i32>,
pub quote_decimals: Option<i32>,
pub is_active: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Hip3Instrument {
pub coin: String,
pub namespace: Option<String>,
pub ticker: Option<String>,
pub mark_price: Option<f64>,
pub open_interest: Option<f64>,
pub mid_price: Option<f64>,
pub latest_timestamp: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FundingRate {
pub coin: String,
pub timestamp: String,
pub funding_rate: String,
pub premium: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenInterest {
pub coin: String,
pub timestamp: String,
pub open_interest: String,
pub mark_price: Option<String>,
pub oracle_price: Option<String>,
pub day_ntl_volume: Option<String>,
pub prev_day_price: Option<String>,
pub mid_price: Option<String>,
pub impact_bid_price: Option<String>,
pub impact_ask_price: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Candle {
pub timestamp: String,
pub open: String,
pub high: String,
pub low: String,
pub close: String,
pub volume: String,
pub quote_volume: Option<String>,
pub trade_count: Option<i64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CandleInterval {
OneMinute,
FiveMinutes,
FifteenMinutes,
ThirtyMinutes,
OneHour,
FourHours,
OneDay,
OneWeek,
}
impl CandleInterval {
pub fn as_str(&self) -> &'static str {
match self {
CandleInterval::OneMinute => "1m",
CandleInterval::FiveMinutes => "5m",
CandleInterval::FifteenMinutes => "15m",
CandleInterval::ThirtyMinutes => "30m",
CandleInterval::OneHour => "1h",
CandleInterval::FourHours => "4h",
CandleInterval::OneDay => "1d",
CandleInterval::OneWeek => "1w",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Liquidation {
pub coin: String,
pub timestamp: String,
pub liquidated_user: String,
pub liquidator_user: Option<String>,
pub price: String,
pub size: String,
pub side: String,
pub mark_price: Option<String>,
pub closed_pnl: Option<String>,
pub direction: Option<String>,
pub trade_id: Option<i64>,
pub tx_hash: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LiquidationVolume {
pub coin: String,
pub timestamp: String,
#[serde(deserialize_with = "deserialize_number_or_string")]
pub total_usd: String,
#[serde(deserialize_with = "deserialize_number_or_string")]
pub long_usd: String,
#[serde(deserialize_with = "deserialize_number_or_string")]
pub short_usd: String,
pub count: i64,
pub long_count: i64,
pub short_count: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OiFundingInterval {
FiveMinutes,
FifteenMinutes,
ThirtyMinutes,
OneHour,
FourHours,
OneDay,
}
impl OiFundingInterval {
pub fn as_str(&self) -> &'static str {
match self {
OiFundingInterval::FiveMinutes => "5m",
OiFundingInterval::FifteenMinutes => "15m",
OiFundingInterval::ThirtyMinutes => "30m",
OiFundingInterval::OneHour => "1h",
OiFundingInterval::FourHours => "4h",
OiFundingInterval::OneDay => "1d",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LighterGranularity {
Checkpoint,
ThirtySeconds,
TenSeconds,
OneSecond,
Tick,
}
impl LighterGranularity {
pub fn as_str(&self) -> &'static str {
match self {
LighterGranularity::Checkpoint => "checkpoint",
LighterGranularity::ThirtySeconds => "30s",
LighterGranularity::TenSeconds => "10s",
LighterGranularity::OneSecond => "1s",
LighterGranularity::Tick => "tick",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataTypeFreshness {
pub last_updated: Option<String>,
pub lag_ms: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoinFreshness {
pub coin: String,
pub exchange: Option<String>,
pub measured_at: Option<String>,
#[serde(flatten)]
pub data_types: std::collections::HashMap<String, DataTypeFreshness>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoinSummary {
pub coin: String,
pub mark_price: Option<String>,
pub mid_price: Option<String>,
pub oracle_price: Option<String>,
pub open_interest: Option<String>,
pub funding_rate: Option<String>,
pub day_ntl_volume: Option<String>,
#[serde(flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriceSnapshot {
pub timestamp: String,
pub mark_price: Option<String>,
pub oracle_price: Option<String>,
pub mid_price: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatusResponse {
pub status: String,
pub updated_at: Option<String>,
#[serde(default)]
pub exchanges: std::collections::HashMap<String, serde_json::Value>,
#[serde(default)]
pub data_types: std::collections::HashMap<String, serde_json::Value>,
pub active_incidents: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoverageResponse {
pub exchanges: Vec<ExchangeCoverage>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExchangeCoverage {
pub exchange: String,
#[serde(default)]
pub data_types: std::collections::HashMap<String, DataTypeCoverage>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataTypeCoverage {
pub earliest: Option<String>,
pub latest: Option<String>,
pub total_records: Option<i64>,
pub completeness: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolCoverageResponse {
pub exchange: String,
pub symbol: String,
#[serde(default)]
pub data_types: std::collections::HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Incident {
pub id: String,
pub status: String,
pub severity: String,
pub exchange: Option<String>,
#[serde(default)]
pub data_types: Vec<String>,
#[serde(default)]
pub symbols_affected: Vec<String>,
pub started_at: String,
pub resolved_at: Option<String>,
pub duration_minutes: Option<f64>,
pub title: String,
pub description: Option<String>,
pub root_cause: Option<String>,
pub resolution: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncidentsResponse {
pub incidents: Vec<Incident>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LatencyResponse {
pub measured_at: Option<String>,
#[serde(default)]
pub exchanges: std::collections::HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SlaResponse {
pub period: Option<String>,
#[serde(default, flatten)]
pub extra: std::collections::HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SiweChallenge {
pub message: String,
pub nonce: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Web3SignupResult {
pub api_key: String,
pub tier: String,
pub wallet_address: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Web3ApiKey {
pub id: String,
pub name: Option<String>,
pub key_prefix: String,
pub is_active: bool,
pub created_at: String,
pub last_used_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Web3KeysList {
pub keys: Vec<Web3ApiKey>,
pub wallet_address: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Web3RevokeResult {
pub message: String,
pub wallet_address: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Web3PaymentRequired {
pub amount: String,
pub asset: String,
pub network: String,
pub pay_to: String,
pub asset_address: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Web3SubscribeResult {
pub api_key: Option<String>,
pub tier: String,
pub expires_at: Option<String>,
pub wallet_address: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderbookDelta {
pub timestamp: i64,
pub side: String,
pub price: f64,
pub size: f64,
pub sequence: i64,
}
#[derive(Debug, Clone)]
pub struct TickData {
pub checkpoint: OrderBook,
pub deltas: Vec<OrderbookDelta>,
}
#[derive(Debug, Clone)]
pub struct ReconstructedOrderBook {
pub coin: String,
pub timestamp: String,
pub bids: Vec<PriceLevel>,
pub asks: Vec<PriceLevel>,
pub mid_price: Option<String>,
pub spread: Option<String>,
pub spread_bps: Option<String>,
pub sequence: Option<i64>,
}
#[derive(Debug, Clone)]
pub struct ReconstructOptions {
pub depth: Option<usize>,
pub emit_all: bool,
}
impl Default for ReconstructOptions {
fn default() -> Self {
Self {
depth: None,
emit_all: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L4OrderEntry {
pub oid: u64,
pub user_address: String,
pub side: String,
pub price: f64,
pub size: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L4OrderBookSnapshot {
pub coin: String,
pub timestamp: String,
pub checkpoint_timestamp: String,
pub diffs_applied: u64,
pub last_block_number: u64,
pub bid_count: usize,
pub ask_count: usize,
pub total_bid_size: f64,
pub total_ask_size: f64,
pub bids: Vec<L4OrderEntry>,
pub asks: Vec<L4OrderEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L4DiffEntry {
pub coin: String,
pub timestamp: String,
pub block_number: u64,
pub oid: u64,
pub side: String,
pub price: f64,
pub diff_type: String,
pub new_size: Option<f64>,
pub user_address: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L2PriceLevel {
pub px: f64,
pub sz: f64,
pub n: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L2OrderBookSnapshot {
pub coin: String,
pub timestamp: String,
pub bid_levels: usize,
pub ask_levels: usize,
pub total_bid_size: f64,
pub total_ask_size: f64,
pub mid_price: Option<f64>,
pub spread: Option<f64>,
pub spread_bps: Option<f64>,
pub bids: Vec<L2PriceLevel>,
pub asks: Vec<L2PriceLevel>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L2DiffEntry {
pub timestamp: String,
pub block_number: u64,
pub side: String,
pub price: f64,
pub size: f64,
pub count: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderHistoryEntry {
pub coin: String,
pub timestamp: String,
pub block_number: u64,
pub block_time: String,
pub oid: u64,
pub user_address: String,
pub side: String,
pub limit_price: f64,
pub size: f64,
pub orig_size: f64,
pub status: String,
pub order_type: String,
pub tif: String,
pub reduce_only: bool,
pub is_trigger: bool,
pub is_position_tpsl: bool,
pub cloid: Option<String>,
}