-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add dlob nodes * fix weird merge & reset stuff * refactor dlob node & add node lists * refactor dlob node a little bit * refactor to use arena * insert order dlob * update order dlob * broken, for review * wip * refactor dlob, MVP for jit maker * cleanup * run cargo fmt * remove vsc folder * remove unused imports * remove bigint * couple pr comment * couple pr comment
- Loading branch information
1 parent
db9c093
commit 15ce9ce
Showing
12 changed files
with
1,648 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
use dashmap::{DashMap, DashSet}; | ||
use drift::controller::position::PositionDirection; | ||
use drift::state::user::{Order, OrderTriggerCondition, OrderType}; | ||
|
||
use crate::dlob::dlob_node::{Node, NodeType, SortDirection}; | ||
use crate::dlob::order_list::Orderlist; | ||
use crate::is_one_of_variant; | ||
use crate::math::order::is_resting_limit_order; | ||
|
||
#[derive(Clone)] | ||
pub(crate) struct Market { | ||
pub resting_limit_orders: Orderlist, | ||
pub floating_limit_orders: Orderlist, | ||
pub taking_limit_orders: Orderlist, | ||
pub market_orders: Orderlist, | ||
pub trigger_orders: Orderlist, | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub enum SubType { | ||
Bid, | ||
Ask, | ||
Above, | ||
Below, | ||
} | ||
|
||
impl Market { | ||
pub(crate) fn new() -> Market { | ||
Market { | ||
resting_limit_orders: Orderlist::new( | ||
SortDirection::Descending, | ||
SortDirection::Ascending, | ||
), | ||
floating_limit_orders: Orderlist::new( | ||
SortDirection::Descending, | ||
SortDirection::Ascending, | ||
), | ||
taking_limit_orders: Orderlist::new(SortDirection::Ascending, SortDirection::Ascending), | ||
market_orders: Orderlist::new(SortDirection::Ascending, SortDirection::Ascending), | ||
trigger_orders: Orderlist::new(SortDirection::Ascending, SortDirection::Descending), | ||
} | ||
} | ||
|
||
pub(crate) fn get_list_for_order( | ||
&mut self, | ||
order: &Order, | ||
slot: u64, | ||
) -> (Option<&mut Orderlist>, SubType) { | ||
let is_inactive_trigger_order = order.must_be_triggered() && !order.triggered(); | ||
|
||
let node_type = if is_inactive_trigger_order { | ||
NodeType::Trigger | ||
} else if is_one_of_variant( | ||
&order.order_type, | ||
&[ | ||
OrderType::Market, | ||
OrderType::TriggerMarket, | ||
OrderType::Oracle, | ||
], | ||
) { | ||
NodeType::Market | ||
} else if order.oracle_price_offset != 0 { | ||
NodeType::FloatingLimit | ||
} else { | ||
if is_resting_limit_order(order, slot) { | ||
NodeType::RestingLimit | ||
} else { | ||
NodeType::TakingLimit | ||
} | ||
}; | ||
|
||
let order_list = match node_type { | ||
NodeType::RestingLimit => &mut self.resting_limit_orders, | ||
NodeType::FloatingLimit => &mut self.floating_limit_orders, | ||
NodeType::TakingLimit => &mut self.taking_limit_orders, | ||
NodeType::Market => &mut self.market_orders, | ||
NodeType::Trigger => &mut self.trigger_orders, | ||
NodeType::VAMM => return (None, SubType::Bid), | ||
}; | ||
|
||
let sub_type = if is_inactive_trigger_order { | ||
if order.trigger_condition == OrderTriggerCondition::Above { | ||
SubType::Bid | ||
} else { | ||
SubType::Ask | ||
} | ||
} else { | ||
match order.direction { | ||
PositionDirection::Long => SubType::Bid, | ||
PositionDirection::Short => SubType::Ask, | ||
} | ||
}; | ||
|
||
(Some(order_list), sub_type) | ||
} | ||
|
||
pub(crate) fn get_best_order( | ||
&self, | ||
order_list: &mut Orderlist, | ||
sub_type: SubType, | ||
) -> Option<Node> { | ||
match sub_type { | ||
SubType::Bid => order_list.get_best_bid(), | ||
SubType::Ask => order_list.get_best_ask(), | ||
_ => unimplemented!(), | ||
}; | ||
|
||
None | ||
} | ||
|
||
pub(crate) fn get_order_list_for_node_type(&self, node_type: NodeType) -> Orderlist { | ||
match node_type { | ||
NodeType::RestingLimit => &self.resting_limit_orders, | ||
NodeType::FloatingLimit => &self.floating_limit_orders, | ||
NodeType::TakingLimit => &self.taking_limit_orders, | ||
NodeType::Market => &self.market_orders, | ||
NodeType::Trigger => &self.trigger_orders, | ||
NodeType::VAMM => panic!("VAMM order list not found"), | ||
} | ||
.clone() | ||
} | ||
} | ||
|
||
pub(crate) type Exchange = DashMap<String, DashMap<u16, Market>>; | ||
|
||
pub fn get_order_lists(exchange: &Exchange) -> Vec<Orderlist> { | ||
let mut order_lists = vec![]; | ||
|
||
for market_type_ref in exchange.iter() { | ||
for market_ref in market_type_ref.iter() { | ||
order_lists.push(market_ref.value().resting_limit_orders.clone()); | ||
order_lists.push(market_ref.value().floating_limit_orders.clone()); | ||
order_lists.push(market_ref.value().taking_limit_orders.clone()); | ||
order_lists.push(market_ref.value().market_orders.clone()); | ||
order_lists.push(market_ref.value().trigger_orders.clone()); | ||
} | ||
} | ||
|
||
order_lists | ||
} | ||
|
||
pub(crate) type OpenOrders = DashMap<String, DashSet<String>>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pub mod dlob; | ||
mod dlob_node; | ||
mod market; | ||
mod order_list; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
use std::collections::BinaryHeap; | ||
|
||
use dashmap::DashMap; | ||
|
||
use crate::dlob::dlob_node::{get_order_signature, DLOBNode, DirectionalNode, Node, SortDirection}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct Orderlist { | ||
pub bids: BinaryHeap<DirectionalNode>, | ||
pub asks: BinaryHeap<DirectionalNode>, | ||
pub order_sigs: DashMap<String, Node>, | ||
bid_sort_direction: SortDirection, | ||
ask_sort_direction: SortDirection, | ||
} | ||
|
||
impl Orderlist { | ||
pub fn new(bid_sort_direction: SortDirection, ask_sort_direction: SortDirection) -> Self { | ||
Orderlist { | ||
bids: BinaryHeap::new(), | ||
asks: BinaryHeap::new(), | ||
order_sigs: DashMap::new(), | ||
bid_sort_direction, | ||
ask_sort_direction, | ||
} | ||
} | ||
|
||
pub fn insert_bid(&mut self, node: Node) { | ||
let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); | ||
self.order_sigs.insert(order_sig.clone(), node.clone()); | ||
let directional = DirectionalNode::new(node, self.bid_sort_direction); | ||
self.bids.push(directional); | ||
} | ||
|
||
pub fn insert_ask(&mut self, node: Node) { | ||
let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); | ||
self.order_sigs.insert(order_sig.clone(), node.clone()); | ||
let directional = DirectionalNode::new(node, self.ask_sort_direction); | ||
self.asks.push(directional); | ||
} | ||
|
||
pub fn get_best_bid(&mut self) -> Option<Node> { | ||
if let Some(node) = self.bids.pop().map(|node| node.node.clone()) { | ||
let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); | ||
if self.order_sigs.contains_key(&order_sig) { | ||
self.order_sigs.remove(&order_sig); | ||
return Some(node); | ||
} | ||
} | ||
None | ||
} | ||
|
||
pub fn get_best_ask(&mut self) -> Option<Node> { | ||
if let Some(node) = self.asks.pop().map(|node| node.node.clone()) { | ||
let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); | ||
if self.order_sigs.contains_key(&order_sig) { | ||
self.order_sigs.remove(&order_sig); | ||
return Some(node); | ||
} | ||
} | ||
None | ||
} | ||
|
||
pub fn get_node(&self, order_sig: &String) -> Option<Node> { | ||
self.order_sigs.get(order_sig).map(|node| node.clone()) | ||
} | ||
|
||
pub fn bids_empty(&self) -> bool { | ||
self.bids.is_empty() | ||
} | ||
|
||
pub fn asks_empty(&self) -> bool { | ||
self.asks.is_empty() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::dlob::dlob_node::{create_node, NodeType}; | ||
|
||
use super::*; | ||
use drift::state::user::Order; | ||
use solana_sdk::pubkey::Pubkey; | ||
|
||
#[test] | ||
fn test_insertion_and_ordering() { | ||
let mut orderlist = Orderlist::new(SortDirection::Ascending, SortDirection::Ascending); | ||
let user_account = Pubkey::new_unique(); | ||
let order_1 = Order { | ||
order_id: 1, | ||
slot: 1, | ||
..Order::default() | ||
}; | ||
let order_2 = Order { | ||
order_id: 2, | ||
slot: 2, | ||
..Order::default() | ||
}; | ||
let order_3 = Order { | ||
order_id: 3, | ||
slot: 3, | ||
..Order::default() | ||
}; | ||
let order_4 = Order { | ||
order_id: 4, | ||
slot: 4, | ||
..Order::default() | ||
}; | ||
let order_5 = Order { | ||
order_id: 5, | ||
slot: 5, | ||
..Order::default() | ||
}; | ||
let order_6 = Order { | ||
order_id: 6, | ||
slot: 1, | ||
..Order::default() | ||
}; | ||
let order_7 = Order { | ||
order_id: 7, | ||
slot: 2, | ||
..Order::default() | ||
}; | ||
let order_8 = Order { | ||
order_id: 8, | ||
slot: 3, | ||
..Order::default() | ||
}; | ||
let order_9 = Order { | ||
order_id: 9, | ||
slot: 4, | ||
..Order::default() | ||
}; | ||
let order_10 = Order { | ||
order_id: 10, | ||
slot: 5, | ||
..Order::default() | ||
}; | ||
|
||
let node_1 = create_node(NodeType::TakingLimit, order_1, user_account); | ||
let node_2 = create_node(NodeType::TakingLimit, order_2, user_account); | ||
let node_3 = create_node(NodeType::TakingLimit, order_3, user_account); | ||
let node_4 = create_node(NodeType::TakingLimit, order_4, user_account); | ||
let node_5 = create_node(NodeType::TakingLimit, order_5, user_account); | ||
|
||
let node_6 = create_node(NodeType::TakingLimit, order_6, user_account); | ||
let node_7 = create_node(NodeType::TakingLimit, order_7, user_account); | ||
let node_8 = create_node(NodeType::TakingLimit, order_8, user_account); | ||
let node_9 = create_node(NodeType::TakingLimit, order_9, user_account); | ||
let node_10 = create_node(NodeType::TakingLimit, order_10, user_account); | ||
|
||
orderlist.insert_bid(node_1); | ||
orderlist.insert_bid(node_2); | ||
orderlist.insert_bid(node_3); | ||
orderlist.insert_bid(node_4); | ||
orderlist.insert_bid(node_5); | ||
|
||
orderlist.insert_ask(node_6); | ||
orderlist.insert_ask(node_7); | ||
orderlist.insert_ask(node_8); | ||
orderlist.insert_ask(node_9); | ||
orderlist.insert_ask(node_10); | ||
|
||
assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 1); | ||
assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 2); | ||
assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 3); | ||
assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 4); | ||
assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 5); | ||
|
||
assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 1); | ||
assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 2); | ||
assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 3); | ||
assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 4); | ||
assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 5); | ||
} | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.