use borsh::{BorshDeserialize, BorshSerialize};
use crate::ix::types::{OrderFlags, SelfTradeBehavior, Side};
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct OrderPacket {
pub(crate) kind: OrderPacketKind,
}
impl OrderPacket {
pub fn post_only(
side: Side,
price_in_ticks: u64,
num_base_lots: u64,
client_order_id: [u8; 16],
slide: bool,
last_valid_slot: Option<u64>,
order_flags: OrderFlags,
cancel_existing: bool,
) -> Self {
Self {
kind: OrderPacketKind::PostOnly {
side,
price_in_ticks,
num_base_lots,
client_order_id,
slide,
last_valid_slot,
order_flags,
cancel_existing,
},
}
}
pub fn limit(
side: Side,
price_in_ticks: u64,
num_base_lots: u64,
self_trade_behavior: SelfTradeBehavior,
match_limit: Option<u64>,
client_order_id: [u8; 16],
last_valid_slot: Option<u64>,
order_flags: OrderFlags,
cancel_existing: bool,
) -> Self {
Self {
kind: OrderPacketKind::Limit {
side,
price_in_ticks,
num_base_lots,
self_trade_behavior,
match_limit,
client_order_id,
last_valid_slot,
order_flags,
cancel_existing,
},
}
}
pub fn immediate_or_cancel(
side: Side,
price_in_ticks: Option<u64>,
num_base_lots: u64,
num_quote_lots: Option<u64>,
min_base_lots_to_fill: u64,
min_quote_lots_to_fill: u64,
self_trade_behavior: SelfTradeBehavior,
match_limit: Option<u64>,
client_order_id: [u8; 16],
last_valid_slot: Option<u64>,
order_flags: OrderFlags,
cancel_existing: bool,
) -> Self {
Self {
kind: OrderPacketKind::ImmediateOrCancel {
side,
price_in_ticks,
num_base_lots,
num_quote_lots,
min_base_lots_to_fill,
min_quote_lots_to_fill,
self_trade_behavior,
match_limit,
client_order_id,
last_valid_slot,
order_flags,
cancel_existing,
},
}
}
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub(crate) enum OrderPacketKind {
PostOnly {
side: Side,
price_in_ticks: u64,
num_base_lots: u64,
client_order_id: [u8; 16],
slide: bool,
last_valid_slot: Option<u64>,
order_flags: OrderFlags,
cancel_existing: bool,
},
Limit {
side: Side,
price_in_ticks: u64,
num_base_lots: u64,
self_trade_behavior: SelfTradeBehavior,
match_limit: Option<u64>,
client_order_id: [u8; 16],
last_valid_slot: Option<u64>,
order_flags: OrderFlags,
cancel_existing: bool,
},
ImmediateOrCancel {
side: Side,
price_in_ticks: Option<u64>,
num_base_lots: u64,
num_quote_lots: Option<u64>,
min_base_lots_to_fill: u64,
min_quote_lots_to_fill: u64,
self_trade_behavior: SelfTradeBehavior,
match_limit: Option<u64>,
client_order_id: [u8; 16],
last_valid_slot: Option<u64>,
order_flags: OrderFlags,
cancel_existing: bool,
},
}
pub fn client_order_id_to_bytes(id: u128) -> [u8; 16] {
id.to_le_bytes()
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct CondensedOrder {
pub price_in_ticks: u64,
pub size_in_base_lots: u64,
pub last_valid_slot: Option<u64>,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct MultipleOrderPacket {
pub bids: Vec<CondensedOrder>,
pub asks: Vec<CondensedOrder>,
pub client_order_id: Option<[u8; 16]>,
pub slide: bool,
}
#[cfg(test)]
mod tests {
use borsh::to_vec;
use super::*;
#[test]
fn test_ioc_serialization_with_none_price() {
let packet = OrderPacket::immediate_or_cancel(
Side::Bid,
None, 1000,
None, 0,
0,
SelfTradeBehavior::Abort,
None, [0u8; 16],
None, OrderFlags::None,
false,
);
let bytes = to_vec(&packet.kind).unwrap();
assert_eq!(bytes[0], 2);
assert_eq!(bytes[1], 0);
assert_eq!(bytes[2], 0);
}
#[test]
fn test_ioc_serialization_with_some_price() {
let packet = OrderPacket::immediate_or_cancel(
Side::Ask,
Some(50000),
1000,
None,
0,
0,
SelfTradeBehavior::Abort,
None,
[0u8; 16],
None,
OrderFlags::None,
false,
);
let bytes = to_vec(&packet.kind).unwrap();
assert_eq!(bytes[0], 2);
assert_eq!(bytes[1], 1);
assert_eq!(bytes[2], 1);
let price_bytes = &bytes[3..11];
let price = u64::from_le_bytes(price_bytes.try_into().unwrap());
assert_eq!(price, 50000);
}
#[test]
fn test_limit_serialization() {
let packet = OrderPacket::limit(
Side::Bid,
50000,
1000,
SelfTradeBehavior::CancelProvide,
None,
[0u8; 16],
None,
OrderFlags::None,
false,
);
let bytes = to_vec(&packet.kind).unwrap();
assert_eq!(bytes[0], 1);
assert_eq!(bytes[1], 0);
}
#[test]
fn test_client_order_id_to_bytes() {
let id: u128 = 0x0102030405060708090a0b0c0d0e0f10;
let bytes = client_order_id_to_bytes(id);
assert_eq!(
bytes,
[
0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
0x02, 0x01
]
);
}
}