Skip to main content

nautilus_common/clients/
execution.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Execution client trait definition.
17
18use async_trait::async_trait;
19use nautilus_core::UnixNanos;
20use nautilus_model::{
21    accounts::AccountAny,
22    enums::OmsType,
23    identifiers::{
24        AccountId, ClientId, ClientOrderId, InstrumentId, StrategyId, Venue, VenueOrderId,
25    },
26    instruments::InstrumentAny,
27    reports::{ExecutionMassStatus, FillReport, OrderStatusReport, PositionStatusReport},
28    types::{AccountBalance, MarginBalance},
29};
30
31use super::log_not_implemented;
32use crate::messages::execution::{
33    BatchCancelOrders, CancelAllOrders, CancelOrder, GenerateFillReports,
34    GenerateOrderStatusReport, GenerateOrderStatusReports, GeneratePositionStatusReports,
35    ModifyOrder, QueryAccount, QueryOrder, SubmitOrder, SubmitOrderList,
36};
37
38/// Defines the interface for an execution client managing order operations.
39///
40/// # Thread Safety
41///
42/// Client instances are not intended to be sent across threads. The `?Send` bound
43/// allows implementations to hold non-Send state for any Python interop.
44#[async_trait(?Send)]
45pub trait ExecutionClient {
46    fn is_connected(&self) -> bool;
47    fn client_id(&self) -> ClientId;
48    fn account_id(&self) -> AccountId;
49    fn venue(&self) -> Venue;
50    fn oms_type(&self) -> OmsType;
51    fn get_account(&self) -> Option<AccountAny>;
52
53    /// Generates and publishes the account state event.
54    ///
55    /// # Errors
56    ///
57    /// Returns an error if generating the account state fails.
58    fn generate_account_state(
59        &self,
60        balances: Vec<AccountBalance>,
61        margins: Vec<MarginBalance>,
62        reported: bool,
63        ts_event: UnixNanos,
64    ) -> anyhow::Result<()>;
65
66    /// Starts the execution client.
67    ///
68    /// # Errors
69    ///
70    /// Returns an error if the client fails to start.
71    fn start(&mut self) -> anyhow::Result<()>;
72
73    /// Stops the execution client.
74    ///
75    /// # Errors
76    ///
77    /// Returns an error if the client fails to stop.
78    fn stop(&mut self) -> anyhow::Result<()>;
79
80    /// Connects the client to the execution venue.
81    ///
82    /// # Errors
83    ///
84    /// Returns an error if connection fails.
85    async fn connect(&mut self) -> anyhow::Result<()> {
86        Ok(())
87    }
88
89    /// Disconnects the client from the execution venue.
90    ///
91    /// # Errors
92    ///
93    /// Returns an error if disconnection fails.
94    async fn disconnect(&mut self) -> anyhow::Result<()> {
95        Ok(())
96    }
97
98    /// Submits a single order command to the execution venue.
99    ///
100    /// # Errors
101    ///
102    /// Returns an error if submission fails.
103    fn submit_order(&self, cmd: &SubmitOrder) -> anyhow::Result<()> {
104        log_not_implemented(cmd);
105        Ok(())
106    }
107
108    /// Submits a list of orders to the execution venue.
109    ///
110    /// # Errors
111    ///
112    /// Returns an error if submission fails.
113    fn submit_order_list(&self, cmd: &SubmitOrderList) -> anyhow::Result<()> {
114        log_not_implemented(cmd);
115        Ok(())
116    }
117
118    /// Modifies an existing order.
119    ///
120    /// # Errors
121    ///
122    /// Returns an error if modification fails.
123    fn modify_order(&self, cmd: &ModifyOrder) -> anyhow::Result<()> {
124        log_not_implemented(cmd);
125        Ok(())
126    }
127
128    /// Cancels a specific order.
129    ///
130    /// # Errors
131    ///
132    /// Returns an error if cancellation fails.
133    fn cancel_order(&self, cmd: &CancelOrder) -> anyhow::Result<()> {
134        log_not_implemented(cmd);
135        Ok(())
136    }
137
138    /// Cancels all orders.
139    ///
140    /// # Errors
141    ///
142    /// Returns an error if cancellation fails.
143    fn cancel_all_orders(&self, cmd: &CancelAllOrders) -> anyhow::Result<()> {
144        log_not_implemented(cmd);
145        Ok(())
146    }
147
148    /// Cancels a batch of orders.
149    ///
150    /// # Errors
151    ///
152    /// Returns an error if batch cancellation fails.
153    fn batch_cancel_orders(&self, cmd: &BatchCancelOrders) -> anyhow::Result<()> {
154        log_not_implemented(cmd);
155        Ok(())
156    }
157
158    /// Queries the status of an account.
159    ///
160    /// # Errors
161    ///
162    /// Returns an error if the query fails.
163    fn query_account(&self, cmd: &QueryAccount) -> anyhow::Result<()> {
164        log_not_implemented(cmd);
165        Ok(())
166    }
167
168    /// Queries the status of an order.
169    ///
170    /// # Errors
171    ///
172    /// Returns an error if the query fails.
173    fn query_order(&self, cmd: &QueryOrder) -> anyhow::Result<()> {
174        log_not_implemented(cmd);
175        Ok(())
176    }
177
178    /// Generates a single order status report.
179    ///
180    /// # Errors
181    ///
182    /// Returns an error if report generation fails.
183    async fn generate_order_status_report(
184        &self,
185        cmd: &GenerateOrderStatusReport,
186    ) -> anyhow::Result<Option<OrderStatusReport>> {
187        log_not_implemented(cmd);
188        Ok(None)
189    }
190
191    /// Generates multiple order status reports.
192    ///
193    /// # Errors
194    ///
195    /// Returns an error if report generation fails.
196    async fn generate_order_status_reports(
197        &self,
198        cmd: &GenerateOrderStatusReports,
199    ) -> anyhow::Result<Vec<OrderStatusReport>> {
200        log_not_implemented(cmd);
201        Ok(Vec::new())
202    }
203
204    /// Generates fill reports based on execution results.
205    ///
206    /// # Errors
207    ///
208    /// Returns an error if fill report generation fails.
209    async fn generate_fill_reports(
210        &self,
211        cmd: GenerateFillReports,
212    ) -> anyhow::Result<Vec<FillReport>> {
213        log_not_implemented(&cmd);
214        Ok(Vec::new())
215    }
216
217    /// Generates position status reports.
218    ///
219    /// # Errors
220    ///
221    /// Returns an error if generation fails.
222    async fn generate_position_status_reports(
223        &self,
224        cmd: &GeneratePositionStatusReports,
225    ) -> anyhow::Result<Vec<PositionStatusReport>> {
226        log_not_implemented(cmd);
227        Ok(Vec::new())
228    }
229
230    /// Generates mass status for executions.
231    ///
232    /// # Errors
233    ///
234    /// Returns an error if status generation fails.
235    async fn generate_mass_status(
236        &self,
237        lookback_mins: Option<u64>,
238    ) -> anyhow::Result<Option<ExecutionMassStatus>> {
239        log_not_implemented(&lookback_mins);
240        Ok(None)
241    }
242
243    /// Registers an external order for tracking by the execution client.
244    ///
245    /// This is called after reconciliation creates an external order, allowing the
246    /// execution client to track it for subsequent events (e.g., cancellations).
247    fn register_external_order(
248        &self,
249        _client_order_id: ClientOrderId,
250        _venue_order_id: VenueOrderId,
251        _instrument_id: InstrumentId,
252        _strategy_id: StrategyId,
253        _ts_init: UnixNanos,
254    ) {
255        // Default no-op implementation
256    }
257
258    /// Handles an instrument update received via the message bus.
259    ///
260    /// Exec clients that need live instrument updates (e.g. for internal maps)
261    /// can override this to process instruments for their venue.
262    fn on_instrument(&mut self, _instrument: InstrumentAny) {
263        // Default no-op
264    }
265}