use crate::{
engine::state::{
instrument::{data::InstrumentDataState, filter::InstrumentFilter},
order::{Orders, manager::OrderManager},
position::{PositionExited, PositionManager},
},
statistic::summary::instrument::TearSheetGenerator,
};
use barter_data::event::MarketEvent;
use barter_execution::{
InstrumentAccountSnapshot,
order::{
Order, OrderKey,
request::OrderResponseCancel,
state::{ActiveOrderState, OrderState},
},
trade::Trade,
};
use barter_instrument::{
Keyed,
asset::{AssetIndex, QuoteAsset, name::AssetNameExchange},
exchange::{ExchangeId, ExchangeIndex},
index::IndexedInstruments,
instrument::{
Instrument, InstrumentIndex,
name::{InstrumentNameExchange, InstrumentNameInternal},
},
};
use barter_integration::collection::{FnvIndexMap, snapshot::Snapshot};
use chrono::{DateTime, Utc};
use derive_more::Constructor;
use itertools::Either;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
pub mod data;
pub mod filter;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct InstrumentStates<
InstrumentData,
ExchangeKey = ExchangeIndex,
AssetKey = AssetIndex,
InstrumentKey = InstrumentIndex,
>(
pub FnvIndexMap<
InstrumentNameInternal,
InstrumentState<InstrumentData, ExchangeKey, AssetKey, InstrumentKey>,
>,
);
impl<InstrumentData> InstrumentStates<InstrumentData> {
pub fn instrument_index(&self, key: &InstrumentIndex) -> &InstrumentState<InstrumentData> {
self.0
.get_index(key.index())
.map(|(_key, state)| state)
.unwrap_or_else(|| panic!("InstrumentStates does not contain: {key}"))
}
pub fn instrument_index_mut(
&mut self,
key: &InstrumentIndex,
) -> &mut InstrumentState<InstrumentData> {
self.0
.get_index_mut(key.index())
.map(|(_key, state)| state)
.unwrap_or_else(|| panic!("InstrumentStates does not contain: {key}"))
}
pub fn instrument(&self, key: &InstrumentNameInternal) -> &InstrumentState<InstrumentData> {
self.0
.get(key)
.unwrap_or_else(|| panic!("InstrumentStates does not contain: {key}"))
}
pub fn instrument_mut(
&mut self,
key: &InstrumentNameInternal,
) -> &mut InstrumentState<InstrumentData> {
self.0
.get_mut(key)
.unwrap_or_else(|| panic!("InstrumentStates does not contain: {key}"))
}
pub fn instruments<'a>(
&'a self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a InstrumentState<InstrumentData>> {
self.filtered(filter)
}
pub fn instruments_mut<'a>(
&'a mut self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a mut InstrumentState<InstrumentData>> {
self.filtered_mut(filter)
}
pub fn tear_sheets<'a>(
&'a self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a TearSheetGenerator>
where
InstrumentData: 'a,
{
self.filtered(filter).map(|state| &state.tear_sheet)
}
pub fn positions<'a>(
&'a self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a PositionManager>
where
InstrumentData: 'a,
{
self.filtered(filter).map(|state| &state.position)
}
pub fn orders<'a>(&'a self, filter: &'a InstrumentFilter) -> impl Iterator<Item = &'a Orders>
where
InstrumentData: 'a,
{
self.filtered(filter).map(|state| &state.orders)
}
pub fn instrument_datas<'a>(
&'a self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a InstrumentData>
where
InstrumentData: 'a,
{
self.filtered(filter).map(|state| &state.data)
}
pub fn instrument_datas_mut<'a>(
&'a mut self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a mut InstrumentData>
where
InstrumentData: 'a,
{
self.filtered_mut(filter).map(|state| &mut state.data)
}
fn filtered<'a>(
&'a self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a InstrumentState<InstrumentData>>
where
InstrumentData: 'a,
{
use filter::InstrumentFilter::*;
match filter {
None => Either::Left(Either::Left(self.0.values())),
Exchanges(exchanges) => Either::Left(Either::Right(
self.0
.values()
.filter(|state| exchanges.contains(&state.instrument.exchange)),
)),
Instruments(instruments) => Either::Right(Either::Right(
self.0
.values()
.filter(|state| instruments.contains(&state.key)),
)),
Underlyings(underlying) => Either::Right(Either::Left(
self.0
.values()
.filter(|state| underlying.contains(&state.instrument.underlying)),
)),
}
}
fn filtered_mut<'a>(
&'a mut self,
filter: &'a InstrumentFilter,
) -> impl Iterator<Item = &'a mut InstrumentState<InstrumentData>>
where
InstrumentData: 'a,
{
use filter::InstrumentFilter::*;
match filter {
None => Either::Left(Either::Left(self.0.values_mut())),
Exchanges(exchanges) => Either::Left(Either::Right(
self.0
.values_mut()
.filter(|state| exchanges.contains(&state.instrument.exchange)),
)),
Instruments(instruments) => Either::Right(Either::Right(
self.0
.values_mut()
.filter(|state| instruments.contains(&state.key)),
)),
Underlyings(underlying) => Either::Right(Either::Left(
self.0
.values_mut()
.filter(|state| underlying.contains(&state.instrument.underlying)),
)),
}
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Constructor)]
pub struct InstrumentState<
InstrumentData,
ExchangeKey = ExchangeIndex,
AssetKey = AssetIndex,
InstrumentKey = InstrumentIndex,
> {
pub key: InstrumentKey,
pub instrument: Instrument<ExchangeKey, AssetKey>,
pub tear_sheet: TearSheetGenerator,
pub position: PositionManager<InstrumentKey>,
pub orders: Orders<ExchangeKey, InstrumentKey>,
pub data: InstrumentData,
}
impl<InstrumentData, ExchangeKey, AssetKey, InstrumentKey>
InstrumentState<InstrumentData, ExchangeKey, AssetKey, InstrumentKey>
{
pub fn update_from_account_snapshot(
&mut self,
snapshot: &InstrumentAccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>,
) where
ExchangeKey: Debug + Clone,
InstrumentKey: Debug + Clone,
AssetKey: Debug + Clone,
{
for order in &snapshot.orders {
self.update_from_order_snapshot(Snapshot(order))
}
}
pub fn update_from_order_snapshot(
&mut self,
order: Snapshot<&Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>>,
) where
ExchangeKey: Debug + Clone,
AssetKey: Debug + Clone,
InstrumentKey: Debug + Clone,
{
self.orders.update_from_order_snapshot(order);
}
pub fn update_from_cancel_response(
&mut self,
response: &OrderResponseCancel<ExchangeKey, AssetKey, InstrumentKey>,
) where
ExchangeKey: Debug + Clone,
AssetKey: Debug + Clone,
InstrumentKey: Debug + Clone,
{
self.orders
.update_from_cancel_response::<AssetKey>(response);
}
pub fn update_from_trade(
&mut self,
trade: &Trade<QuoteAsset, InstrumentKey>,
) -> Option<PositionExited<QuoteAsset, InstrumentKey>>
where
InstrumentKey: Debug + Clone + PartialEq,
{
self.position
.update_from_trade(trade)
.inspect(|closed| self.tear_sheet.update_from_position(closed))
}
pub fn update_from_market(
&mut self,
event: &MarketEvent<InstrumentKey, InstrumentData::MarketEventKind>,
) where
InstrumentData: InstrumentDataState<ExchangeKey, AssetKey, InstrumentKey>,
{
self.data.process(event);
let Some(position) = &mut self.position.current else {
return;
};
let Some(price) = self.data.price() else {
return;
};
position.update_pnl_unrealised(price);
}
}
pub fn generate_unindexed_instrument_account_snapshot<
InstrumentData,
ExchangeKey,
AssetKey,
InstrumentKey,
>(
exchange: ExchangeId,
state: &InstrumentState<InstrumentData, ExchangeKey, AssetKey, InstrumentKey>,
) -> InstrumentAccountSnapshot<ExchangeId, AssetNameExchange, InstrumentNameExchange>
where
ExchangeKey: Debug + Clone,
InstrumentKey: Debug + Clone,
{
let InstrumentState {
key: _,
instrument,
tear_sheet: _,
position: _,
orders,
data: _,
} = state;
InstrumentAccountSnapshot {
instrument: instrument.name_exchange.clone(),
orders: orders
.orders()
.filter_map(|order| {
let Order {
key,
side,
price,
quantity,
kind,
time_in_force,
state: ActiveOrderState::Open(open),
} = order
else {
return None;
};
Some(Order {
key: OrderKey {
exchange,
instrument: instrument.name_exchange.clone(),
strategy: key.strategy.clone(),
cid: key.cid.clone(),
},
side: *side,
price: *price,
quantity: *quantity,
kind: *kind,
time_in_force: *time_in_force,
state: OrderState::active(open.clone()),
})
})
.collect(),
}
}
pub fn generate_indexed_instrument_states<'a, FnPosMan, FnOrders, FnInsData, InstrumentData>(
instruments: &'a IndexedInstruments,
time_engine_start: DateTime<Utc>,
position_manager_init: FnPosMan,
orders_init: FnOrders,
instrument_data_init: FnInsData,
) -> InstrumentStates<InstrumentData>
where
FnPosMan: Fn() -> PositionManager,
FnOrders: Fn() -> Orders,
FnInsData: Fn(
&'a Keyed<InstrumentIndex, Instrument<Keyed<ExchangeIndex, ExchangeId>, AssetIndex>>,
) -> InstrumentData,
{
InstrumentStates(
instruments
.instruments()
.iter()
.map(|instrument| {
let exchange_index = instrument.value.exchange.key;
(
instrument.value.name_internal.clone(),
InstrumentState::new(
instrument.key,
instrument.value.clone().map_exchange_key(exchange_index),
TearSheetGenerator::init(time_engine_start),
position_manager_init(),
orders_init(),
instrument_data_init(instrument),
),
)
})
.collect(),
)
}