Perp: Reorganize fill events, add client order id to LeafNodes (#426)
- don't store internal order ids: unneeded - provide the maker client order id for user correlation - store fees as f32 to waste fewer bytes - new FillLogV2
This commit is contained in:
parent
a91a9ae998
commit
5328003183
|
@ -5,7 +5,7 @@ use crate::error::MangoError;
|
|||
use crate::state::{EventQueue, IxGate, MangoAccountFixed, MangoAccountLoader};
|
||||
use crate::state::{EventType, FillEvent, Group, OutEvent, PerpMarket};
|
||||
|
||||
use crate::logs::{emit_perp_balances, FillLog};
|
||||
use crate::logs::{emit_perp_balances, FillLogV2};
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct PerpConsumeEvents<'info> {
|
||||
|
@ -119,7 +119,7 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
&perp_market,
|
||||
);
|
||||
}
|
||||
emit!(FillLog {
|
||||
emit!(FillLogV2 {
|
||||
mango_group: group_key,
|
||||
market_index: perp_market_index,
|
||||
taker_side: fill.taker_side as u8,
|
||||
|
@ -128,13 +128,12 @@ pub fn perp_consume_events(ctx: Context<PerpConsumeEvents>, limit: usize) -> Res
|
|||
timestamp: fill.timestamp,
|
||||
seq_num: fill.seq_num,
|
||||
maker: fill.maker,
|
||||
maker_order_id: fill.maker_order_id,
|
||||
maker_fee: fill.maker_fee.to_bits(),
|
||||
maker_client_order_id: fill.maker_client_order_id,
|
||||
maker_fee: fill.maker_fee,
|
||||
maker_timestamp: fill.maker_timestamp,
|
||||
taker: fill.taker,
|
||||
taker_order_id: fill.taker_order_id,
|
||||
taker_client_order_id: fill.taker_client_order_id,
|
||||
taker_fee: fill.taker_fee.to_bits(),
|
||||
taker_fee: fill.taker_fee,
|
||||
price: fill.price,
|
||||
quantity: fill.quantity,
|
||||
});
|
||||
|
|
|
@ -112,6 +112,31 @@ pub struct FillLog {
|
|||
pub quantity: i64, // number of base lots
|
||||
}
|
||||
|
||||
#[event]
|
||||
pub struct FillLogV2 {
|
||||
pub mango_group: Pubkey,
|
||||
pub market_index: u16,
|
||||
pub taker_side: u8, // side from the taker's POV
|
||||
pub maker_slot: u8,
|
||||
pub maker_out: bool, // true if maker order quantity == 0
|
||||
pub timestamp: u64,
|
||||
pub seq_num: u64, // note: usize same as u64
|
||||
|
||||
pub maker: Pubkey,
|
||||
pub maker_client_order_id: u64,
|
||||
pub maker_fee: f32,
|
||||
|
||||
// Timestamp of when the maker order was placed; copied over from the LeafNode
|
||||
pub maker_timestamp: u64,
|
||||
|
||||
pub taker: Pubkey,
|
||||
pub taker_client_order_id: u64,
|
||||
pub taker_fee: f32,
|
||||
|
||||
pub price: i64,
|
||||
pub quantity: i64, // number of base lots
|
||||
}
|
||||
|
||||
#[event]
|
||||
pub struct PerpUpdateFundingLog {
|
||||
pub mango_group: Pubkey,
|
||||
|
|
|
@ -898,7 +898,7 @@ impl<
|
|||
let side = fill.taker_side().invert_side();
|
||||
let (base_change, quote_change) = fill.base_quote_change(side);
|
||||
let quote = cm!(I80F48::from(perp_market.quote_lot_size) * I80F48::from(quote_change));
|
||||
let fees = cm!(quote.abs() * fill.maker_fee);
|
||||
let fees = cm!(quote.abs() * I80F48::from_num(fill.maker_fee));
|
||||
pa.record_trading_fee(fees);
|
||||
pa.record_trade(perp_market, base_change, quote);
|
||||
|
||||
|
|
|
@ -144,11 +144,10 @@ impl<'a> Orderbook<'a> {
|
|||
now_ts,
|
||||
event_queue.header.seq_num,
|
||||
best_opposing.node.owner,
|
||||
best_opposing.node.key,
|
||||
best_opposing.node.client_order_id,
|
||||
market.maker_fee,
|
||||
best_opposing.node.timestamp,
|
||||
*mango_account_pk,
|
||||
order_id,
|
||||
order.client_order_id,
|
||||
market.taker_fee,
|
||||
best_opposing_price,
|
||||
|
@ -245,6 +244,7 @@ impl<'a> Orderbook<'a> {
|
|||
PostOrderType::Limit, // TODO: Support order types? needed?
|
||||
order.time_in_force,
|
||||
order.peg_limit(),
|
||||
order.client_order_id,
|
||||
);
|
||||
let _result = bookside.insert_leaf(order_tree_target, &new_order)?;
|
||||
|
||||
|
|
|
@ -206,8 +206,19 @@ mod tests {
|
|||
let mut order_tree = new_order_tree(order_tree_type);
|
||||
let mut root_fixed = OrderTreeRoot::zeroed();
|
||||
let mut root_pegged = OrderTreeRoot::zeroed();
|
||||
let new_leaf =
|
||||
|key: u128| LeafNode::new(0, key, Pubkey::default(), 0, 1, PostOrderType::Limit, 0, -1);
|
||||
let new_leaf = |key: u128| {
|
||||
LeafNode::new(
|
||||
0,
|
||||
key,
|
||||
Pubkey::default(),
|
||||
0,
|
||||
1,
|
||||
PostOrderType::Limit,
|
||||
0,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
// add 100 leaves to each BookSide, mostly random
|
||||
let mut keys = vec![];
|
||||
|
@ -301,6 +312,7 @@ mod tests {
|
|||
PostOrderType::Limit,
|
||||
tif,
|
||||
peg_limit,
|
||||
0,
|
||||
)
|
||||
};
|
||||
let mut add_fixed = |price: i64, tif: u16| {
|
||||
|
|
|
@ -244,8 +244,10 @@ mod tests {
|
|||
// Add lots and fees to make sure to exercise unit conversion
|
||||
market.base_lot_size = 10;
|
||||
market.quote_lot_size = 100;
|
||||
market.maker_fee = I80F48::from_num(-0.001f64);
|
||||
market.taker_fee = I80F48::from_num(0.01f64);
|
||||
let maker_fee = I80F48::from_num(-0.001f32);
|
||||
let taker_fee = I80F48::from_num(0.01f32);
|
||||
market.maker_fee = maker_fee;
|
||||
market.taker_fee = taker_fee;
|
||||
|
||||
let buffer = MangoAccount::default_for_tests().try_to_vec().unwrap();
|
||||
let mut maker = MangoAccountValue::from_bytes(&buffer).unwrap();
|
||||
|
@ -286,6 +288,10 @@ mod tests {
|
|||
u8::MAX,
|
||||
)
|
||||
.unwrap();
|
||||
let order =
|
||||
order_tree_leaf_by_key(&book.bids, maker.perp_order_by_raw_index(0).id).unwrap();
|
||||
assert_eq!(order.client_order_id, 42);
|
||||
assert_eq!(order.quantity, bid_quantity);
|
||||
assert_eq!(
|
||||
maker.perp_order_mut_by_raw_index(0).market,
|
||||
market.perp_market_index
|
||||
|
@ -352,10 +358,7 @@ mod tests {
|
|||
|
||||
// fees were immediately accrued
|
||||
let match_quote = I80F48::from(match_quantity * price_lots * market.quote_lot_size);
|
||||
assert_eq!(
|
||||
market.fees_accrued,
|
||||
match_quote * (market.maker_fee + market.taker_fee)
|
||||
);
|
||||
assert_eq!(market.fees_accrued, match_quote * (maker_fee + taker_fee));
|
||||
|
||||
// the taker account is updated
|
||||
assert_eq!(taker.perp_order_by_raw_index(0).market, FREE_ORDER_SLOT);
|
||||
|
@ -372,7 +375,7 @@ mod tests {
|
|||
assert_eq!(taker.perp_position_by_raw_index(0).base_position_lots(), 0);
|
||||
assert_eq!(
|
||||
taker.perp_position_by_raw_index(0).quote_position_native(),
|
||||
-match_quote * market.taker_fee
|
||||
-match_quote * taker_fee
|
||||
);
|
||||
|
||||
// the fill gets added to the event queue
|
||||
|
@ -385,8 +388,8 @@ mod tests {
|
|||
assert_eq!(fill.taker_client_order_id, 43);
|
||||
assert_eq!(fill.maker, maker_pk);
|
||||
assert_eq!(fill.taker, taker_pk);
|
||||
assert_eq!(fill.maker_fee, market.maker_fee);
|
||||
assert_eq!(fill.taker_fee, market.taker_fee);
|
||||
assert_eq!(fill.maker_fee, maker_fee.to_num::<f32>());
|
||||
assert_eq!(fill.taker_fee, taker_fee.to_num::<f32>());
|
||||
|
||||
// simulate event queue processing
|
||||
maker
|
||||
|
@ -411,7 +414,7 @@ mod tests {
|
|||
);
|
||||
assert_eq!(
|
||||
maker.perp_position_by_raw_index(0).quote_position_native(),
|
||||
-match_quote - match_quote * market.maker_fee
|
||||
-match_quote - match_quote * maker_fee
|
||||
);
|
||||
|
||||
assert_eq!(taker.perp_position_by_raw_index(0).bids_base_lots, 0);
|
||||
|
@ -424,7 +427,7 @@ mod tests {
|
|||
);
|
||||
assert_eq!(
|
||||
taker.perp_position_by_raw_index(0).quote_position_native(),
|
||||
match_quote - match_quote * market.taker_fee
|
||||
match_quote - match_quote * taker_fee
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -179,11 +179,14 @@ pub struct LeafNode {
|
|||
/// Only applicable in the oracle_pegged OrderTree
|
||||
pub peg_limit: i64,
|
||||
|
||||
pub reserved: [u8; 40],
|
||||
/// User defined id for this order, used in FillEvents
|
||||
pub client_order_id: u64,
|
||||
|
||||
pub reserved: [u8; 32],
|
||||
}
|
||||
const_assert_eq!(
|
||||
size_of::<LeafNode>(),
|
||||
4 + 1 + 1 + 1 + 1 + 16 + 32 + 8 + 8 + 8 + 40
|
||||
4 + 1 + 1 + 1 + 1 + 16 + 32 + 8 + 8 + 8 + 8 + 32
|
||||
);
|
||||
const_assert_eq!(size_of::<LeafNode>(), NODE_SIZE);
|
||||
const_assert_eq!(size_of::<LeafNode>() % 8, 0);
|
||||
|
@ -199,6 +202,7 @@ impl LeafNode {
|
|||
order_type: PostOrderType,
|
||||
time_in_force: u16,
|
||||
peg_limit: i64,
|
||||
client_order_id: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
tag: NodeTag::LeafNode.into(),
|
||||
|
@ -212,7 +216,8 @@ impl LeafNode {
|
|||
quantity,
|
||||
timestamp,
|
||||
peg_limit,
|
||||
reserved: [0; 40],
|
||||
client_order_id,
|
||||
reserved: [0; 32],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -557,6 +557,7 @@ mod tests {
|
|||
PostOrderType::Limit,
|
||||
1,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -649,6 +650,7 @@ mod tests {
|
|||
PostOrderType::Limit,
|
||||
1,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
@ -186,20 +186,22 @@ pub struct FillEvent {
|
|||
pub seq_num: u64,
|
||||
|
||||
pub maker: Pubkey,
|
||||
pub maker_order_id: u128,
|
||||
pub maker_fee: I80F48,
|
||||
pub padding2: [u8; 32],
|
||||
|
||||
// Timestamp of when the maker order was placed; copied over from the LeafNode
|
||||
pub maker_timestamp: u64,
|
||||
|
||||
pub taker: Pubkey,
|
||||
pub taker_order_id: u128,
|
||||
pub padding3: [u8; 16],
|
||||
pub taker_client_order_id: u64,
|
||||
pub taker_fee: I80F48,
|
||||
pub padding4: [u8; 16],
|
||||
|
||||
pub price: i64,
|
||||
pub quantity: i64, // number of quote lots
|
||||
pub reserved: [u8; 24],
|
||||
pub maker_client_order_id: u64,
|
||||
pub maker_fee: f32,
|
||||
pub taker_fee: f32,
|
||||
pub reserved: [u8; 8],
|
||||
}
|
||||
const_assert_eq!(size_of::<FillEvent>() % 8, 0);
|
||||
const_assert_eq!(size_of::<FillEvent>(), EVENT_SIZE);
|
||||
|
@ -213,12 +215,10 @@ impl FillEvent {
|
|||
timestamp: u64,
|
||||
seq_num: u64,
|
||||
maker: Pubkey,
|
||||
maker_order_id: u128,
|
||||
maker_client_order_id: u64,
|
||||
maker_fee: I80F48,
|
||||
maker_timestamp: u64,
|
||||
|
||||
taker: Pubkey,
|
||||
taker_order_id: u128,
|
||||
taker_client_order_id: u64,
|
||||
taker_fee: I80F48,
|
||||
price: i64,
|
||||
|
@ -229,20 +229,22 @@ impl FillEvent {
|
|||
taker_side: taker_side.into(),
|
||||
maker_out: maker_out.into(),
|
||||
maker_slot,
|
||||
padding: Default::default(),
|
||||
timestamp,
|
||||
seq_num,
|
||||
maker,
|
||||
maker_order_id,
|
||||
maker_fee,
|
||||
maker_client_order_id,
|
||||
maker_fee: maker_fee.to_num::<f32>(),
|
||||
maker_timestamp,
|
||||
taker,
|
||||
taker_order_id,
|
||||
taker_client_order_id,
|
||||
taker_fee,
|
||||
taker_fee: taker_fee.to_num::<f32>(),
|
||||
price,
|
||||
quantity,
|
||||
reserved: [0; 24],
|
||||
padding: Default::default(),
|
||||
padding2: Default::default(),
|
||||
padding3: Default::default(),
|
||||
padding4: Default::default(),
|
||||
reserved: [0; 8],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue