1use crate::matcher::Matcher;
2use crate::portfolio::Portfolio;
3use crate::types::{AgentId, FillEvent, MarketState, OrderRequest};
4use std::collections::HashMap;
5
6pub struct Exchange<M: Matcher> {
9 matcher: M,
10 portfolios: HashMap<AgentId, Portfolio>,
11 order_agent_map: HashMap<u64, AgentId>,
12 last_fills: Vec<(AgentId, FillEvent)>,
13 fill_history: Vec<(AgentId, FillEvent)>,
14}
15
16impl<M: Matcher> Exchange<M> {
17 pub fn new(matcher: M) -> Self {
18 Self {
19 matcher,
20 portfolios: HashMap::new(),
21 order_agent_map: HashMap::new(),
22 last_fills: Vec::new(),
23 fill_history: Vec::new(),
24 }
25 }
26
27 pub fn register_agent(&mut self, id: AgentId, initial_cash: f64, transaction_cost_rate: f64) {
28 self.portfolios
29 .insert(id, Portfolio::new(initial_cash, transaction_cost_rate));
30 }
31
32 pub fn get_portfolio(&self, id: AgentId) -> Option<&Portfolio> {
33 self.portfolios.get(&id)
34 }
35
36 pub fn submit_orders(&mut self, agent_id: AgentId, requests: Vec<OrderRequest>) {
39 for request in requests {
40 match request {
41 OrderRequest::New(order) => {
42 self.order_agent_map.insert(order.id, agent_id);
43 self.matcher.add_order(order);
44 }
45 OrderRequest::Cancel(id) => {
46 self.order_agent_map.remove(&id);
47 self.matcher.cancel_order(id);
48 }
49 OrderRequest::CancelAll => {
50 let agent_order_ids: Vec<u64> = self
51 .order_agent_map
52 .iter()
53 .filter(|&(_, &aid)| aid == agent_id)
54 .map(|(&oid, _)| oid)
55 .collect();
56 for oid in &agent_order_ids {
57 self.matcher.cancel_order(*oid);
58 self.order_agent_map.remove(oid);
59 }
60 }
61 }
62 }
63 }
64
65 pub fn resolve_matches(&mut self, state: &MarketState) -> Vec<FillEvent> {
68 let fills = self.matcher.process_quote(state);
69
70 self.last_fills.clear();
71
72 for fill in &fills {
73 if let Some(&agent_id) = self.order_agent_map.get(&fill.order_id) {
74 if let Some(portfolio) = self.portfolios.get_mut(&agent_id) {
75 portfolio.update(fill);
76 }
77 self.last_fills.push((agent_id, fill.clone()));
78 self.fill_history.push((agent_id, fill.clone()));
79 self.order_agent_map.remove(&fill.order_id);
80 }
81 }
82
83 fills
84 }
85
86 pub fn last_fills(&self) -> &[(AgentId, FillEvent)] {
88 &self.last_fills
89 }
90
91 pub fn fill_history_for(&self, agent_id: AgentId) -> Vec<&FillEvent> {
93 self.fill_history
94 .iter()
95 .filter(|(aid, _)| *aid == agent_id)
96 .map(|(_, fill)| fill)
97 .collect()
98 }
99
100 pub fn fill_history(&self) -> &[(AgentId, FillEvent)] {
102 &self.fill_history
103 }
104
105 pub fn get_matcher(&self) -> &M {
106 &self.matcher
107 }
108
109 pub fn get_matcher_parameters(&self) -> HashMap<String, f64> {
112 self.matcher.augment_parameters()
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::matcher::SimpleMatcher;
120 use crate::types::{DEFAULT_AGENT, Order, Side};
121
122 fn sample_state(bid: f64, ask: f64) -> MarketState {
123 MarketState {
124 timestamp: 0.0,
125 best_bid: bid,
126 best_ask: ask,
127 last_price: None,
128 true_volatility: None,
129 true_drift: None,
130 parameters: None,
131 }
132 }
133
134 #[test]
135 fn test_register_and_get_portfolio() {
136 let mut exchange = Exchange::new(SimpleMatcher::new());
137 exchange.register_agent(DEFAULT_AGENT, 10000.0, 0.0);
138
139 let portfolio = exchange.get_portfolio(DEFAULT_AGENT).unwrap();
140 assert_eq!(portfolio.cash, 10000.0);
141 assert_eq!(portfolio.position, 0.0);
142 }
143
144 #[test]
145 fn test_submit_and_match_orders() {
146 let mut exchange = Exchange::new(SimpleMatcher::new());
147 exchange.register_agent(DEFAULT_AGENT, 10000.0, 0.0);
148
149 let requests = vec![OrderRequest::New(Order::new(1, Side::Buy, 100.10, 1.0))];
150 exchange.submit_orders(DEFAULT_AGENT, requests);
151
152 let state = sample_state(99.95, 100.05);
153 let fills = exchange.resolve_matches(&state);
154
155 assert_eq!(fills.len(), 1);
156 assert_eq!(fills[0].price, 100.05);
157
158 let portfolio = exchange.get_portfolio(DEFAULT_AGENT).unwrap();
159 assert_eq!(portfolio.position, 1.0);
160 assert!((portfolio.cash - (10000.0 - 100.05)).abs() < 1e-10);
161 }
162
163 #[test]
164 fn test_multi_agent_isolation() {
165 let mut exchange = Exchange::new(SimpleMatcher::new());
166 exchange.register_agent(0, 10000.0, 0.0);
167 exchange.register_agent(1, 5000.0, 0.0);
168
169 exchange.submit_orders(
170 0,
171 vec![OrderRequest::New(Order::new(1, Side::Buy, 100.10, 1.0))],
172 );
173 exchange.submit_orders(
174 1,
175 vec![OrderRequest::New(Order::new(2, Side::Sell, 99.90, 2.0))],
176 );
177
178 let state = sample_state(99.95, 100.05);
179 let fills = exchange.resolve_matches(&state);
180
181 assert_eq!(fills.len(), 2);
182
183 let p0 = exchange.get_portfolio(0).unwrap();
184 assert_eq!(p0.position, 1.0);
185
186 let p1 = exchange.get_portfolio(1).unwrap();
187 assert_eq!(p1.position, -2.0);
188 }
189
190 #[test]
191 fn test_cancel_all_per_agent() {
192 let mut exchange = Exchange::new(SimpleMatcher::new());
193 exchange.register_agent(0, 10000.0, 0.0);
194 exchange.register_agent(1, 10000.0, 0.0);
195
196 exchange.submit_orders(
197 0,
198 vec![OrderRequest::New(Order::new(1, Side::Buy, 99.50, 1.0))],
199 );
200 exchange.submit_orders(
201 1,
202 vec![OrderRequest::New(Order::new(2, Side::Buy, 99.50, 1.0))],
203 );
204
205 exchange.submit_orders(0, vec![OrderRequest::CancelAll]);
207
208 let state = sample_state(99.40, 99.50);
210 let fills = exchange.resolve_matches(&state);
211
212 assert_eq!(fills.len(), 1);
213 assert_eq!(fills[0].order_id, 2);
214 }
215
216 #[test]
217 fn test_fill_history_tracking() {
218 let mut exchange = Exchange::new(SimpleMatcher::new());
219 exchange.register_agent(0, 10000.0, 0.0);
220 exchange.register_agent(1, 10000.0, 0.0);
221
222 exchange.submit_orders(
223 0,
224 vec![OrderRequest::New(Order::new(1, Side::Buy, 100.10, 1.0))],
225 );
226 exchange.submit_orders(
227 1,
228 vec![OrderRequest::New(Order::new(2, Side::Sell, 99.80, 1.0))],
229 );
230
231 let state = sample_state(99.95, 100.05);
232 exchange.resolve_matches(&state);
233
234 assert_eq!(exchange.fill_history().len(), 2);
235 assert_eq!(exchange.fill_history_for(0).len(), 1);
236 assert_eq!(exchange.fill_history_for(1).len(), 1);
237 assert_eq!(exchange.last_fills().len(), 2);
238 }
239
240 #[test]
241 fn test_last_fills_cleared_on_new_resolve() {
242 let mut exchange = Exchange::new(SimpleMatcher::new());
243 exchange.register_agent(0, 10000.0, 0.0);
244
245 exchange.submit_orders(
246 0,
247 vec![OrderRequest::New(Order::new(1, Side::Buy, 100.10, 1.0))],
248 );
249 let state = sample_state(99.95, 100.05);
250 exchange.resolve_matches(&state);
251 assert_eq!(exchange.last_fills().len(), 1);
252
253 exchange.resolve_matches(&state);
255 assert_eq!(exchange.last_fills().len(), 0);
256 assert_eq!(exchange.fill_history().len(), 1);
258 }
259
260 #[test]
261 fn test_cancelall_removes_multiple_orders_from_same_agent() {
262 let mut exchange = Exchange::new(SimpleMatcher::new());
265 exchange.register_agent(0, 10000.0, 0.0);
266
267 exchange.submit_orders(
268 0,
269 vec![
270 OrderRequest::New(Order::new(1, Side::Buy, 101.0, 1.0)),
271 OrderRequest::New(Order::new(2, Side::Buy, 102.0, 1.0)),
272 OrderRequest::New(Order::new(3, Side::Sell, 98.0, 1.0)),
273 ],
274 );
275 exchange.submit_orders(0, vec![OrderRequest::CancelAll]);
276
277 let fills = exchange.resolve_matches(&sample_state(99.0, 100.0));
278 assert_eq!(fills.len(), 0);
279 }
280
281 #[test]
282 fn test_portfolio_position_accumulates_across_ticks() {
283 let mut exchange = Exchange::new(SimpleMatcher::new());
286 exchange.register_agent(0, 10000.0, 0.0);
287
288 exchange.submit_orders(
289 0,
290 vec![OrderRequest::New(Order::new(1, Side::Buy, 101.0, 1.0))],
291 );
292 exchange.resolve_matches(&sample_state(99.0, 100.0));
293
294 exchange.submit_orders(
295 0,
296 vec![OrderRequest::New(Order::new(2, Side::Buy, 101.0, 2.0))],
297 );
298 exchange.resolve_matches(&sample_state(99.0, 100.0));
299
300 let p = exchange.get_portfolio(0).unwrap();
301 assert!((p.position - 3.0).abs() < 1e-10);
302 assert!((p.cash - (10000.0 - 300.0)).abs() < 1e-10);
303 }
304
305 #[test]
306 fn test_transaction_cost_applied_on_sell() {
307 let cost_rate = 0.001;
310 let mut exchange = Exchange::new(SimpleMatcher::new());
311 exchange.register_agent(0, 10000.0, cost_rate);
312
313 exchange.submit_orders(
314 0,
315 vec![OrderRequest::New(Order::new(1, Side::Sell, 98.0, 1.0))],
316 );
317 exchange.resolve_matches(&sample_state(99.0, 100.0));
318
319 let p = exchange.get_portfolio(0).unwrap();
320 let expected_proceeds = 99.0 * (1.0 - cost_rate);
321 assert!((p.cash - (10000.0 + expected_proceeds)).abs() < 1e-10);
322 assert!((p.position - (-1.0)).abs() < 1e-10);
323 }
324}