apple_quant_algorithmic/order/
client.rs1use crate::{
2 price::{AbsolutePrice, BidAskPriceSpread, ProtoabsolutePrice},
3 backend::OrderIdGenerator, instrument::InstrumentSpec,
4 liquidity::LiquidityEstimation, volume::DirectionalIntent,
5};
6
7use super::{ClientOrderTracker, MatchableOrder};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum ClientOrder<IS: InstrumentSpec> {
11 Stop(ClientStopOrder<IS>),
12}
13
14impl<IS: InstrumentSpec> ClientOrder<IS> {
15 pub(crate) fn parent_processed(
16 &mut self,
17 bid_ask_price_spread: &BidAskPriceSpread<IS>,
18 ) {
19 #[allow(irrefutable_let_patterns)]
20 let Self::Stop(
21 client_stop_order,
22 ) = self else {
23 return;
24 };
25
26 client_stop_order.parent_processed(bid_ask_price_spread);
27 }
28
29 pub fn register(
30 &self,
31 order_id_generator: &mut OrderIdGenerator,
32 ) -> ClientOrderTracker
33 where
34 IS: Send,
35 {
36 let local_order_id = order_id_generator.next_local_order_id();
37 ClientOrderTracker::new(local_order_id)
38 }
39}
40
41impl<IS: InstrumentSpec> MatchableOrder<IS> for ClientOrder<IS> {
42 fn is_liquidable(
43 &self,
44 liquidity_estimation: &LiquidityEstimation<IS>,
45 ) -> Option<AbsolutePrice<IS>> {
46 match self {
47 Self::Stop(
48 client_stop_order,
49 ) => client_stop_order.is_liquidable(liquidity_estimation),
50 }
51 }
52}
53
54impl<IS: InstrumentSpec> From<ClientStopOrder<IS>> for ClientOrder<IS> {
55 fn from(
56 value: ClientStopOrder<IS>,
57 ) -> Self {
58 Self::Stop(value)
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub struct ClientStopOrder<IS: InstrumentSpec> {
64 pub price: ProtoabsolutePrice<IS>,
65 pub cross_over_directional_intent: DirectionalIntent,
66}
67
68impl<IS: InstrumentSpec> ClientStopOrder<IS> {
69 pub fn new(
70 price: ProtoabsolutePrice<IS>,
71 cross_over_directional_intent: DirectionalIntent,
72 ) -> Self {
73 Self {
74 price,
75 cross_over_directional_intent,
76 }
77 }
78
79 pub(crate) fn parent_processed(
80 &mut self,
81 bid_ask_price_spread: &BidAskPriceSpread<IS>,
82 ) {
83 let ProtoabsolutePrice::Relative(
84 relative_price,
85 ) = &self.price else {
86 return;
87 };
88
89 let absolute_price = if relative_price.is_positive() {
90 bid_ask_price_spread.ask_price + relative_price
91 } else {
92 bid_ask_price_spread.bid_price + relative_price
93 };
94
95 self.price = absolute_price.into_protoabsolute_price();
96 }
97
98 pub fn into_client_order(
99 self,
100 ) -> ClientOrder<IS> {
101 self.into()
102 }
103}
104
105impl<IS: InstrumentSpec> MatchableOrder<IS> for ClientStopOrder<IS> {
106 fn is_liquidable(
107 &self,
108 liquidity_estimation: &LiquidityEstimation<IS>,
109 ) -> Option<AbsolutePrice<IS>> {
110 let Some((
111 bid_price_volume_level,
112 ask_price_volume_level,
113 )) = liquidity_estimation.furthest_bid_ask() else {
114 return None;
115 };
116
117 let ProtoabsolutePrice::Absolute(
118 absolute_price,
119 ) = &self.price else {
120 return None;
121 };
122
123 match self.cross_over_directional_intent {
124 DirectionalIntent::Positive => {
125 if &ask_price_volume_level.price < absolute_price {
126 return None;
127 }
128
129 Some(ask_price_volume_level.price)
130 },
131 DirectionalIntent::Negative => {
132 if &bid_price_volume_level.price > absolute_price {
133 return None;
134 }
135
136 Some(bid_price_volume_level.price)
137 },
138 }
139 }
140}