1use bitcode::{Decode, Encode};
9
10use crate::{Direction, Operation, Transaction};
11
12#[derive(Debug, PartialEq, Decode, Encode, Clone)]
13pub enum MarketOrder {
14 New(NewMarketOrder),
15 Posted(PostedMarketOrder),
16 Filled(FilledMarketOrder),
17 Rejected(RejectedMarketOrder),
18}
19impl MarketOrder {
20 #[allow(clippy::new_ret_no_self)]
21 pub fn new(direction: Direction, lots: u32) -> NewMarketOrder {
22 NewMarketOrder { direction, lots }
23 }
24}
25impl std::fmt::Display for MarketOrder {
26 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
27 match self {
28 Self::New(order) => write!(f, "{order}"),
29 Self::Posted(order) => write!(f, "{order}"),
30 Self::Filled(order) => write!(f, "{order}"),
31 Self::Rejected(order) => write!(f, "{order}"),
32 }
33 }
34}
35
36#[derive(Debug, PartialEq, Decode, Encode, Clone)]
37pub struct NewMarketOrder {
38 pub direction: Direction,
39 pub lots: u32,
40}
41impl NewMarketOrder {
42 pub fn post(self, broker_id: &str) -> PostedMarketOrder {
43 PostedMarketOrder {
44 direction: self.direction,
45 lots: self.lots,
46 broker_id: broker_id.to_string(),
47 transactions: Vec::new(),
48 }
49 }
50 pub fn reject(self, meta: &str) -> RejectedMarketOrder {
51 RejectedMarketOrder {
52 direction: self.direction,
53 lots: self.lots,
54 meta: meta.to_string(),
55 }
56 }
57}
58impl std::fmt::Display for NewMarketOrder {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 write!(f, "MarketOrder::New={} {}", self.direction, self.lots)
61 }
62}
63
64#[derive(Debug, PartialEq, Decode, Encode, Clone)]
65pub struct PostedMarketOrder {
66 pub direction: Direction,
67 pub lots: u32,
68 pub broker_id: String,
69 pub transactions: Vec<Transaction>,
70}
71impl PostedMarketOrder {
72 pub fn add_transaction(&mut self, t: Transaction) {
73 self.transactions.push(t);
74 }
75 pub fn fill(self, ts_nanos: i64, commission: f64) -> FilledMarketOrder {
76 let operation =
77 Operation::from(ts_nanos, &self.transactions, commission);
78 FilledMarketOrder {
79 direction: self.direction,
80 lots: self.lots,
81 broker_id: self.broker_id,
82 transactions: self.transactions,
83 operation,
84 }
85 }
86}
87impl std::fmt::Display for PostedMarketOrder {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 write!(
90 f,
91 "MarketOrder::Posted={} {} id={} t={:?}",
92 self.direction, self.lots, self.broker_id, self.transactions
93 )
94 }
95}
96
97#[derive(Debug, PartialEq, Decode, Encode, Clone)]
98pub struct FilledMarketOrder {
99 pub direction: Direction,
100 pub lots: u32,
101 pub broker_id: String,
102 pub transactions: Vec<Transaction>,
103 pub operation: Operation,
104}
105impl std::fmt::Display for FilledMarketOrder {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(
108 f,
109 "MarketOrder::Filled={} {} id={} t={:?} {}",
110 self.direction,
111 self.lots,
112 self.broker_id,
113 self.transactions,
114 self.operation
115 )
116 }
117}
118
119#[derive(Debug, PartialEq, Decode, Encode, Clone)]
120pub struct RejectedMarketOrder {
121 pub direction: Direction,
122 pub lots: u32,
123 pub meta: String,
124}
125impl std::fmt::Display for RejectedMarketOrder {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 write!(
128 f,
129 "MarketOrder::Rejected={} {} meta={}",
130 self.direction, self.lots, self.meta
131 )
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use chrono::Utc;
139
140 #[test]
141 fn new_post_fill() {
142 let new = MarketOrder::new(Direction::Buy, 10);
143
144 let mut posted = new.post("order_id=100500");
145 assert_eq!(posted.broker_id, "order_id=100500");
146
147 let t1 = Transaction::new(5, 320.0);
148 posted.add_transaction(t1);
149 assert_eq!(posted.broker_id, "order_id=100500");
150 assert_eq!(posted.transactions.len(), 1);
151
152 let t2 = Transaction::new(5, 320.0);
153 posted.add_transaction(t2);
154 assert_eq!(posted.broker_id, "order_id=100500");
155 assert_eq!(posted.transactions.len(), 2);
156
157 let dt = Utc::now();
158 let ts = dt.timestamp_nanos_opt().unwrap();
159 let order = posted.fill(ts, 3.2);
160 assert_eq!(order.operation.dt(), dt);
161 assert_eq!(order.operation.quantity, 10);
162 assert_eq!(order.operation.value, 3200.0);
163 assert_eq!(order.operation.commission, 3.2);
164 }
165 #[test]
166 fn reject() {
167 let new = MarketOrder::new(Direction::Sell, 10);
168 assert_eq!(new.direction, Direction::Sell);
169 assert_eq!(new.lots, 10);
170 dbg!(&new);
171
172 let reject = new.reject("market is closed");
173 assert_eq!(reject.meta, "market is closed");
174 dbg!(&reject);
175 }
176}