use std::{cell::UnsafeCell, collections::VecDeque, rc::Rc};
use crate::{backtest::models::LatencyModel, types::Order};
#[derive(Clone, Debug, Default)]
pub struct OrderBus {
order_list: Rc<UnsafeCell<VecDeque<(Order, i64)>>>,
}
impl OrderBus {
pub fn new() -> Self {
Default::default()
}
pub fn earliest_timestamp(&self) -> Option<i64> {
unsafe { &*self.order_list.get() }
.front()
.map(|(_order, ts)| *ts)
}
pub fn append(&mut self, order: Order, timestamp: i64) {
let latest_timestamp = {
let order_list = unsafe { &*self.order_list.get() };
let len = order_list.len();
if len > 0 {
let (_, timestamp) = order_list.get(len - 1).unwrap();
*timestamp
} else {
0
}
};
let timestamp = timestamp.max(latest_timestamp);
unsafe { &mut *self.order_list.get() }.push_back((order, timestamp));
}
pub fn reset(&mut self) {
unsafe { &mut *self.order_list.get() }.clear();
}
pub fn len(&self) -> usize {
unsafe { &*self.order_list.get() }.len()
}
pub fn is_empty(&self) -> bool {
unsafe { &*self.order_list.get() }.is_empty()
}
pub fn pop_front(&mut self) -> Option<(Order, i64)> {
unsafe { &mut *self.order_list.get() }.pop_front()
}
}
pub struct ExchToLocal<LM> {
to_exch: OrderBus,
to_local: OrderBus,
order_latency: LM,
}
impl<LM> ExchToLocal<LM>
where
LM: LatencyModel,
{
pub fn earliest_recv_order_timestamp(&self) -> Option<i64> {
self.to_exch.earliest_timestamp()
}
pub fn earliest_send_order_timestamp(&self) -> Option<i64> {
self.to_local.earliest_timestamp()
}
pub fn respond(&mut self, order: Order) {
let local_recv_timestamp =
order.exch_timestamp + self.order_latency.response(order.exch_timestamp, &order);
self.to_local.append(order, local_recv_timestamp);
}
pub fn receive(&mut self, receipt_timestamp: i64) -> Option<Order> {
if let Some(timestamp) = self.to_exch.earliest_timestamp() {
if timestamp == receipt_timestamp {
self.to_exch.pop_front().map(|(order, _)| order)
} else {
assert!(timestamp > receipt_timestamp);
None
}
} else {
None
}
}
}
pub struct LocalToExch<LM> {
to_exch: OrderBus,
to_local: OrderBus,
order_latency: LM,
}
impl<LM> LocalToExch<LM>
where
LM: LatencyModel,
{
pub fn earliest_recv_order_timestamp(&self) -> Option<i64> {
self.to_local.earliest_timestamp()
}
pub fn earliest_send_order_timestamp(&self) -> Option<i64> {
self.to_exch.earliest_timestamp()
}
pub fn request<F>(&mut self, mut order: Order, mut reject: F)
where
F: FnMut(&mut Order),
{
let order_entry_latency = self.order_latency.entry(order.local_timestamp, &order);
if order_entry_latency < 0 {
reject(&mut order);
let rej_recv_timestamp = order.local_timestamp - order_entry_latency;
self.to_local.append(order, rej_recv_timestamp);
} else {
let exch_recv_timestamp = order.local_timestamp + order_entry_latency;
self.to_exch.append(order, exch_recv_timestamp);
}
}
pub fn receive(&mut self, receipt_timestamp: i64) -> Option<Order> {
if let Some(timestamp) = self.to_local.earliest_timestamp() {
if timestamp == receipt_timestamp {
self.to_local.pop_front().map(|(order, _)| order)
} else {
assert!(timestamp > receipt_timestamp);
None
}
} else {
None
}
}
}
pub fn order_bus<LM>(order_latency: LM) -> (ExchToLocal<LM>, LocalToExch<LM>)
where
LM: LatencyModel + Clone,
{
let to_exch = OrderBus::new();
let to_local = OrderBus::new();
(
ExchToLocal {
to_exch: to_exch.clone(),
to_local: to_local.clone(),
order_latency: order_latency.clone(),
},
LocalToExch {
to_exch,
to_local,
order_latency,
},
)
}