brokapi_bybit/config.rs
1//! Configuration of the two connectors: the Bybit client settings plus the choices of the connector itself
2//! (source label, reconnect pauses, buffer size).
3//!
4//! Both configs wrap a `BybitConfig` from the protocol crate. It holds the key pair, the contour (main, demo or test),
5//! the receive window and the addresses. Build it with `BybitConfig::from_env()` for a real account, or with
6//! `BybitConfig::for_mock(key, secret, url)` for tests against `brokapi-mocks`.
7
8use std::sync::Arc;
9use std::time::Duration;
10
11use brokapi_bybit_protocol::config::BybitConfig;
12use brokapi_bybit_protocol::ws::session::{
13 DEFAULT_RECONNECT_MAX, DEFAULT_RECONNECT_MIN, WsOptions,
14};
15use brokapi_runtime::PriceGrid;
16
17/// Settings of [`MarketDataConnector`](crate::MarketDataConnector).
18///
19/// # Examples
20///
21/// ```
22/// use std::time::Duration;
23/// use brokapi_bybit_protocol::config::BybitConfig;
24/// use brokapi_bybit::MarketDataConfig;
25///
26/// let mut cfg = MarketDataConfig::new(BybitConfig::new("key", "secret"), "bybit-md");
27/// assert_eq!(&*cfg.source, "bybit-md");
28/// // Wait at most 10 seconds between reconnects instead of the default 30.
29/// cfg.reconnect_max = Duration::from_secs(10);
30/// ```
31#[derive(Debug, Clone)]
32pub struct MarketDataConfig {
33 /// Client settings of the Bybit API: key pair, contour, receive window, endpoints.
34 pub bybit: BybitConfig,
35 /// Envelope source label, e.g. `"bybit-md"`.
36 pub source: Arc<str>,
37 /// Pause before the first reconnect of the WebSocket, doubling up to `reconnect_max` (default 0.5 s, as at
38 /// the other brokers).
39 pub reconnect_min: Duration,
40 /// Upper bound of the pause (default 30 s). The pause returns to `reconnect_min` once a connection has
41 /// lived 10 seconds.
42 pub reconnect_max: Duration,
43 /// How long a `subscribe_*` call waits for the broker to confirm the subscription (default 3 s). The call
44 /// returns when the broker has confirmed: what happens after that is delivered. A refusal is returned as
45 /// `Rejected`. If nothing comes in time, the call fails with `Transport` and the subscription is taken back, so
46 /// the call can be repeated.
47 pub subscribe_ack_timeout: Duration,
48}
49
50impl MarketDataConfig {
51 /// Creates a config with the default reconnect pauses (0.5 s up to 30 s).
52 ///
53 /// `source` is the label put in every [`Envelope`](brokapi_core::Envelope) this connector emits, so a bot
54 /// with several connectors can tell them apart.
55 pub fn new(bybit: BybitConfig, source: impl Into<Arc<str>>) -> Self {
56 Self {
57 bybit,
58 source: source.into(),
59 reconnect_min: DEFAULT_RECONNECT_MIN,
60 reconnect_max: DEFAULT_RECONNECT_MAX,
61 subscribe_ack_timeout: Duration::from_secs(3),
62 }
63 }
64
65 pub(crate) fn ws_options(&self) -> WsOptions {
66 // The core is told of every connect: a reconnect voids the order books (`Resync`).
67 WsOptions {
68 announce_connects: true,
69 reconnect_min: self.reconnect_min,
70 reconnect_max: self.reconnect_max,
71 }
72 }
73}
74
75/// Settings of [`UserDataConnector`](crate::UserDataConnector).
76///
77/// The contour (main or demo) and the category come from the `bybit` config.
78///
79/// # Examples
80///
81/// ```
82/// use brokapi_bybit_protocol::config::BybitConfig;
83/// use brokapi_bybit::UserDataConfig;
84///
85/// let mut cfg = UserDataConfig::new(BybitConfig::new("key", "secret"), "bybit-ud");
86/// assert_eq!(cfg.order_state_buffer, 1024);
87/// // A bigger buffer gives a slow bot more room before an overflow closes the trading gate.
88/// cfg.order_state_buffer = 4096;
89/// ```
90#[derive(Debug, Clone)]
91pub struct UserDataConfig {
92 /// Client settings of the Bybit API: key pair, contour, receive window, endpoints.
93 pub bybit: BybitConfig,
94 /// Envelope source label, e.g. `"bybit-ud"`.
95 pub source: Arc<str>,
96 /// Capacity of the lossless buffer of each order state and execution subscription (default 1024 events).
97 /// When it is full, the subscription reports an overflow and the connector becomes degraded: commands are
98 /// refused until the next successful `reconcile`.
99 pub order_state_buffer: usize,
100 /// Pause before the first reconnect of the WebSocket, doubling up to `reconnect_max` (default 0.5 s).
101 pub reconnect_min: Duration,
102 /// Upper bound of the pause (default 30 s).
103 pub reconnect_max: Duration,
104 /// How long a `subscribe_*` call waits for the broker to confirm the subscription (default 3 s), see
105 /// [`MarketDataConfig::subscribe_ack_timeout`].
106 pub subscribe_ack_timeout: Duration,
107 /// Price steps and lot sizes the connector checks orders against (default: empty, only the lot sizes the
108 /// connector reads from the broker). Fill it with [`PriceGrid::learn`] from the trading parameters of the
109 /// instruments you trade. A price off the step is then refused with `Rejected` (`price_off_step`) before
110 /// anything is sent.
111 pub price_grid: PriceGrid,
112}
113
114impl UserDataConfig {
115 /// Creates a config with the default buffer (1024 events) and the default reconnect pauses.
116 ///
117 /// `source` is the label put in every [`Envelope`](brokapi_core::Envelope) this connector emits.
118 pub fn new(bybit: BybitConfig, source: impl Into<Arc<str>>) -> Self {
119 Self {
120 bybit,
121 source: source.into(),
122 order_state_buffer: 1024,
123 reconnect_min: DEFAULT_RECONNECT_MIN,
124 reconnect_max: DEFAULT_RECONNECT_MAX,
125 subscribe_ack_timeout: Duration::from_secs(3),
126 price_grid: PriceGrid::default(),
127 }
128 }
129
130 /// Options of the session: it announces every connect, so the core sees a lost connection
131 /// ([`brokapi_core::Event::Reconnected`]).
132 pub(crate) fn ws_options(&self) -> WsOptions {
133 WsOptions {
134 announce_connects: true,
135 reconnect_min: self.reconnect_min,
136 reconnect_max: self.reconnect_max,
137 }
138 }
139}