Skip to main content

Crate brokapi_conformance

Crate brokapi_conformance 

Source
Expand description

Shared behaviour scenarios that every broker adapter must pass against its own mock.

This is the test layer of the connector library. Each adapter (brokapi-bcs, brokapi-tbank, brokapi-finam, …) implements the capability traits of [brokapi_core], and each runs the same scenarios from this crate against its own in-process broker imitation (see brokapi-mocks). So all brokers behave the same through the traits: the same refusal is the same [brokapi_core::Error], the same stream gives the same envelope. The scenarios use only the traits, never an adapter’s own types.

A scenario is an async fn that takes the connector (and sometimes the event receiver). It returns () and panics when the adapter breaks the contract. The panic message starts with [conformance:<scenario name>] and gives the reason, so the failing scenario and the cause are visible in the test output. A scenario that passes leaves the connector usable, with its test orders cancelled.

What a scenario proves is that the adapter agrees with the mock. The mocks are written from the broker documentation. They do not prove how the live broker behaves.

The mock behind the adapter must:

Trading scenarios need the command gate open, so call reconcile first on a user data connector. Until the first reconcile every command fails with [brokapi_core::Error::NotReconciled].

The book is at https://brokapi.ru/docs/.

§Examples

The usual adapter test: start the mock, start the connector on it, run the scenarios, shut down. Here the adapter is the BCS connector.

use brokapi_bcs::limits::default_limits;
use brokapi_bcs::{UserDataConfig, UserDataConnector};
use brokapi_core::{InstrumentId, InstrumentKey, NativeId, ShutdownMode};
use brokapi_runtime::BrokerLimiter;

// `ud` is a connected user data connector, `sber` the test instrument.
brokapi_conformance::reconcile(&ud).await;
brokapi_conformance::place_and_cancel(&ud, &sber, Price::from(1)).await;

Constants§

EVENT_TIMEOUT
How long a scenario waits for a pushed event, or for one command, before it fails.
LOT
One lot of the instruments the mocks serve, in units: 10. The scenarios order whole lots, because an order of units that is not a whole number of lots is refused (invalid_qty) by the connectors that know the lot. A connector that does not look the lot up itself (BCS, Finam) is told the lot of the test instrument with price_grid().set_lot(..) in the test.
REJECT_PRICE
A limit order at exactly this price is refused by every mock (the broker says no).

Functions§

active_orders_lifecycle
active_orders follows the order: a placed order is listed with its details, a cancelled one is gone.
duplicate_place
A cid is used for one place at most: the second place with it is refused locally and creates nothing.
executions
Own executions: the history works, and a fill arrives as an Execution event and in the history.
executions_history_is_complete
The history of own trades is complete: expected trades come back, none is dropped or doubled.
foreign_instrument_id
An instrument id of another broker’s kind is a configuration error, and nothing is sent.
gate_checked_after_the_queue
A command that waits in the queue of its instrument is checked against the gate again when its turn comes: a gate that closed meanwhile stops it, and nothing is sent.
instrument_lookup
Instrument directory: a search finds the instrument, and its trading parameters are usable for order sizing.
invalid_qty
A quantity the broker cannot take is refused before anything is sent, and the cid stays usable.
lots
n lots of the test instruments, in units.
market_data_history
The tape, candles, trading status and schedule of one instrument.
market_data_history_without_schedule
The tape, candles and trading status of one instrument: market_data_history without the schedule, for a broker whose API has no timetable of sessions (its schedule answers Unsupported, which this scenario does not call).
market_data_streams
Market trades, quotes and candles as streams, each for the right instrument and tagged with our source and subscription id.
market_subscribe_returns_while_the_stream_opens_late
The soft variant of market_subscribe_waits_for_the_stream (see subscribe_returns_while_the_stream_opens_late): subscribe_order_book returns Ok when the stream is not open in time, and after release the books arrive on that subscription.
market_subscribe_waits_for_the_stream
subscribe_order_book returns when the stream is open, and a stream that does not open is an error.
next_matching
Reads envelopes from rx until pred accepts one, and returns that one.
order_book_resync
The order book stream is void after a break: a [Event::Resync] follows, then a fresh snapshot.
order_book_snapshot
REST order book: the right instrument, the asked depth, sorted best-first, not crossed.
order_book_stream
Order book stream: subscribe, then an order book envelope arrives tagged with our source and subscription id.
order_state_events
The order stream: placing an order gives an event for our cid, cancelling it gives a Cancelled event.
order_state_unknown_cid
order_state of a cid the broker has never seen is a refusal: [Error::Rejected] with code not_found ([brokapi_core::NOT_FOUND]), spelled the same at every broker.
place_and_cancel
Places a far-from-market limit order, reads its state by cid, cancels it.
place_without_answer_is_unknown
A place the broker never answers is Unknown: not repeated, not Rejected, resolved by asking.
portfolio
Portfolio: the snapshot works, and a portfolio update arrives after subscribe.
reconcile
Reconcile: an empty ledger touches nothing, and an unknown cid is reported as closed offline.
rejected_order_does_not_block_the_instrument
An order the broker refuses must not block the instrument: the next order on the same instrument goes through.
replace_order
replace: where the broker has it the order moves to a new cid, where it has not, replace says Unsupported.
stop_order_far_from_market
Stop orders, the common path: place, list, cancel by cid, then a stop-limit cancelled by broker id.
stop_orders_unsupported
A connector without stop orders says so: every stop method answers [brokapi_core::Error::Unsupported].
stop_without_answer_keeps_its_cid
A stop order the broker took, whose answer was lost, comes back in the list with its cid.
stream_cut_degrades_until_reconcile
The stream of own orders breaks: the bot is told, the gate closes, reconcile opens it.
subscribe_returns_while_the_stream_opens_late
The soft variant of subscribe_waits_for_the_stream, for a broker whose stream may announce itself only with its first message (Finam, gRPC): subscribe_* waits for the stream, and when it does not open in time it still returns Ok and the stream goes on opening in the background.
subscribe_waits_for_the_stream
subscribe_order_state and subscribe_executions return when the stream is open, not before.
unknown_instrument
A read of an instrument the broker does not know is Rejected(not_found), the same at every broker.
unsubscribe
Unsubscribing an active subscription succeeds, and doing it again is refused the same way at every broker.
unsubscribe_unknown
Unsubscribing an id the connector never gave out is refused: [Error::Rejected] with code unknown_subscription. The same answer at every broker, so a bot needs one branch for it.

Type Aliases§

SubscribeCall
The future of one subscribe_* call, as the scenarios of this section hand it to the adapter.