use crate::engine::{
Processor,
state::{
asset::{AssetStates, filter::AssetFilter},
builder::EngineStateBuilder,
connectivity::ConnectivityStates,
instrument::{
InstrumentStates, data::InstrumentDataState, filter::InstrumentFilter,
generate_unindexed_instrument_account_snapshot,
},
position::PositionExited,
trading::TradingState,
},
};
use barter_data::event::MarketEvent;
use barter_execution::{
AccountEvent, AccountEventKind, UnindexedAccountSnapshot, balance::AssetBalance,
};
use barter_instrument::{
Keyed,
asset::{AssetIndex, QuoteAsset},
exchange::{ExchangeId, ExchangeIndex},
index::IndexedInstruments,
instrument::{Instrument, InstrumentIndex},
};
use barter_integration::collection::{one_or_many::OneOrMany, snapshot::Snapshot};
use derive_more::Constructor;
use fnv::FnvHashMap;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
pub mod asset;
pub mod connectivity;
pub mod instrument;
pub mod order;
pub mod position;
pub mod trading;
pub mod builder;
pub mod global;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Constructor)]
pub struct EngineState<GlobalData, InstrumentData> {
pub trading: TradingState,
pub global: GlobalData,
pub connectivity: ConnectivityStates,
pub assets: AssetStates,
pub instruments: InstrumentStates<InstrumentData, ExchangeIndex, AssetIndex, InstrumentIndex>,
}
impl<GlobalData, InstrumentData> EngineState<GlobalData, InstrumentData> {
pub fn builder<FnInstrumentData>(
instruments: &IndexedInstruments,
global: GlobalData,
instrument_data_init: FnInstrumentData,
) -> EngineStateBuilder<'_, GlobalData, FnInstrumentData>
where
FnInstrumentData: Fn(
&Keyed<InstrumentIndex, Instrument<Keyed<ExchangeIndex, ExchangeId>, AssetIndex>>,
) -> InstrumentData,
{
EngineStateBuilder::new(instruments, global, instrument_data_init)
}
pub fn update_from_account(
&mut self,
event: &AccountEvent,
) -> Option<PositionExited<QuoteAsset>>
where
GlobalData: for<'a> Processor<&'a AccountEvent>,
InstrumentData: for<'a> Processor<&'a AccountEvent>,
{
self.connectivity.update_from_account_event(&event.exchange);
let output = match &event.kind {
AccountEventKind::Snapshot(snapshot) => {
for balance in &snapshot.balances {
self.assets
.asset_index_mut(&balance.asset)
.update_from_balance(Snapshot(balance))
}
for instrument in &snapshot.instruments {
let instrument_state = self
.instruments
.instrument_index_mut(&instrument.instrument);
instrument_state.update_from_account_snapshot(instrument);
instrument_state.data.process(event);
}
None
}
AccountEventKind::BalanceSnapshot(balance) => {
self.assets
.asset_index_mut(&balance.0.asset)
.update_from_balance(balance.as_ref());
None
}
AccountEventKind::OrderSnapshot(order) => {
let instrument_state = self
.instruments
.instrument_index_mut(&order.value().key.instrument);
instrument_state.update_from_order_snapshot(order.as_ref());
instrument_state.data.process(event);
None
}
AccountEventKind::OrderCancelled(response) => {
let instrument_state = self
.instruments
.instrument_index_mut(&response.key.instrument);
instrument_state.update_from_cancel_response(response);
instrument_state.data.process(event);
None
}
AccountEventKind::Trade(trade) => {
let instrument_state = self.instruments.instrument_index_mut(&trade.instrument);
instrument_state.data.process(event);
instrument_state.update_from_trade(trade)
}
};
self.global.process(event);
output
}
pub fn update_from_market(
&mut self,
event: &MarketEvent<InstrumentIndex, InstrumentData::MarketEventKind>,
) where
GlobalData:
for<'a> Processor<&'a MarketEvent<InstrumentIndex, InstrumentData::MarketEventKind>>,
InstrumentData: InstrumentDataState,
{
self.connectivity.update_from_market_event(&event.exchange);
let instrument_state = self.instruments.instrument_index_mut(&event.instrument);
self.global.process(event);
instrument_state.data.process(event);
}
}
impl<GlobalData, InstrumentData> From<&EngineState<GlobalData, InstrumentData>>
for FnvHashMap<ExchangeId, UnindexedAccountSnapshot>
{
fn from(value: &EngineState<GlobalData, InstrumentData>) -> Self {
let EngineState {
trading: _,
global: _,
connectivity,
assets,
instruments,
} = value;
let mut snapshots =
FnvHashMap::with_capacity_and_hasher(connectivity.exchanges.len(), Default::default());
for (index, exchange) in connectivity.exchange_ids().enumerate() {
snapshots.insert(
*exchange,
UnindexedAccountSnapshot {
exchange: *exchange,
balances: assets
.filtered(&AssetFilter::Exchanges(OneOrMany::One(*exchange)))
.map(AssetBalance::from)
.collect(),
instruments: instruments
.instruments(&InstrumentFilter::Exchanges(OneOrMany::One(ExchangeIndex(
index,
))))
.map(|snapshot| {
generate_unindexed_instrument_account_snapshot(*exchange, snapshot)
})
.collect::<Vec<_>>(),
},
);
}
snapshots
}
}