apple_quant_algorithmic/order/
remote.rs1use num_traits::Signed;
2
3use crate::{
4 backend::OrderIdGenerator,
5 instrument::InstrumentSpec,
6 liquidity::LiquidityEstimation,
7 price::{AbsolutePrice, BidAskPriceSpread, Price},
8 volume::{
9 AggressiveVolume, AggressorSide, DirectionalIntentVolume, DirectionlessVolume, RestingSide,
10 RestingVolume,
11 },
12};
13
14use super::{
15 DesiredVolumeOrder, DesiredVolumeOrderError, MatchableOrder, OrderExecutionExpectation,
16 OrderGoal, RemoteOrderTracker,
17};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum RemoteOrder<IS: InstrumentSpec> {
21 Market(MarketOrder<IS>),
22 Limit(LimitOrder<IS>),
23}
24
25impl<IS: InstrumentSpec> RemoteOrder<IS> {
26 pub(crate) fn parent_processed(
27 &mut self,
28 bid_ask_price_spread: &BidAskPriceSpread<IS>,
29 ) {
30 let Self::Limit(limit_order) = self else {
31 return;
32 };
33
34 limit_order.parent_processed(bid_ask_price_spread);
35 }
36
37 pub fn as_order_execution_expectation(&self) -> OrderExecutionExpectation {
38 match self {
39 Self::Market(_) => OrderExecutionExpectation::Immediate,
40 Self::Limit(limit_order) => limit_order.order_execution_expectation,
41 }
42 }
43
44 pub fn register(
45 &self,
46 order_id_generator: &mut OrderIdGenerator,
47 ) -> Result<RemoteOrderTracker<IS>, DesiredVolumeOrderError>
48 where
49 IS: Send,
50 {
51 let local_order_id = order_id_generator.next_local_order_id();
52
53 let directional_intent_volume = self.desired_directional_intent_volume()?;
54 let order_execution_expectation = self.as_order_execution_expectation();
55
56 let order_goal = OrderGoal::new_submit_remote_with_execution_expectation(
57 local_order_id,
58 directional_intent_volume,
59 order_execution_expectation,
60 );
61
62 Ok(RemoteOrderTracker::new(
63 order_goal,
64 ))
65 }
66}
67
68impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for RemoteOrder<IS> {
69 fn desired_directional_intent_volume(
70 &self
71 ) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
72 match self {
73 Self::Market(market_order) => market_order.desired_directional_intent_volume(),
74 Self::Limit(limit_order) => limit_order.desired_directional_intent_volume(),
75 }
76 }
77
78 fn desired_directionless_volume(
79 &self
80 ) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
81 match self {
82 Self::Market(market_order) => market_order.desired_directionless_volume(),
83 Self::Limit(limit_order) => limit_order.desired_directionless_volume(),
84 }
85 }
86}
87
88impl<IS: InstrumentSpec> MatchableOrder<IS> for RemoteOrder<IS> {
89 fn is_liquidable(
90 &self,
91 liquidity_estimation: &LiquidityEstimation<IS>,
92 ) -> Option<AbsolutePrice<IS>> {
93 match self {
94 Self::Market(market_order) => market_order.is_liquidable(liquidity_estimation),
95 Self::Limit(limit_order) => limit_order.is_liquidable(liquidity_estimation),
96 }
97 }
98}
99
100impl<IS: InstrumentSpec> From<MarketOrder<IS>> for RemoteOrder<IS> {
101 fn from(value: MarketOrder<IS>) -> Self {
102 Self::Market(value)
103 }
104}
105
106impl<IS: InstrumentSpec> From<LimitOrder<IS>> for RemoteOrder<IS> {
107 fn from(value: LimitOrder<IS>) -> Self {
108 Self::Limit(value)
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
113pub struct MarketOrder<IS: InstrumentSpec> {
114 pub aggressive_volume: AggressiveVolume<IS>,
115}
116
117impl<IS: InstrumentSpec> MarketOrder<IS> {
118 pub fn new(aggressive_volume: AggressiveVolume<IS>) -> Self {
119 Self { aggressive_volume }
120 }
121
122 pub fn new_from_parts(
123 directionless_volume: DirectionlessVolume<IS>,
124 aggressor_side: AggressorSide,
125 ) -> Self {
126 Self {
127 aggressive_volume: AggressiveVolume {
128 directionless_volume,
129 aggressor_side,
130 },
131 }
132 }
133
134 pub fn into_remote(self) -> RemoteOrder<IS> {
135 self.into()
136 }
137}
138
139impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for MarketOrder<IS> {
140 fn desired_directional_intent_volume(
141 &self
142 ) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
143 Ok(self
144 .aggressive_volume
145 .as_directional_intent_volume())
146 }
147
148 fn desired_directionless_volume(
149 &self
150 ) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
151 Ok(self
152 .aggressive_volume
153 .as_directionless_volume())
154 }
155}
156
157impl<IS: InstrumentSpec> MatchableOrder<IS> for MarketOrder<IS> {
158 fn is_liquidable(
159 &self,
160 liquidity_estimation: &LiquidityEstimation<IS>,
161 ) -> Option<AbsolutePrice<IS>> {
162 let Some((bid_level, ask_level)) = liquidity_estimation.furthest_bid_ask() else {
163 return None;
164 };
165
166 match self
167 .aggressive_volume
168 .aggressor_side()
169 {
170 AggressorSide::Bid => Some(bid_level.price),
171 AggressorSide::Ask => Some(ask_level.price),
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
177pub struct LimitOrder<IS: InstrumentSpec> {
178 pub price: Price<IS>,
179 pub resting_volume: RestingVolume<IS>,
180 pub order_execution_expectation: OrderExecutionExpectation,
181}
182
183impl<IS: InstrumentSpec> LimitOrder<IS> {
184 pub fn new(
185 price: Price<IS>,
186 resting_volume: RestingVolume<IS>,
187 order_execution_expectation: OrderExecutionExpectation,
188 ) -> Self {
189 Self {
190 price,
191 resting_volume,
192 order_execution_expectation,
193 }
194 }
195
196 pub(crate) fn parent_processed(
197 &mut self,
198 bid_ask_price_spread: &BidAskPriceSpread<IS>,
199 ) {
200 let Price::Relative(relative_price) = &mut self.price else {
201 return;
202 };
203
204 let absolute_price: AbsolutePrice<IS> = if relative_price.is_positive() {
205 AbsolutePrice::new(*bid_ask_price_spread.ask_price + **relative_price)
206 } else {
207 AbsolutePrice::new(*bid_ask_price_spread.bid_price + **relative_price)
208 };
209
210 self.price = Price::Absolute(absolute_price);
211 }
212
213 pub fn into_remote(self) -> RemoteOrder<IS> {
214 self.into()
215 }
216}
217
218impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for LimitOrder<IS> {
219 fn desired_directional_intent_volume(
220 &self
221 ) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
222 Ok(self
223 .resting_volume
224 .as_directional_intent_volume())
225 }
226
227 fn desired_directionless_volume(
228 &self
229 ) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
230 Ok(self
231 .resting_volume
232 .as_directionless_volume())
233 }
234}
235
236impl<IS: InstrumentSpec> MatchableOrder<IS> for LimitOrder<IS> {
237 fn is_liquidable(
238 &self,
239 liquidity_estimation: &LiquidityEstimation<IS>,
240 ) -> Option<AbsolutePrice<IS>> {
241 let Some((bid_level, ask_level)) = liquidity_estimation.furthest_bid_ask() else {
242 return None;
243 };
244
245 match self
246 .resting_volume
247 .resting_side
248 {
249 RestingSide::Bid => {
250 let Price::Absolute(absolute_price) = self.price else {
251 return None;
252 };
253
254 if bid_level.price <= absolute_price {
255 Some(bid_level.price)
256 } else {
257 None
258 }
259 }
260 RestingSide::Ask => {
261 let Price::Absolute(absolute_price) = self.price else {
262 return None;
263 };
264
265 if ask_level.price >= absolute_price {
266 Some(ask_level.price)
267 } else {
268 None
269 }
270 }
271 }
272 }
273}