use arrayvec::ArrayString;
use jiff::Timestamp;
use smart_default::SmartDefault;
use uuid::Uuid;
use v_utils::{arch::ComponentState, trades::Side};
use crate::Ticker;
#[derive(Clone, Debug, derive_more::Deref, derive_more::DerefMut, PartialEq, derive_new::new)]
pub struct ExchangeOrder<O> {
#[deref]
#[deref_mut]
pub order: O,
pub ticker: Ticker,
#[new(default)]
pub expected_fee_usd: Option<f64>,
}
impl<O: Eq> Eq for ExchangeOrder<O> {}
impl<O: std::hash::Hash> std::hash::Hash for ExchangeOrder<O> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.order.hash(state);
self.ticker.hash(state);
self.expected_fee_usd.map(f64::to_bits).hash(state);
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, SmartDefault)]
pub struct OrderId {
#[default(Uuid::now_v7())]
pub id: Uuid,
pub parent: Option<Uuid>,
pub exchange_id: Option<ArrayString<32>>,
}
#[derive(Clone, Debug, PartialEq, derive_new::new)]
pub struct LimitOrder {
pub side: Side,
pub price: f64,
pub qty: f64, #[new(value = "TimeInForce::Gtc")]
pub time_in_force: TimeInForce,
#[new(default)]
pub post_only: bool,
#[new(default)]
pub reduce_only: bool,
#[new(default)]
pub display_qty: Option<f64>,
#[new(default)]
pub trigger: Option<Trigger>,
#[new(default)]
pub stp: Option<SelfTradePreventionMode>,
#[new(default)]
pub order_id: OrderId,
#[new(default)]
pub contingency: Option<Contingency>,
#[new(default)]
pub tags: Vec<ArrayString<32>>,
}
impl Eq for LimitOrder {}
impl std::hash::Hash for LimitOrder {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.side.hash(state);
self.price.to_bits().hash(state);
self.qty.to_bits().hash(state);
self.time_in_force.hash(state);
self.post_only.hash(state);
self.reduce_only.hash(state);
self.display_qty.map(f64::to_bits).hash(state);
self.trigger.hash(state);
self.stp.hash(state);
self.order_id.hash(state);
self.contingency.hash(state);
self.tags.hash(state);
}
}
#[derive(Clone, Debug, derive_new::new)]
pub struct MarketOrder {
pub side: Side,
pub qty: f64,
#[new(default)]
pub reduce_only: bool,
#[new(default)]
pub stp: Option<SelfTradePreventionMode>,
#[new(default)]
pub order_id: OrderId,
}
#[derive(Clone, Debug, derive_new::new)]
pub struct StopLimitOrder {
pub side: Side,
pub price: f64,
pub qty: f64,
pub trigger: Trigger,
#[new(value = "TimeInForce::Gtc")]
pub time_in_force: TimeInForce,
#[new(default)]
pub reduce_only: bool,
#[new(default)]
pub close_position: bool,
#[new(default)]
pub stp: Option<SelfTradePreventionMode>,
#[new(default)]
pub order_id: OrderId,
}
#[derive(Clone, Debug, derive_new::new)]
pub struct StopMarketOrder {
pub side: Side,
pub qty: f64,
pub trigger: Trigger,
#[new(default)]
pub reduce_only: bool,
#[new(default)]
pub close_position: bool,
#[new(default)]
pub stp: Option<SelfTradePreventionMode>,
#[new(default)]
pub order_id: OrderId,
}
#[derive(Clone, Debug, derive_new::new)]
pub struct TrailingStopOrder {
pub side: Side,
pub qty: f64,
pub callback: TrailingCallback,
#[new(default)]
pub activation_price: Option<f64>,
#[new(default)]
pub trigger_price_type: TriggerPriceType,
#[new(default)]
pub reduce_only: bool,
#[new(default)]
pub stp: Option<SelfTradePreventionMode>,
#[new(default)]
pub order_id: OrderId,
}
#[derive(Clone, Debug, PartialEq, derive_new::new)]
pub struct Trigger {
pub price: f64,
#[new(default)]
pub price_type: TriggerPriceType,
}
impl Trigger {
pub fn last(price: f64) -> Self {
Self {
price,
price_type: TriggerPriceType::Last,
}
}
pub fn mark(price: f64) -> Self {
Self {
price,
price_type: TriggerPriceType::Mark,
}
}
pub fn index(price: f64) -> Self {
Self {
price,
price_type: TriggerPriceType::Index,
}
}
}
impl Eq for Trigger {}
impl std::hash::Hash for Trigger {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.price.to_bits().hash(state);
self.price_type.hash(state);
}
}
#[derive(Clone, Copy, Debug, Default, strum::Display, Eq, Hash, PartialEq)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
pub enum TriggerPriceType {
#[default]
Last,
Mark,
Index,
}
#[derive(Clone, Copy, Debug)]
pub enum TrailingCallback {
Percent(f64),
Price(f64),
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Default, derive_more::Display, Eq, Hash, PartialEq)]
pub enum TimeInForce {
#[default]
#[display("GTC")]
Gtc,
#[display("IOC")]
Ioc,
#[display("FOK")]
Fok,
#[display("AON")]
Aon,
#[display("GTD")]
Gtd(Timestamp),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Contingency {
Oco(Vec<Uuid>),
Oto(Vec<Uuid>),
}
#[derive(Clone, Copy, Debug, strum::Display, Eq, Hash, PartialEq)]
pub enum SelfTradePreventionMode {
#[strum(serialize = "EXPIRE_MAKER")]
CancelMaker,
#[strum(serialize = "EXPIRE_TAKER")]
CancelTaker,
#[strum(serialize = "EXPIRE_BOTH")]
CancelBoth,
}
#[derive(Clone, Debug, derive_new::new)]
pub struct OrderPlaced {
pub order_id: OrderId,
pub status: OrderStatus,
}
#[derive(Clone, Copy, Debug, strum::Display, Eq, PartialEq)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
pub enum OrderStatus {
New,
PartiallyFilled,
Filled,
Canceled,
Expired,
Rejected,
}