use super::OrderStatus;
use crate::shared::{
serde_util, OrderBookId, OrderUpdateType, PubkeyStr, Side, TimeInForce, TriggerResultStatus,
TriggerStatus, TriggerType, TriggerUpdateType,
};
use chrono::{DateTime, Utc};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConditionalBalance {
pub outcome_index: i16,
#[serde(alias = "conditional_token")]
pub mint: PubkeyStr,
pub idle: Decimal,
pub on_book: Decimal,
}
#[derive(Deserialize, Debug, Clone)]
pub struct UserBalanceUpdate {
pub market_pubkey: PubkeyStr,
pub orderbook_id: OrderBookId,
pub balance: BalanceUpdateOutcomes,
pub timestamp: DateTime<Utc>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct BalanceUpdateOutcomes {
pub outcomes: Vec<ConditionalBalance>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct UserSnapshotBalance {
pub market_pubkey: PubkeyStr,
pub orderbook_id: OrderBookId,
pub outcomes: Vec<ConditionalBalance>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct GlobalDepositBalance {
pub mint: PubkeyStr,
pub balance: Decimal,
}
#[derive(Deserialize, Debug, Clone)]
pub struct GlobalDepositUpdate {
pub mint: PubkeyStr,
pub balance: Decimal,
pub timestamp: DateTime<Utc>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct NonceUpdate {
pub user_pubkey: PubkeyStr,
pub new_nonce: u64,
pub timestamp: DateTime<Utc>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct OrderUpdate {
pub market_pubkey: PubkeyStr,
pub orderbook_id: OrderBookId,
pub timestamp: DateTime<Utc>,
pub tx_signature: Option<String>,
#[serde(rename = "type", default)]
pub update_type: OrderUpdateType,
pub order: WsOrder,
}
#[derive(Deserialize, Debug, Clone)]
pub struct WsOrder {
pub order_hash: String,
pub price: Decimal,
pub is_maker: bool,
pub remaining: Decimal,
pub filled: Decimal,
pub fill_amount: Decimal,
pub side: Side,
#[serde(with = "serde_util::timestamp_ms")]
pub created_at: DateTime<Utc>,
pub base_mint: PubkeyStr,
pub quote_mint: PubkeyStr,
pub outcome_index: i16,
#[serde(default)]
pub status: OrderStatus,
#[serde(default)]
pub balance: Option<UserOrderUpdateBalance>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct UserSnapshotOrderCommon {
pub order_hash: String,
pub market_pubkey: PubkeyStr,
pub orderbook_id: OrderBookId,
pub side: Side,
#[serde(alias = "maker_amount")]
pub amount_in: Decimal,
#[serde(alias = "taker_amount")]
pub amount_out: Decimal,
#[serde(default)]
pub remaining: Decimal,
#[serde(default)]
pub filled: Decimal,
#[serde(default)]
pub price: Decimal,
#[serde(with = "serde_util::timestamp_ms")]
pub created_at: DateTime<Utc>,
#[serde(default)]
pub expiration: u64,
pub base_mint: PubkeyStr,
pub quote_mint: PubkeyStr,
pub outcome_index: i16,
#[serde(default)]
pub status: OrderStatus,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "order_type", rename_all = "lowercase")]
pub enum UserSnapshotOrder {
Limit {
#[serde(flatten)]
common: UserSnapshotOrderCommon,
#[serde(default)]
tx_signature: Option<String>,
},
Trigger {
#[serde(flatten)]
common: UserSnapshotOrderCommon,
trigger_order_id: String,
trigger_price: Decimal,
trigger_type: TriggerType,
#[serde(
default,
with = "serde_util::tif_numeric_opt",
skip_serializing_if = "Option::is_none"
)]
time_in_force: Option<TimeInForce>,
},
}
impl UserSnapshotOrder {
pub fn common(&self) -> &UserSnapshotOrderCommon {
match self {
UserSnapshotOrder::Limit { common, .. } => common,
UserSnapshotOrder::Trigger { common, .. } => common,
}
}
}
#[derive(Deserialize, Debug, Clone)]
pub struct UserOrderUpdateBalance {
pub outcomes: Vec<ConditionalBalance>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct UserSnapshot {
pub orders: Vec<UserSnapshotOrder>,
pub balances: std::collections::HashMap<OrderBookId, UserSnapshotBalance>,
#[serde(default)]
pub global_deposits: Vec<GlobalDepositBalance>,
#[serde(default)]
pub notifications: Vec<crate::domain::notification::Notification>,
#[serde(default)]
pub nonce: u64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct TriggerOrderUpdate {
pub trigger_order_id: String,
#[serde(default)]
pub user_pubkey: PubkeyStr,
pub market_pubkey: PubkeyStr,
pub orderbook_id: OrderBookId,
pub trigger_price: Decimal,
pub trigger_above: bool,
pub status: TriggerStatus,
#[serde(rename = "type", default)]
pub update_type: TriggerUpdateType,
pub order_hash: String,
pub side: Side,
#[serde(default, with = "serde_util::empty_string_as_none")]
pub result_status: Option<TriggerResultStatus>,
#[serde(default)]
pub result_filled: Decimal,
#[serde(default)]
pub result_remaining: Decimal,
pub timestamp: DateTime<Utc>,
#[serde(default)]
pub maker_amount: Decimal,
#[serde(default)]
pub taker_amount: Decimal,
#[serde(default, with = "serde_util::tif_numeric")]
pub tif: TimeInForce,
}
#[cfg(feature = "trigger_orders")]
impl TriggerOrderUpdate {
pub fn into_trigger_order(self) -> super::TriggerOrder {
let trigger_type = if self.trigger_above {
TriggerType::TakeProfit
} else {
TriggerType::StopLoss
};
super::TriggerOrder {
trigger_order_id: self.trigger_order_id,
order_hash: self.order_hash,
market_pubkey: self.market_pubkey,
orderbook_id: self.orderbook_id,
trigger_price: self.trigger_price,
trigger_type,
side: self.side,
amount_in: self.maker_amount,
amount_out: self.taker_amount,
time_in_force: self.tif,
created_at: self.timestamp,
}
}
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "order_type")]
pub enum OrderEvent {
#[serde(rename = "limit")]
Limit(OrderUpdate),
#[serde(rename = "trigger")]
Trigger(TriggerOrderUpdate),
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "event_type")]
pub enum UserUpdate {
#[serde(rename = "snapshot")]
Snapshot(UserSnapshot),
#[serde(rename = "order")]
Order(OrderEvent),
#[serde(rename = "balance_update")]
BalanceUpdate(UserBalanceUpdate),
#[serde(rename = "global_deposit_update")]
GlobalDepositUpdate(GlobalDepositUpdate),
#[serde(rename = "nonce")]
NonceUpdate(NonceUpdate),
#[serde(rename = "notification")]
Notification(NotificationUpdate),
}
#[derive(Deserialize, Debug, Clone)]
pub struct NotificationUpdate {
pub notification: crate::domain::notification::Notification,
}
#[derive(Deserialize, Debug, Clone)]
pub struct Authenticated {
pub wallet: PubkeyStr,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "status")]
pub enum AuthUpdate {
#[serde(rename = "authenticated")]
Authenticated(Authenticated),
#[serde(rename = "anonymous")]
Anonymous {
#[serde(default)]
reason: Option<String>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct UserOrderFillsResponse {
pub orders: Vec<UserOrderFill>,
pub next_cursor: Option<String>,
pub has_more: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct UserOrderFill {
pub order_hash: String,
pub market_pubkey: PubkeyStr,
pub orderbook_id: OrderBookId,
pub side: Side,
pub role: Role,
pub price: Decimal,
pub size: Decimal,
pub filled_size: Decimal,
pub remaining_size: Decimal,
pub base_mint: PubkeyStr,
pub quote_mint: PubkeyStr,
pub outcome_index: i16,
pub status: FillStatus,
#[serde(with = "serde_util::timestamp_ms")]
pub created_at: DateTime<Utc>,
pub fills: Vec<OrderFillEvent>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OrderFillEvent {
pub fill_amount: Decimal,
pub tx_signature: String,
#[serde(with = "serde_util::timestamp_ms")]
pub filled_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Role {
Maker,
Taker,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum FillStatus {
Filled,
Cancelled,
PartiallyFilled,
}