Skip to content

Commit

Permalink
frank/dlob (#12)
Browse files Browse the repository at this point in the history
* 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
soundsonacid authored Mar 18, 2024
1 parent db9c093 commit 15ce9ce
Show file tree
Hide file tree
Showing 12 changed files with 1,648 additions and 1 deletion.
664 changes: 664 additions & 0 deletions src/dlob/dlob.rs

Large diffs are not rendered by default.

493 changes: 493 additions & 0 deletions src/dlob/dlob_node.rs

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions src/dlob/market.rs
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>>;
4 changes: 4 additions & 0 deletions src/dlob/mod.rs
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;
175 changes: 175 additions & 0 deletions src/dlob/order_list.rs
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.
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ pub mod websocket_program_account_subscriber;

// subscribers
pub mod auction_subscriber;
pub mod dlob;
pub mod dlob_client;
pub mod event_subscriber;
pub mod slot_subscriber;

pub mod dlob;
pub mod math;
pub mod usermap;

use types::*;
Expand Down
Loading

0 comments on commit 15ce9ce

Please sign in to comment.