use crate::AlgoState;
pub mod OrderType {
pub const LIMIT: u8 = 0;
pub const MARKET: u8 = 1;
pub const IOC: u8 = 2;
pub const FOK: u8 = 3;
pub const POST_ONLY: u8 = 4;
}
pub const ACTION_NEW: u8 = 0;
pub const ACTION_CANCEL: u8 = 1;
pub const ACTION_AMEND: u8 = 2;
pub const ACTION_INTENT: u8 = 3;
pub mod IntentPolicy {
pub const IOC_SWEEP: u8 = 0;
pub const AGGRESSIVE_CHASE: u8 = 1;
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Action {
pub order_id: u64,
pub px_1e9: u64,
pub qty_1e8: i64,
pub side: i8, pub is_cancel: u8,
pub order_type: u8, pub venue_id: u8, pub pool_idx: u8, pub symbol_idx: u8, pub _pad: [u8; 2],
}
pub const MAX_ACTIONS: usize = 16;
#[repr(C)]
pub struct Actions {
actions: [Action; MAX_ACTIONS],
len: usize,
}
impl Actions {
#[inline(always)]
pub const fn new() -> Self {
Self {
actions: [Action {
order_id: 0,
px_1e9: 0,
qty_1e8: 0,
side: 0,
is_cancel: 0,
order_type: 0,
venue_id: 0,
pool_idx: 0,
symbol_idx: 0,
_pad: [0; 2],
}; MAX_ACTIONS],
len: 0,
}
}
#[inline(always)]
pub fn clear(&mut self) {
self.len = 0;
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub fn is_full(&self) -> bool {
self.len >= MAX_ACTIONS
}
#[inline(always)]
pub fn buy(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, 1, qty_1e8, px_1e9, OrderType::LIMIT)
}
#[inline(always)]
pub fn sell(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, -1, qty_1e8, px_1e9, OrderType::LIMIT)
}
#[inline(always)]
pub fn order(&mut self, order_id: u64, side: i8, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, side, qty_1e8, px_1e9, OrderType::LIMIT)
}
#[inline(always)]
pub fn market_buy(&mut self, order_id: u64, qty_1e8: i64) -> bool {
self.order_typed(order_id, 1, qty_1e8, 0, OrderType::MARKET)
}
#[inline(always)]
pub fn market_sell(&mut self, order_id: u64, qty_1e8: i64) -> bool {
self.order_typed(order_id, -1, qty_1e8, 0, OrderType::MARKET)
}
#[inline(always)]
pub fn ioc_buy(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, 1, qty_1e8, px_1e9, OrderType::IOC)
}
#[inline(always)]
pub fn ioc_sell(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, -1, qty_1e8, px_1e9, OrderType::IOC)
}
#[inline(always)]
pub fn fok_buy(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, 1, qty_1e8, px_1e9, OrderType::FOK)
}
#[inline(always)]
pub fn fok_sell(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, -1, qty_1e8, px_1e9, OrderType::FOK)
}
#[inline(always)]
pub fn post_only_buy(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, 1, qty_1e8, px_1e9, OrderType::POST_ONLY)
}
#[inline(always)]
pub fn post_only_sell(&mut self, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
self.order_typed(order_id, -1, qty_1e8, px_1e9, OrderType::POST_ONLY)
}
#[inline(always)]
pub fn order_typed(
&mut self,
order_id: u64,
side: i8,
qty_1e8: i64,
px_1e9: u64,
order_type: u8,
) -> bool {
if self.len >= MAX_ACTIONS {
return false;
}
self.actions[self.len] = Action {
order_id,
px_1e9,
qty_1e8,
side,
is_cancel: 0,
order_type,
venue_id: 0,
pool_idx: 0,
symbol_idx: 0,
_pad: [0; 2],
};
self.len += 1;
true
}
#[inline(always)]
pub fn cancel(&mut self, order_id: u64) -> bool {
if self.len >= MAX_ACTIONS {
return false;
}
self.actions[self.len] = Action {
order_id,
px_1e9: 0,
qty_1e8: 0,
side: 0,
is_cancel: 1,
order_type: 0,
venue_id: 0,
pool_idx: 0,
symbol_idx: 0,
_pad: [0; 2],
};
self.len += 1;
true
}
#[inline(always)]
pub fn cancel_all(&mut self, state: &AlgoState) {
for i in 0..state.order_ct as usize {
let o = &state.orders[i];
if o.is_live() && self.len < MAX_ACTIONS {
self.cancel(o.order_id);
}
}
}
#[inline(always)]
pub fn amend(&mut self, order_id: u64, new_qty_1e8: i64, new_px_1e9: u64) -> bool {
if self.len >= MAX_ACTIONS {
return false;
}
self.actions[self.len] = Action {
order_id,
px_1e9: new_px_1e9,
qty_1e8: new_qty_1e8,
side: 0, is_cancel: ACTION_AMEND,
order_type: 0,
venue_id: 0,
pool_idx: 0,
symbol_idx: 0,
_pad: [0; 2],
};
self.len += 1;
true
}
#[inline(always)]
pub fn intent(
&mut self,
intent_id: u64,
venue_id: u8,
side: i8,
qty_1e8: i64,
limit_px_1e9: u64,
policy: u8,
ttl_ms: u16,
) -> bool {
if self.len >= MAX_ACTIONS {
return false;
}
let ttl_bytes = ttl_ms.to_le_bytes();
self.actions[self.len] = Action {
order_id: intent_id,
px_1e9: limit_px_1e9,
qty_1e8,
side,
is_cancel: ACTION_INTENT,
order_type: policy,
venue_id,
pool_idx: 0,
symbol_idx: 0,
_pad: ttl_bytes,
};
self.len += 1;
true
}
pub fn buy_symbol(&mut self, symbol_idx: u8, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
if self.len >= MAX_ACTIONS { return false; }
self.actions[self.len] = Action {
order_id, px_1e9, qty_1e8, side: 1,
is_cancel: 0, order_type: 0, venue_id: 0, pool_idx: 0,
symbol_idx, _pad: [0; 2],
};
self.len += 1;
true
}
pub fn sell_symbol(&mut self, symbol_idx: u8, order_id: u64, qty_1e8: i64, px_1e9: u64) -> bool {
if self.len >= MAX_ACTIONS { return false; }
self.actions[self.len] = Action {
order_id, px_1e9, qty_1e8, side: -1,
is_cancel: 0, order_type: 0, venue_id: 0, pool_idx: 0,
symbol_idx, _pad: [0; 2],
};
self.len += 1;
true
}
#[inline(always)]
pub fn clear_at(&mut self, idx: usize) {
if idx < self.len {
self.actions[idx] = Action {
order_id: 0,
px_1e9: 0,
qty_1e8: 0,
side: 0,
is_cancel: 0,
order_type: 0,
venue_id: 0,
pool_idx: 0,
symbol_idx: 0,
_pad: [0; 2],
};
}
}
#[inline(always)]
pub fn get(&self, idx: usize) -> Option<&Action> {
if idx < self.len {
Some(&self.actions[idx])
} else {
None
}
}
#[inline(always)]
pub fn iter(&self) -> impl Iterator<Item = &Action> {
self.actions[..self.len].iter()
}
}
impl Default for Actions {
fn default() -> Self {
Self::new()
}
}
#[repr(C)]
pub struct WasmActions {
pub count: u32,
pub _pad: u32,
pub actions: [Action; MAX_ACTIONS],
}
impl WasmActions {
pub const fn new() -> Self {
Self {
count: 0,
_pad: 0,
actions: [Action {
order_id: 0,
px_1e9: 0,
qty_1e8: 0,
side: 0,
is_cancel: 0,
order_type: 0,
venue_id: 0,
pool_idx: 0,
symbol_idx: 0,
_pad: [0; 2],
}; MAX_ACTIONS],
}
}
pub fn from_actions(&mut self, actions: &Actions) {
self.count = actions.len() as u32;
for i in 0..actions.len() {
self.actions[i] = actions.actions[i];
}
}
}