use std::{cell::RefCell, rc::Rc};
use nautilus_common::msgbus::Handler;
use nautilus_core::WeakCell;
use nautilus_model::{
data::{Bar, BarType, QuoteTick, TradeTick},
identifiers::InstrumentId,
};
use ustr::Ustr;
use crate::aggregation::{BarAggregator, SpreadQuoteAggregator};
pub(super) const BAR_AGGREGATOR_PRIORITY: u32 = 5;
#[derive(Debug)]
pub(super) struct WarmupBuffer<T>(Rc<RefCell<Option<Vec<T>>>>);
impl<T> Clone for WarmupBuffer<T> {
fn clone(&self) -> Self {
Self(Rc::clone(&self.0))
}
}
impl<T: Copy> WarmupBuffer<T> {
pub(super) fn new() -> Self {
Self(Rc::new(RefCell::new(Some(Vec::new()))))
}
fn hold(&self, item: &T) -> bool {
match self.0.borrow_mut().as_mut() {
Some(held) => {
held.push(*item);
true
}
None => false,
}
}
pub(super) fn release(&self) -> Vec<T> {
self.0.borrow_mut().take().unwrap_or_default()
}
}
#[derive(Debug)]
pub(super) struct BarQuoteHandler {
aggregator: WeakCell<Box<dyn BarAggregator>>,
bar_type: BarType,
warmup: Option<WarmupBuffer<QuoteTick>>,
}
impl BarQuoteHandler {
pub(crate) fn new(aggregator: &Rc<RefCell<Box<dyn BarAggregator>>>, bar_type: BarType) -> Self {
Self {
aggregator: WeakCell::from(Rc::downgrade(aggregator)),
bar_type,
warmup: None,
}
}
pub(super) fn with_warmup(mut self, warmup: Option<WarmupBuffer<QuoteTick>>) -> Self {
self.warmup = warmup;
self
}
}
impl Handler<QuoteTick> for BarQuoteHandler {
fn id(&self) -> Ustr {
Ustr::from(&format!("BarQuoteHandler|{}", self.bar_type))
}
fn handle(&self, quote: &QuoteTick) {
if self
.warmup
.as_ref()
.is_some_and(|warmup| warmup.hold(quote))
{
return;
}
if let Some(agg) = self.aggregator.upgrade() {
agg.borrow_mut().handle_quote(*quote);
}
}
}
#[derive(Debug)]
pub(super) struct BarTradeHandler {
aggregator: WeakCell<Box<dyn BarAggregator>>,
bar_type: BarType,
warmup: Option<WarmupBuffer<TradeTick>>,
}
impl BarTradeHandler {
pub(crate) fn new(aggregator: &Rc<RefCell<Box<dyn BarAggregator>>>, bar_type: BarType) -> Self {
Self {
aggregator: WeakCell::from(Rc::downgrade(aggregator)),
bar_type,
warmup: None,
}
}
pub(super) fn with_warmup(mut self, warmup: Option<WarmupBuffer<TradeTick>>) -> Self {
self.warmup = warmup;
self
}
}
impl Handler<TradeTick> for BarTradeHandler {
fn id(&self) -> Ustr {
Ustr::from(&format!("BarTradeHandler|{}", self.bar_type))
}
fn handle(&self, trade: &TradeTick) {
if self
.warmup
.as_ref()
.is_some_and(|warmup| warmup.hold(trade))
{
return;
}
if let Some(agg) = self.aggregator.upgrade() {
agg.borrow_mut().handle_trade(*trade);
}
}
}
#[derive(Debug)]
pub(super) struct BarBarHandler {
aggregator: WeakCell<Box<dyn BarAggregator>>,
bar_type: BarType,
warmup: Option<WarmupBuffer<Bar>>,
}
impl BarBarHandler {
pub(crate) fn new(aggregator: &Rc<RefCell<Box<dyn BarAggregator>>>, bar_type: BarType) -> Self {
Self {
aggregator: WeakCell::from(Rc::downgrade(aggregator)),
bar_type,
warmup: None,
}
}
pub(super) fn with_warmup(mut self, warmup: Option<WarmupBuffer<Bar>>) -> Self {
self.warmup = warmup;
self
}
}
impl Handler<Bar> for BarBarHandler {
fn id(&self) -> Ustr {
Ustr::from(&format!("BarBarHandler|{}", self.bar_type))
}
fn handle(&self, bar: &Bar) {
if self.warmup.as_ref().is_some_and(|warmup| warmup.hold(bar)) {
return;
}
if let Some(agg) = self.aggregator.upgrade() {
agg.borrow_mut().handle_bar(*bar);
}
}
}
#[derive(Debug)]
pub(super) struct SpreadQuoteHandler {
aggregator: WeakCell<SpreadQuoteAggregator>,
spread_instrument_id: InstrumentId,
leg_instrument_id: InstrumentId,
}
impl SpreadQuoteHandler {
pub(crate) fn new(
aggregator: &Rc<RefCell<SpreadQuoteAggregator>>,
spread_instrument_id: InstrumentId,
leg_instrument_id: InstrumentId,
) -> Self {
Self {
aggregator: WeakCell::from(Rc::downgrade(aggregator)),
spread_instrument_id,
leg_instrument_id,
}
}
}
impl Handler<QuoteTick> for SpreadQuoteHandler {
fn id(&self) -> Ustr {
Ustr::from(&format!(
"SpreadQuoteHandler|{}|{}",
self.spread_instrument_id, self.leg_instrument_id,
))
}
fn handle(&self, quote: &QuoteTick) {
if let Some(agg) = self.aggregator.upgrade() {
agg.borrow_mut().handle_quote_tick(*quote);
}
}
}