1use crate::order::{
2 id::StrategyId,
3 request::{OrderRequestCancel, OrderRequestOpen, RequestCancel, RequestOpen},
4 state::UnindexedOrderState,
5};
6use chrono::{DateTime, Utc};
7use derive_more::{Constructor, Display};
8use id::ClientOrderId;
9use rust_decimal::Decimal;
10use rustrade_instrument::{
11 Side,
12 asset::{AssetIndex, name::AssetNameExchange},
13 exchange::{ExchangeId, ExchangeIndex},
14 instrument::{InstrumentIndex, name::InstrumentNameExchange},
15};
16use serde::{Deserialize, Serialize};
17use state::{ActiveOrderState, Cancelled, InactiveOrderState, Open, OpenInFlight, OrderState};
18
19pub mod id;
21
22pub mod state;
26
27pub mod request;
31
32pub mod bracket;
34
35pub type UnindexedOrder = Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>;
37
38pub type UnindexedOrderKey = OrderKey<ExchangeId, InstrumentNameExchange>;
41
42pub type UnindexedOrderSnapshot = Order<
45 ExchangeId,
46 InstrumentNameExchange,
47 OrderState<AssetNameExchange, InstrumentNameExchange>,
48>;
49
50pub type OrderSnapshot<
52 ExchangeKey = ExchangeIndex,
53 AssetKey = AssetIndex,
54 InstrumentKey = InstrumentIndex,
55> = Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>;
56
57#[derive(
58 Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Constructor,
59)]
60
61pub struct OrderEvent<State, ExchangeKey = ExchangeIndex, InstrumentKey = InstrumentIndex> {
62 pub key: OrderKey<ExchangeKey, InstrumentKey>,
63 pub state: State,
64}
65
66#[derive(
67 Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Constructor,
68)]
69pub struct OrderKey<ExchangeKey = ExchangeIndex, InstrumentKey = InstrumentIndex> {
70 pub exchange: ExchangeKey,
71 pub instrument: InstrumentKey,
72 pub strategy: StrategyId,
73 pub cid: ClientOrderId,
74}
75
76#[derive(
77 Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Constructor,
78)]
79pub struct Order<ExchangeKey = ExchangeIndex, InstrumentKey = InstrumentIndex, State = OrderState> {
80 pub key: OrderKey<ExchangeKey, InstrumentKey>,
81 pub side: Side,
82 pub price: Option<Decimal>,
84 pub quantity: Decimal,
85 pub kind: OrderKind,
86 pub time_in_force: TimeInForce,
87 pub state: State,
88}
89
90impl<ExchangeKey, AssetKey, InstrumentKey>
91 Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>
92{
93 pub fn to_active(&self) -> Option<Order<ExchangeKey, InstrumentKey, ActiveOrderState>>
94 where
95 ExchangeKey: Clone,
96 InstrumentKey: Clone,
97 {
98 let OrderState::Active(state) = &self.state else {
99 return None;
100 };
101
102 Some(Order {
103 key: self.key.clone(),
104 side: self.side,
105 price: self.price,
106 quantity: self.quantity,
107 kind: self.kind,
108 time_in_force: self.time_in_force,
109 state: state.clone(),
110 })
111 }
112
113 pub fn to_inactive(
114 &self,
115 ) -> Option<Order<ExchangeKey, InstrumentKey, InactiveOrderState<AssetKey, InstrumentKey>>>
116 where
117 ExchangeKey: Clone,
118 AssetKey: Clone,
119 InstrumentKey: Clone,
120 {
121 let OrderState::Inactive(state) = &self.state else {
122 return None;
123 };
124
125 Some(Order {
126 key: self.key.clone(),
127 side: self.side,
128 price: self.price,
129 quantity: self.quantity,
130 kind: self.kind,
131 time_in_force: self.time_in_force,
132 state: state.clone(),
133 })
134 }
135}
136
137impl<ExchangeKey, InstrumentKey> Order<ExchangeKey, InstrumentKey, ActiveOrderState>
138where
139 ExchangeKey: Clone,
140 InstrumentKey: Clone,
141{
142 pub fn to_request_cancel(&self) -> Option<OrderRequestCancel<ExchangeKey, InstrumentKey>> {
143 let Order { key, state, .. } = self;
144
145 let request_cancel = match state {
146 ActiveOrderState::OpenInFlight(_) => RequestCancel { id: None },
147 ActiveOrderState::Open(open) => RequestCancel {
148 id: Some(open.id.clone()),
149 },
150 _ => return None,
151 };
152
153 Some(OrderRequestCancel {
154 key: key.clone(),
155 state: request_cancel,
156 })
157 }
158}
159
160#[derive(
167 Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Display,
168)]
169pub enum TrailingOffsetType {
170 Absolute,
172 Percentage,
174 BasisPoints,
176}
177
178#[derive(
179 Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Display,
180)]
181pub enum OrderKind {
182 Market,
183 Limit,
184 #[display("Stop({trigger_price})")]
186 Stop {
187 trigger_price: Decimal,
188 },
189 #[display("StopLimit({trigger_price})")]
191 StopLimit {
192 trigger_price: Decimal,
193 },
194 #[display("TrailingStop({offset}, {offset_type})")]
196 TrailingStop {
197 offset: Decimal,
198 offset_type: TrailingOffsetType,
199 },
200 #[display("TrailingStopLimit({offset}, {offset_type}, {limit_offset})")]
202 TrailingStopLimit {
203 offset: Decimal,
204 offset_type: TrailingOffsetType,
205 limit_offset: Decimal,
207 },
208}
209
210#[derive(
211 Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Display,
212)]
213pub enum TimeInForce {
214 GoodUntilCancelled {
215 post_only: bool,
216 },
217 GoodUntilEndOfDay,
218 FillOrKill,
219 ImmediateOrCancel,
220 #[display("GoodTillDate({expiry})")]
222 GoodTillDate {
223 expiry: DateTime<Utc>,
224 },
225 AtOpen,
227 AtClose,
229}
230
231impl<ExchangeKey, InstrumentKey> From<&OrderRequestOpen<ExchangeKey, InstrumentKey>>
232 for Order<ExchangeKey, InstrumentKey, ActiveOrderState>
233where
234 ExchangeKey: Clone,
235 InstrumentKey: Clone,
236{
237 fn from(value: &OrderRequestOpen<ExchangeKey, InstrumentKey>) -> Self {
238 let OrderRequestOpen {
239 key,
240 state:
241 RequestOpen {
242 side,
243 price,
244 quantity,
245 kind,
246 time_in_force,
247 position_id: _,
248 reduce_only: _, },
250 } = value;
251
252 Self {
253 key: key.clone(),
254 side: *side,
255 price: *price,
256 quantity: *quantity,
257 kind: *kind,
258 time_in_force: *time_in_force,
259 state: ActiveOrderState::OpenInFlight(OpenInFlight),
260 }
261 }
262}
263
264impl<ExchangeKey, InstrumentKey> From<Order<ExchangeKey, InstrumentKey, Open>>
265 for Order<ExchangeKey, InstrumentKey, ActiveOrderState>
266{
267 fn from(value: Order<ExchangeKey, InstrumentKey, Open>) -> Self {
268 let Order {
269 key,
270 side,
271 price,
272 quantity,
273 kind,
274 time_in_force,
275 state,
276 } = value;
277
278 Self {
279 key,
280 side,
281 price,
282 quantity,
283 kind,
284 time_in_force,
285 state: ActiveOrderState::Open(state),
286 }
287 }
288}
289
290impl<ExchangeKey, AssetKey, InstrumentKey> From<Order<ExchangeKey, InstrumentKey, Open>>
291 for Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>
292{
293 fn from(value: Order<ExchangeKey, InstrumentKey, Open>) -> Self {
294 let Order {
295 key,
296 side,
297 price,
298 quantity,
299 kind,
300 time_in_force,
301 state,
302 } = value;
303
304 Self {
305 key,
306 side,
307 price,
308 quantity,
309 kind,
310 time_in_force,
311 state: OrderState::Active(ActiveOrderState::Open(state)),
312 }
313 }
314}
315
316impl<ExchangeKey, AssetKey, InstrumentKey> From<Order<ExchangeKey, InstrumentKey, Cancelled>>
317 for Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>
318{
319 fn from(value: Order<ExchangeKey, InstrumentKey, Cancelled>) -> Self {
320 let Order {
321 key,
322 side,
323 price,
324 quantity,
325 kind,
326 time_in_force,
327 state,
328 } = value;
329
330 Self {
331 key,
332 side,
333 price,
334 quantity,
335 kind,
336 time_in_force,
337 state: OrderState::Inactive(InactiveOrderState::Cancelled(state)),
338 }
339 }
340}