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