pub trait ExecutionSource: Send + Sync {
// Required methods
fn executions<'life0, 'async_trait>(
&'life0 self,
range: TimeRange,
) -> Pin<Box<dyn Future<Output = Result<Vec<Execution>, Error>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn subscribe_executions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}Expand description
Your own fills: the history and the live stream.
An Execution is one fill of one of your orders. Public deals of the market are in
MarketDataSource. The stream is
Backpressure::Lossless: a fill must not be lost, so an
overflow is announced with Event::Overflow and trading stops until
OrderExecutor::reconcile.
§Examples
use std::time::Duration;
use brokapi_bcs::limits::default_limits;
use brokapi_bcs::{UserDataConfig, UserDataConnector};
use brokapi_core::{
ClientOrderId, Event, ExecutionSource, InstrumentId, InstrumentKey, NativeId, OrderExecutor,
OrderType, PlaceOrderRequest, Price, Qty, ShutdownMode, Side, TimeRange, UnixNanos,
};
use brokapi_runtime::BrokerLimiter;
let (events_tx, mut events) = tokio::sync::mpsc::channel(256);
let limiter = BrokerLimiter::new(&default_limits());
let ud = UserDataConnector::start(UserDataConfig::new(cfg, "bcs-ud"), limiter, events_tx).await?;
ud.reconcile(&[]).await?;
// Follow the fills as they happen.
let sub = ud.subscribe_executions().await?;
let cid = ClientOrderId::new_v4();
ud.place(PlaceOrderRequest {
cid,
instrument: InstrumentId::new(
InstrumentKey::new("SBER", "TQBR"),
NativeId::TickerClass { ticker: "SBER".into(), class_code: "TQBR".into() },
),
side: Side::Buy,
order_type: OrderType::Limit,
qty: Qty::from(2),
price: Some(Price::from(100)),
})
.await?;
let fill = tokio::time::timeout(Duration::from_secs(8), async {
while let Some(env) = events.recv().await {
if let Event::Execution(x) = env.payload {
assert_eq!(env.sub, Some(sub));
return Some(x);
}
}
None
})
.await?
.expect("a fill arrived");
assert_eq!(fill.cid, Some(cid));
assert!(fill.qty.is_positive());
// The history of the day, the same fill with its trade id.
let everything = TimeRange::new(UnixNanos::ZERO, UnixNanos::from_nanos(i64::MAX / 2));
let history = ud.executions(everything).await?;
assert!(history.iter().any(|x| x.trade_id.len() > 0));
ud.shutdown(ShutdownMode::Immediate).await;Required Methods§
Sourcefn executions<'life0, 'async_trait>(
&'life0 self,
range: TimeRange,
) -> Pin<Box<dyn Future<Output = Result<Vec<Execution>, Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn executions<'life0, 'async_trait>(
&'life0 self,
range: TimeRange,
) -> Pin<Box<dyn Future<Output = Result<Vec<Execution>, Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Reads your fills in range.
Use it to find what happened to an order after Error::Unknown, or to catch up after a
gap. cid of an Execution is None when the broker does not echo it (the BCS history
does not), match by broker_order_id then. commission is 0.0 where the broker gives none
(BCS history). How far back it goes is decided by the broker.
§Contract
- When: at any time. Reads only. The way to catch up on fills after
Error::Unknown, anEvent::Overflow(from itslost_from) or a restart.
§Errors
Error::RateLimited,Error::Transport: wait or repeat later.Error::Rejectedwhen the broker refuses the request.
§Examples
use brokapi_core::{ExecutionSource, TimeRange, UnixNanos};
let everything = TimeRange::new(UnixNanos::ZERO, UnixNanos::from_nanos(i64::MAX / 2));
let history = ud.executions(everything).await?;
// A fresh account has no fills. The call still works.
assert!(history.is_empty());Sourcefn subscribe_executions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn subscribe_executions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Starts the stream of your fills.
Each fill arrives once as Event::Execution, tagged with the
returned id. The stream is lossless and has a buffer size from the connector config: keep
draining your channel. Subscribe before you place: the call returns when the stream is open, so a
fill after it cannot be missed, but fills that happened before are not delivered (read
executions to catch up). There is no way to end this subscription except
shutting the connector down.
§Contract
- When: once per connector, before the first
OrderExecutor::place. Allowed while the gate is closed. - Guarantee: returns only when the stream is open, like
OrderExecutor::subscribe_order_state. Lossless like it: a loss is announced withEvent::Overflow.
§Errors
Error::Unsupportedwhen the broker has no fill stream (UserDataCaps::streams_executionsisfalse). Pollexecutionsyourself then.Error::Transportwhen the subscription could not be made, also when the stream did not open in time.
§Examples
See the example of the trait, which receives a fill.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".