use nautilus_common::cache::Cache;
use nautilus_model::{
data::InstrumentClose,
enums::InstrumentCloseType,
identifiers::{InstrumentId, PositionId},
instruments::InstrumentAny,
position::Position,
types::Quantity,
};
pub fn settle_instrument_close(
cache: &mut Cache,
close: InstrumentClose,
) -> anyhow::Result<Vec<(Position, Quantity)>> {
let instrument_id = close.instrument_id;
if close.close_type != InstrumentCloseType::ContractExpired
|| !matches!(
cache.instrument(&instrument_id),
Some(InstrumentAny::BinaryOption(_))
)
{
return Ok(Vec::new());
}
let close = if let Some(settled) = settlement_close(cache, &instrument_id) {
if settled.close_price != close.close_price {
log::error!(
"Ignoring conflicting instrument close for {instrument_id}: settled at {}, received {}",
settled.close_price,
close.close_price,
);
}
settled
} else {
cache.add_instrument_close(close)?;
close
};
let positions: Vec<(PositionId, Quantity)> = cache
.positions_open(None, Some(&instrument_id), None, None, None)
.iter()
.map(|position| (position.id, position.quantity))
.collect();
let mut settled = Vec::with_capacity(positions.len());
for (position_id, last_qty) in positions {
match cache.update_position_from_instrument_close(position_id, close) {
Ok(position) => settled.push((position, last_qty)),
Err(e) => log::error!("Cannot settle position {position_id}: {e}"),
}
}
Ok(settled)
}
#[must_use]
pub fn settlement_close(cache: &Cache, instrument_id: &InstrumentId) -> Option<InstrumentClose> {
if !matches!(
cache.instrument(instrument_id),
Some(InstrumentAny::BinaryOption(_))
) {
return None;
}
cache
.instrument_close(instrument_id)
.copied()
.filter(|close| close.close_type == InstrumentCloseType::ContractExpired)
}