use crate::engine::state::{
EngineState,
instrument::{InstrumentState, data::InstrumentDataState, filter::InstrumentFilter},
position::Position,
};
use barter_execution::order::{
OrderKey, OrderKind, TimeInForce,
id::{ClientOrderId, StrategyId},
request::{OrderRequestCancel, OrderRequestOpen, RequestOpen},
};
use barter_instrument::{
Side, asset::AssetIndex, exchange::ExchangeIndex, instrument::InstrumentIndex,
};
use rust_decimal::Decimal;
pub trait ClosePositionsStrategy<
ExchangeKey = ExchangeIndex,
AssetKey = AssetIndex,
InstrumentKey = InstrumentIndex,
>
{
type State;
fn close_positions_requests<'a>(
&'a self,
state: &'a Self::State,
filter: &'a InstrumentFilter<ExchangeKey, AssetKey, InstrumentKey>,
) -> (
impl IntoIterator<Item = OrderRequestCancel<ExchangeKey, InstrumentKey>> + 'a,
impl IntoIterator<Item = OrderRequestOpen<ExchangeKey, InstrumentKey>> + 'a,
)
where
ExchangeKey: 'a,
AssetKey: 'a,
InstrumentKey: 'a;
}
pub fn close_open_positions_with_market_orders<'a, GlobalData, InstrumentData>(
strategy_id: &'a StrategyId,
state: &'a EngineState<GlobalData, InstrumentData>,
filter: &'a InstrumentFilter,
gen_cid: impl Fn(&InstrumentState<InstrumentData>) -> ClientOrderId + Copy + 'a,
) -> (
impl IntoIterator<Item = OrderRequestCancel<ExchangeIndex, InstrumentIndex>> + 'a,
impl IntoIterator<Item = OrderRequestOpen<ExchangeIndex, InstrumentIndex>> + 'a,
)
where
InstrumentData: InstrumentDataState,
ExchangeIndex: 'a,
AssetIndex: 'a,
InstrumentIndex: 'a,
{
let open_requests = state
.instruments
.instruments(filter)
.filter_map(move |state| {
let position = state.position.current.as_ref()?;
let price = state.data.price()?;
Some(build_ioc_market_order_to_close_position(
state.instrument.exchange,
position,
strategy_id.clone(),
price,
|| gen_cid(state),
))
});
(std::iter::empty(), open_requests)
}
pub fn build_ioc_market_order_to_close_position<ExchangeKey, AssetKey, InstrumentKey>(
exchange: ExchangeKey,
position: &Position<AssetKey, InstrumentKey>,
strategy_id: StrategyId,
price: Decimal,
gen_cid: impl Fn() -> ClientOrderId,
) -> OrderRequestOpen<ExchangeKey, InstrumentKey>
where
ExchangeKey: Clone,
InstrumentKey: Clone,
{
OrderRequestOpen {
key: OrderKey {
exchange: exchange.clone(),
instrument: position.instrument.clone(),
strategy: strategy_id,
cid: gen_cid(),
},
state: RequestOpen {
side: match position.side {
Side::Buy => Side::Sell,
Side::Sell => Side::Buy,
},
price,
quantity: position.quantity_abs,
kind: OrderKind::Market,
time_in_force: TimeInForce::ImmediateOrCancel,
},
}
}