1#![allow(dead_code)]
20#![allow(unused_variables)]
21
22use std::{any::Any, cell::RefCell, rc::Rc};
23
24use nautilus_common::{cache::Cache, msgbus::MessageBus};
25use nautilus_core::{AtomicTime, UUID4, UnixNanos};
26use nautilus_model::{
27 accounts::AccountAny,
28 enums::{AccountType, LiquiditySide, OmsType, OrderSide, OrderType},
29 events::{
30 AccountState, OrderAccepted, OrderCancelRejected, OrderCanceled, OrderEventAny,
31 OrderExpired, OrderFilled, OrderModifyRejected, OrderRejected, OrderSubmitted,
32 OrderTriggered, OrderUpdated,
33 },
34 identifiers::{
35 AccountId, ClientId, ClientOrderId, InstrumentId, PositionId, StrategyId, TradeId,
36 TraderId, Venue, VenueOrderId,
37 },
38 types::{AccountBalance, Currency, MarginBalance, Money, Price, Quantity},
39};
40use ustr::Ustr;
41
42use crate::messages::{
43 BatchCancelOrders, CancelAllOrders, CancelOrder, ModifyOrder, QueryOrder, SubmitOrder,
44 SubmitOrderList,
45};
46
47pub struct ExecutionClient {
48 pub trader_id: TraderId,
49 pub client_id: ClientId,
50 pub venue: Venue,
51 pub oms_type: OmsType,
52 pub account_id: AccountId,
53 pub account_type: AccountType,
54 pub base_currency: Option<Currency>,
55 pub is_connected: bool,
56 clock: &'static AtomicTime,
57 cache: Rc<RefCell<Cache>>,
58 msgbus: Rc<RefCell<MessageBus>>,
59}
60
61impl ExecutionClient {
62 #[allow(clippy::too_many_arguments)]
63 pub const fn new(
64 trader_id: TraderId,
65 client_id: ClientId,
66 venue: Venue,
67 oms_type: OmsType,
68 account_id: AccountId,
69 account_type: AccountType,
70 base_currency: Option<Currency>,
71 clock: &'static AtomicTime,
72 cache: Rc<RefCell<Cache>>,
73 msgbus: Rc<RefCell<MessageBus>>,
74 ) -> Self {
75 Self {
76 trader_id,
77 client_id,
78 venue,
79 oms_type,
80 account_id,
81 account_type,
82 base_currency,
83 is_connected: false,
84 clock,
85 cache,
86 msgbus,
87 }
88 }
89
90 #[must_use]
91 pub fn get_account(&self) -> Option<AccountAny> {
92 self.cache.borrow().account(&self.account_id).cloned()
93 }
94
95 pub fn submit_order(&self, command: SubmitOrder) -> anyhow::Result<()> {
98 todo!();
99 }
100
101 pub fn submit_order_list(&self, command: SubmitOrderList) -> anyhow::Result<()> {
102 todo!();
103 }
104
105 pub fn modify_order(&self, command: ModifyOrder) -> anyhow::Result<()> {
106 todo!();
107 }
108
109 pub fn cancel_order(&self, command: CancelOrder) -> anyhow::Result<()> {
110 todo!();
111 }
112
113 pub fn cancel_all_orders(&self, command: CancelAllOrders) -> anyhow::Result<()> {
114 todo!();
115 }
116
117 pub fn batch_cancel_orders(&self, command: BatchCancelOrders) -> anyhow::Result<()> {
118 todo!();
119 }
120
121 pub fn query_order(&self, command: QueryOrder) -> anyhow::Result<()> {
122 todo!();
123 }
124
125 pub fn generate_account_state(
126 &self,
127 balances: Vec<AccountBalance>,
128 margins: Vec<MarginBalance>,
129 reported: bool,
130 ts_event: UnixNanos,
131 ) -> anyhow::Result<()> {
133 let account_state = AccountState::new(
134 self.account_id,
135 self.account_type,
136 balances,
137 margins,
138 reported,
139 UUID4::new(),
140 ts_event,
141 self.clock.get_time_ns(),
142 self.base_currency,
143 );
144 self.send_account_state(account_state);
145 Ok(())
146 }
147
148 pub fn generate_order_submitted(
149 &self,
150 strategy_id: StrategyId,
151 instrument_id: InstrumentId,
152 client_order_id: ClientOrderId,
153 ts_event: UnixNanos,
154 ) {
155 let event = OrderSubmitted::new(
156 self.trader_id,
157 strategy_id,
158 instrument_id,
159 client_order_id,
160 self.account_id,
161 UUID4::new(),
162 ts_event,
163 self.clock.get_time_ns(),
164 );
165 self.send_order_event(OrderEventAny::Submitted(event));
166 }
167
168 pub fn generate_order_rejected(
169 &self,
170 strategy_id: StrategyId,
171 instrument_id: InstrumentId,
172 client_order_id: ClientOrderId,
173 reason: &str,
174 ts_event: UnixNanos,
175 ) {
176 let event = OrderRejected::new(
177 self.trader_id,
178 strategy_id,
179 instrument_id,
180 client_order_id,
181 self.account_id,
182 reason.into(),
183 UUID4::new(),
184 ts_event,
185 self.clock.get_time_ns(),
186 false,
187 );
188 self.send_order_event(OrderEventAny::Rejected(event));
189 }
190
191 pub fn generate_order_accepted(
192 &self,
193 strategy_id: StrategyId,
194 instrument_id: InstrumentId,
195 client_order_id: ClientOrderId,
196 venue_order_id: VenueOrderId,
197 ts_event: UnixNanos,
198 ) {
199 let event = OrderAccepted::new(
200 self.trader_id,
201 strategy_id,
202 instrument_id,
203 client_order_id,
204 venue_order_id,
205 self.account_id,
206 UUID4::new(),
207 ts_event,
208 self.clock.get_time_ns(),
209 false,
210 );
211 self.send_order_event(OrderEventAny::Accepted(event));
212 }
213
214 pub fn generate_order_modify_rejected(
215 &self,
216 strategy_id: StrategyId,
217 instrument_id: InstrumentId,
218 client_order_id: ClientOrderId,
219 venue_order_id: VenueOrderId,
220 reason: &str,
221 ts_event: UnixNanos,
222 ) {
223 let event = OrderModifyRejected::new(
224 self.trader_id,
225 strategy_id,
226 instrument_id,
227 client_order_id,
228 reason.into(),
229 UUID4::new(),
230 ts_event,
231 self.clock.get_time_ns(),
232 false,
233 Some(venue_order_id),
234 Some(self.account_id),
235 );
236 self.send_order_event(OrderEventAny::ModifyRejected(event));
237 }
238
239 pub fn generate_order_cancel_rejected(
240 &self,
241 strategy_id: StrategyId,
242 instrument_id: InstrumentId,
243 client_order_id: ClientOrderId,
244 venue_order_id: VenueOrderId,
245 reason: &str,
246 ts_event: UnixNanos,
247 ) {
248 let event = OrderCancelRejected::new(
249 self.trader_id,
250 strategy_id,
251 instrument_id,
252 client_order_id,
253 reason.into(),
254 UUID4::new(),
255 ts_event,
256 self.clock.get_time_ns(),
257 false,
258 Some(venue_order_id),
259 Some(self.account_id),
260 );
261 self.send_order_event(OrderEventAny::CancelRejected(event));
262 }
263
264 #[allow(clippy::too_many_arguments)]
265 pub fn generate_order_updated(
266 &self,
267 strategy_id: StrategyId,
268 instrument_id: InstrumentId,
269 client_order_id: ClientOrderId,
270 venue_order_id: VenueOrderId,
271 quantity: Quantity,
272 price: Price,
273 trigger_price: Option<Price>,
274 reason: &str,
275 ts_event: UnixNanos,
276 venue_order_id_modified: bool,
277 ) {
278 if !venue_order_id_modified {
279 let cache = self.cache.as_ref().borrow();
280 let existing_order_result = cache.venue_order_id(&client_order_id);
281 if let Some(existing_order) = existing_order_result {
282 if *existing_order != venue_order_id {
283 log::error!(
284 "Existing venue order id {} does not match provided venue order id {}",
285 existing_order,
286 venue_order_id
287 );
288 }
289 }
290 }
291
292 let event = OrderUpdated::new(
293 self.trader_id,
294 strategy_id,
295 instrument_id,
296 client_order_id,
297 quantity,
298 UUID4::new(),
299 ts_event,
300 self.clock.get_time_ns(),
301 false,
302 Some(venue_order_id),
303 Some(self.account_id),
304 Some(price),
305 trigger_price,
306 );
307
308 self.send_order_event(OrderEventAny::Updated(event));
309 }
310
311 pub fn generate_order_canceled(
312 &self,
313 strategy_id: StrategyId,
314 instrument_id: InstrumentId,
315 client_order_id: ClientOrderId,
316 venue_order_id: VenueOrderId,
317 ts_event: UnixNanos,
318 ) {
319 let event = OrderCanceled::new(
320 self.trader_id,
321 strategy_id,
322 instrument_id,
323 client_order_id,
324 UUID4::new(),
325 ts_event,
326 self.clock.get_time_ns(),
327 false,
328 Some(venue_order_id),
329 Some(self.account_id),
330 );
331
332 self.send_order_event(OrderEventAny::Canceled(event));
333 }
334
335 pub fn generate_order_triggered(
336 &self,
337 strategy_id: StrategyId,
338 instrument_id: InstrumentId,
339 client_order_id: ClientOrderId,
340 venue_order_id: VenueOrderId,
341 ts_event: UnixNanos,
342 ) {
343 let event = OrderTriggered::new(
344 self.trader_id,
345 strategy_id,
346 instrument_id,
347 client_order_id,
348 UUID4::new(),
349 ts_event,
350 self.clock.get_time_ns(),
351 false,
352 Some(venue_order_id),
353 Some(self.account_id),
354 );
355
356 self.send_order_event(OrderEventAny::Triggered(event));
357 }
358
359 pub fn generate_order_expired(
360 &self,
361 strategy_id: StrategyId,
362 instrument_id: InstrumentId,
363 client_order_id: ClientOrderId,
364 venue_order_id: VenueOrderId,
365 ts_event: UnixNanos,
366 ) {
367 let event = OrderExpired::new(
368 self.trader_id,
369 strategy_id,
370 instrument_id,
371 client_order_id,
372 UUID4::new(),
373 ts_event,
374 self.clock.get_time_ns(),
375 false,
376 Some(venue_order_id),
377 Some(self.account_id),
378 );
379
380 self.send_order_event(OrderEventAny::Expired(event));
381 }
382
383 #[allow(clippy::too_many_arguments)]
384 pub fn generate_order_filled(
385 &self,
386 strategy_id: StrategyId,
387 instrument_id: InstrumentId,
388 client_order_id: ClientOrderId,
389 venue_order_id: VenueOrderId,
390 venue_position_id: PositionId,
391 trade_id: TradeId,
392 order_side: OrderSide,
393 order_type: OrderType,
394 last_qty: Quantity,
395 last_px: Price,
396 quote_currency: Currency,
397 commission: Money,
398 liquidity_side: LiquiditySide,
399 ts_event: UnixNanos,
400 ) {
401 let event = OrderFilled::new(
402 self.trader_id,
403 strategy_id,
404 instrument_id,
405 client_order_id,
406 venue_order_id,
407 self.account_id,
408 trade_id,
409 order_side,
410 order_type,
411 last_qty,
412 last_px,
413 quote_currency,
414 liquidity_side,
415 UUID4::new(),
416 ts_event,
417 self.clock.get_time_ns(),
418 false,
419 Some(venue_position_id),
420 Some(commission),
421 );
422
423 self.send_order_event(OrderEventAny::Filled(event));
424 }
425
426 fn send_account_state(&self, account_state: AccountState) {
427 let endpoint = Ustr::from("Portfolio.update_account");
428 self.msgbus
429 .borrow()
430 .send(&endpoint, &account_state as &dyn Any);
431 }
432
433 fn send_order_event(&self, event: OrderEventAny) {
434 todo!()
435 }
436
437 }