exc_types/trading/
mod.rs

1/// Place: the order builder.
2pub mod place;
3
4/// Order.
5pub mod order;
6
7use std::{collections::BTreeMap, fmt, sync::Arc};
8
9use exc_service::{ExchangeError, Request};
10use futures::{future::BoxFuture, stream::BoxStream};
11use indicator::{Tick, TickValue, Tickable};
12pub use order::{Order, OrderId, OrderKind, OrderState, OrderStatus, OrderTrade, TimeInForce};
13pub use place::Place;
14use positions::Asset;
15use time::OffsetDateTime;
16
17use crate::Str;
18
19/// Options for order placement.
20#[derive(Debug, Clone)]
21pub struct PlaceOrderOptions {
22    /// Instrument.
23    instrument: Str,
24    /// Client id.
25    client_id: Option<Str>,
26    /// Margin currency perferred to use.
27    margin: Option<Asset>,
28    /// Exchange-defined options.
29    custom: BTreeMap<Str, Str>,
30}
31
32impl PlaceOrderOptions {
33    /// Create a new options with the given instrument.
34    pub fn new(inst: impl AsRef<str>) -> Self {
35        Self {
36            instrument: Str::new(inst),
37            client_id: None,
38            margin: None,
39            custom: BTreeMap::default(),
40        }
41    }
42
43    /// Set the client id to place.
44    pub fn with_client_id(&mut self, id: Option<impl AsRef<str>>) -> &mut Self {
45        self.client_id = id.map(Str::new);
46        self
47    }
48
49    /// Set the margin currency preffered to use.
50    /// # Warning
51    /// It is up to the exchange to decide if this option applies,
52    /// so please check the documents of the exchange you use.
53    pub fn with_margin(&mut self, currency: &Asset) -> &mut Self {
54        self.margin = Some(currency.clone());
55        self
56    }
57
58    /// Insert an exchange-defined custom option.
59    pub fn insert<K, V>(&mut self, key: K, value: V) -> &mut Self
60    where
61        K: AsRef<str>,
62        V: AsRef<str>,
63    {
64        self.custom
65            .insert(Str::new(key.as_ref()), Str::new(value.as_ref()));
66        self
67    }
68
69    /// Get the instrument name to trade.
70    pub fn instrument(&self) -> &str {
71        &self.instrument
72    }
73
74    /// Get the client id to use.
75    pub fn client_id(&self) -> Option<&str> {
76        self.client_id.as_deref()
77    }
78
79    /// Get the margin currency perferred to use.
80    pub fn margin(&self) -> Option<&str> {
81        self.margin.as_deref()
82    }
83
84    /// Get the exchange-defined custom options.
85    pub fn custom(&self) -> &BTreeMap<Str, Str> {
86        &self.custom
87    }
88}
89
90/// Place order.
91#[derive(Debug, Clone)]
92pub struct PlaceOrder {
93    /// Place.
94    pub place: Place,
95    /// Options.
96    pub opts: Arc<PlaceOrderOptions>,
97}
98
99impl PlaceOrder {
100    /// Create a new request to place order.
101    pub fn new(place: Place, opts: &PlaceOrderOptions) -> Self {
102        Self {
103            place,
104            opts: Arc::new(opts.clone()),
105        }
106    }
107}
108
109/// Place order response.
110#[derive(Clone)]
111pub struct Placed {
112    /// Order id.
113    pub id: OrderId,
114    /// The placed order.
115    pub order: Option<Order>,
116    /// Timestamp.
117    pub ts: OffsetDateTime,
118}
119
120impl fmt::Debug for Placed {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        f.debug_struct("Placed")
123            .field("ts", &self.ts.to_string())
124            .field("id", &self.id.as_str())
125            .field("order", &self.order)
126            .finish()
127    }
128}
129
130impl Request for PlaceOrder {
131    type Response = BoxFuture<'static, Result<Placed, ExchangeError>>;
132}
133
134/// Cancel order.
135#[derive(Debug, Clone)]
136pub struct CancelOrder {
137    /// Instrument.
138    pub instrument: Str,
139    /// Id.
140    pub id: OrderId,
141}
142
143impl CancelOrder {
144    /// Create a new [`CancelOrder`] request.
145    pub fn new(inst: impl AsRef<str>, id: OrderId) -> Self {
146        Self {
147            instrument: Str::new(inst),
148            id,
149        }
150    }
151}
152
153/// Cancel order response.
154#[derive(Clone)]
155pub struct Canceled {
156    /// The placed order.
157    pub order: Option<Order>,
158    /// Timestamp.
159    pub ts: OffsetDateTime,
160}
161
162impl fmt::Debug for Canceled {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        f.debug_struct("Cancelled")
165            .field("ts", &self.ts.to_string())
166            .field("order", &self.order)
167            .finish()
168    }
169}
170
171impl Request for CancelOrder {
172    type Response = BoxFuture<'static, Result<Canceled, ExchangeError>>;
173}
174
175/// Get order.
176#[derive(Debug, Clone)]
177pub struct GetOrder {
178    /// Instrument.
179    pub instrument: Str,
180    /// Id.
181    pub id: OrderId,
182}
183
184impl GetOrder {
185    /// Create a new [`GetOrder`] request.
186    pub fn new(inst: impl AsRef<str>, id: OrderId) -> Self {
187        Self {
188            instrument: Str::new(inst),
189            id,
190        }
191    }
192}
193
194/// Order update.
195#[derive(Clone)]
196pub struct OrderUpdate {
197    /// Timestamp.
198    pub ts: OffsetDateTime,
199    /// Order.
200    pub order: Order,
201}
202
203impl fmt::Debug for OrderUpdate {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        f.debug_struct("OrderUpdate")
206            .field("ts", &self.ts.to_string())
207            .field("order", &self.order)
208            .finish()
209    }
210}
211
212impl Tickable for OrderUpdate {
213    type Value = Order;
214
215    fn tick(&self) -> Tick {
216        Tick::new(self.ts)
217    }
218
219    fn value(&self) -> &Self::Value {
220        &self.order
221    }
222
223    fn into_tick_value(self) -> TickValue<Self::Value> {
224        TickValue::new(self.ts, self.order)
225    }
226}
227
228impl Request for GetOrder {
229    type Response = BoxFuture<'static, Result<OrderUpdate, ExchangeError>>;
230}
231
232/// Orders Stream.
233pub type OrderStream = BoxStream<'static, Result<OrderUpdate, ExchangeError>>;
234
235/// Subscribe to order updates.
236#[derive(Debug, Clone)]
237pub struct SubscribeOrders {
238    /// Instrument.
239    pub instrument: Str,
240}
241
242impl SubscribeOrders {
243    /// Create a new [`SubscribeOrders`] request.
244    pub fn new(inst: impl AsRef<str>) -> Self {
245        Self {
246            instrument: Str::new(inst),
247        }
248    }
249}
250
251impl Request for SubscribeOrders {
252    type Response = OrderStream;
253}