Struct UserDataConnector
pub struct UserDataConnector { /* private fields */ }Expand description
The user data connector of Bybit for one account: implements [OrderExecutor], [StopOrderExecutor],
[ExecutionSource] and [PortfolioSource].
Commands (place, cancel) go by HTTP, one request each, never repeated: a lost answer is [Error::Unknown]. The
streams (own orders, fills, positions, wallet) come over one private WebSocket session that logs in with the key,
reconnects on its own and restores its subscriptions. The account must be in one-way position mode (the default);
the unified trading account is the only kind V5 knows.
Quantities are in units of the base coin (0.001 BTC). The connector reads the quantity step, the smallest order and
the price step of a symbol once, and refuses an order off the grid before anything is sent.
The cid goes to the exchange as the orderLinkId of the order, which is how it comes back in the order list, the
stream and the fills. A conditional order (a stop order) is an order with a trigger price: it is placed and cancelled
through the same methods, and listed apart in [StopOrderExecutor::active_stop_orders].
§Examples
use brokapi_bybit::limits::default_limits;
use brokapi_bybit::util::instrument_id;
use brokapi_bybit::{UserDataConfig, UserDataConnector};
use brokapi_core::{
ClientOrderId, Decimal, OrderExecutor, OrderType, PlaceOrderRequest, Price, Qty, ShutdownMode, Side, dec,
};
use brokapi_runtime::BrokerLimiter;
use tokio::sync::mpsc;
let (tx, _events) = mpsc::channel(256);
let ud = UserDataConnector::start(UserDataConfig::new(cfg, "bybit-ud"), BrokerLimiter::new(&default_limits()), tx).await?;
// Commands wait for the first reconcile.
ud.reconcile(&[]).await?;
let cid = ClientOrderId::new_v4();
let ack = ud
.place(PlaceOrderRequest {
cid,
instrument: instrument_id("MOCKUSDT", "linear"),
side: Side::Buy,
order_type: OrderType::Limit,
qty: Qty::from(10), // one step of the mock symbol
price: Some(Price::new(dec!(1.00))),
})
.await?;
assert_eq!(ack.cid, cid);
ud.cancel(cid).await?;
ud.shutdown(ShutdownMode::Immediate).await;Implementations§
§impl UserDataConnector
impl UserDataConnector
pub async fn start(
cfg: UserDataConfig,
limiter: Arc<BrokerLimiter>,
out: Sender<Envelope>,
) -> Result<UserDataConnector, Error>
pub async fn start( cfg: UserDataConfig, limiter: Arc<BrokerLimiter>, out: Sender<Envelope>, ) -> Result<UserDataConnector, Error>
Starts the connector: reads the clock of the exchange, checks the key pair with a read of the wallet, and opens
the private WebSocket session in the background. Commands wait for the first
reconcile.
§Errors
[Error::Config] when the client cannot be built or the exchange refuses the key pair (a key of the demo account
used on the main host, a wrong secret, a missing right, an IP not on the list of the key);
[Error::Transport] when the exchange cannot be reached.
pub fn raw(&self) -> BybitRaw
pub fn raw(&self) -> BybitRaw
Direct access to any API method with this connector’s key and rate limiter. See BybitRaw.
pub fn price_grid(&self) -> &PriceGrid
pub fn price_grid(&self) -> &PriceGrid
The price steps and quantity steps the connector checks orders against, on top of the rules it reads from the
exchange. Fill it with learn to be stricter.
pub fn caps(&self) -> UserDataCaps
pub fn caps(&self) -> UserDataCaps
What the connector can do.
place_idempotency:LabelOnly. The documentation says anorderLinkIdis unique and a second order with the same one is refused (code 110072), but how long the exchange remembers a closed order’s id is not stated and not checked on a live account. The library never repeats a place whatever the value.supports_replace: no. An amendment of the exchange keeps the client id of the order, and the sharedreplacepromises a new order under a new cid. The amendment is available throughrawandBybitHttpClient::amend_order.supports_stop_ordersandstreams_executions: yes.ws_rpcandordered_command_channel: no (commands go by HTTP; the exchange has a WebSocket trade channel that this connector does not use, and the demo contour has none).sandbox: yes on the demo contour (virtual money), no on the main one.
pub async fn shutdown(self, mode: ShutdownMode) -> ShutdownReport
pub async fn shutdown(self, mode: ShutdownMode) -> ShutdownReport
Stops the connector. Unless the mode is Immediate it closes the trading gate first; Graceful also lets the
bot’s channel take what is still buffered. Orders at the exchange are not touched.
Trait Implementations§
§impl Connector for UserDataConnector
impl Connector for UserDataConnector
§fn caps(&self) -> UserDataCaps
fn caps(&self) -> UserDataCaps
§fn shutdown<'async_trait>(
self,
mode: ShutdownMode,
) -> Pin<Box<dyn Future<Output = ShutdownReport> + Send + 'async_trait>>where
UserDataConnector: 'async_trait,
fn shutdown<'async_trait>(
self,
mode: ShutdownMode,
) -> Pin<Box<dyn Future<Output = ShutdownReport> + Send + 'async_trait>>where
UserDataConnector: 'async_trait,
Error::Unknown], see [ShutdownReport]) and ends its tasks. Takes the connector by value, so it
cannot be used afterwards.§impl ExecutionSource for UserDataConnector
impl ExecutionSource for UserDataConnector
§fn executions<'life0, 'async_trait>(
&'life0 self,
range: TimeRange,
) -> Pin<Box<dyn Future<Output = Result<Vec<Execution>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn executions<'life0, 'async_trait>(
&'life0 self,
range: TimeRange,
) -> Pin<Box<dyn Future<Output = Result<Vec<Execution>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
range. Read more§fn subscribe_executions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn subscribe_executions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§impl OrderExecutor for UserDataConnector
impl OrderExecutor for UserDataConnector
§fn place<'life0, 'async_trait>(
&'life0 self,
req: PlaceOrderRequest,
) -> Pin<Box<dyn Future<Output = Result<OrderAck, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn place<'life0, 'async_trait>(
&'life0 self,
req: PlaceOrderRequest,
) -> Pin<Box<dyn Future<Output = Result<OrderAck, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn cancel<'life0, 'async_trait>(
&'life0 self,
cid: Uuid,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn cancel<'life0, 'async_trait>(
&'life0 self,
cid: Uuid,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn replace<'life0, 'async_trait>(
&'life0 self,
_req: ReplaceOrderRequest,
) -> Pin<Box<dyn Future<Output = Result<OrderAck, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn replace<'life0, 'async_trait>(
&'life0 self,
_req: ReplaceOrderRequest,
) -> Pin<Box<dyn Future<Output = Result<OrderAck, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn order_state<'life0, 'async_trait>(
&'life0 self,
cid: Uuid,
) -> Pin<Box<dyn Future<Output = Result<OrderSnapshot, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn order_state<'life0, 'async_trait>(
&'life0 self,
cid: Uuid,
) -> Pin<Box<dyn Future<Output = Result<OrderSnapshot, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn active_orders<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<OrderSnapshot>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn active_orders<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<OrderSnapshot>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn subscribe_order_state<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn subscribe_order_state<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn reconcile<'life0, 'life1, 'async_trait>(
&'life0 self,
ledger: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<ReconcileReport, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
UserDataConnector: 'async_trait,
fn reconcile<'life0, 'life1, 'async_trait>(
&'life0 self,
ledger: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<ReconcileReport, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
UserDataConnector: 'async_trait,
§impl PortfolioSource for UserDataConnector
impl PortfolioSource for UserDataConnector
§fn portfolio<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Portfolio, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn portfolio<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Portfolio, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn positions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<Position>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn positions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<Position>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn balances<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<Balance>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn balances<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<Balance>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn subscribe_portfolio<'life0, 'async_trait>(
&'life0 self,
opts: SubscribeOpts,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn subscribe_portfolio<'life0, 'async_trait>(
&'life0 self,
opts: SubscribeOpts,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§impl StopOrderExecutor for UserDataConnector
impl StopOrderExecutor for UserDataConnector
§fn place_stop<'life0, 'async_trait>(
&'life0 self,
req: PlaceStopOrderRequest,
) -> Pin<Box<dyn Future<Output = Result<OrderAck, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn place_stop<'life0, 'async_trait>(
&'life0 self,
req: PlaceStopOrderRequest,
) -> Pin<Box<dyn Future<Output = Result<OrderAck, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn cancel_stop<'life0, 'async_trait>(
&'life0 self,
stop: StopOrderRef,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn cancel_stop<'life0, 'async_trait>(
&'life0 self,
stop: StopOrderRef,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn active_stop_orders<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<StopOrderSnapshot>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn active_stop_orders<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<StopOrderSnapshot>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
§fn subscribe_stop_orders<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
fn subscribe_stop_orders<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SubscriptionId, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
UserDataConnector: 'async_trait,
Unsupported where the broker has no such stream. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for UserDataConnector
impl !UnwindSafe for UserDataConnector
impl Freeze for UserDataConnector
impl Send for UserDataConnector
impl Sync for UserDataConnector
impl Unpin for UserDataConnector
impl UnsafeUnpin for UserDataConnector
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].