Skip to content

Commit 9b21279

Browse files
committed
feat(rust): backtest order modification.
1 parent d14f42a commit 9b21279

File tree

4 files changed

+207
-284
lines changed

4 files changed

+207
-284
lines changed

hftbacktest/src/backtest/models/queue.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ pub trait L3QueueModel<MD> {
422422
fn modify_backtest_order(
423423
&mut self,
424424
order_id: OrderId,
425-
order: Order,
425+
order: &mut Order,
426426
depth: &MD,
427427
) -> Result<(), BacktestError>;
428428

@@ -771,7 +771,7 @@ where
771771
fn modify_backtest_order(
772772
&mut self,
773773
order_id: OrderId,
774-
mut order: Order,
774+
order: &mut Order,
775775
_depth: &MD,
776776
) -> Result<(), BacktestError> {
777777
order.q = Box::new(L3OrderSource::Backtest);
@@ -793,7 +793,7 @@ where
793793
{
794794
let mut prev_order = queue.remove(i).unwrap();
795795
let prev_order_price_tick = prev_order.price_tick;
796-
prev_order.update(&order);
796+
prev_order.update(order);
797797
// if queue.len() == 0 {
798798
// self.bid_queue.remove(&order_price_tick);
799799
// }
@@ -829,7 +829,7 @@ where
829829
{
830830
let mut prev_order = queue.remove(i).unwrap();
831831
let prev_order_price_tick = prev_order.price_tick;
832-
prev_order.update(&order);
832+
prev_order.update(order);
833833
// if queue.len() == 0 {
834834
// self.bid_queue.remove(&order_price_tick);
835835
// }

hftbacktest/src/backtest/proc/l3_nopartialfillexchange.rs

Lines changed: 64 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,26 @@ where
105105
mut order: Order,
106106
recv_timestamp: i64,
107107
) -> Result<(), BacktestError> {
108+
order.req = Status::None;
109+
108110
// Processes a new order.
109111
if order.req == Status::New {
110-
order.req = Status::None;
111-
self.ack_new(order, recv_timestamp)?;
112+
self.ack_new(&mut order, recv_timestamp)?;
112113
}
113114
// Processes a cancel order.
114115
else if order.req == Status::Canceled {
115-
order.req = Status::None;
116-
self.ack_cancel(order, recv_timestamp)?;
116+
self.ack_cancel(&mut order, recv_timestamp)?;
117+
}
118+
// Processes a modify order.
119+
else if order.req == Status::Replaced {
120+
self.ack_modify::<false>(&mut order, recv_timestamp)?;
117121
} else {
118122
return Err(BacktestError::InvalidOrderRequest);
119123
}
124+
// Makes the response.
125+
let local_recv_timestamp =
126+
recv_timestamp + self.order_latency.response(recv_timestamp, &order);
127+
self.orders_to.append(order, local_recv_timestamp);
120128
Ok(())
121129
}
122130

@@ -125,14 +133,14 @@ where
125133
order.leaves_qty = 0.0;
126134
order.status = Status::Expired;
127135
order.exch_timestamp = timestamp;
136+
128137
let local_recv_timestamp =
129138
order.exch_timestamp + self.order_latency.response(timestamp, &order);
130-
131139
self.orders_to.append(order, local_recv_timestamp);
132140
Ok(())
133141
}
134142

135-
fn fill(
143+
fn fill<const INSERT_BUS: bool>(
136144
&mut self,
137145
order: &mut Order,
138146
timestamp: i64,
@@ -157,11 +165,14 @@ where
157165
order.leaves_qty = 0.0;
158166
order.status = Status::Filled;
159167
order.exch_timestamp = timestamp;
160-
let local_recv_timestamp =
161-
order.exch_timestamp + self.order_latency.response(timestamp, order);
162168

163169
self.state.apply_fill(order);
164-
self.orders_to.append(order.clone(), local_recv_timestamp);
170+
171+
if INSERT_BUS {
172+
let local_recv_timestamp =
173+
order.exch_timestamp + self.order_latency.response(timestamp, order);
174+
self.orders_to.append(order.clone(), local_recv_timestamp);
175+
}
165176
Ok(())
166177
}
167178

@@ -176,7 +187,7 @@ where
176187
.on_best_bid_update(prev_best_tick, new_best_tick)?;
177188
for mut order in filled {
178189
let price_tick = order.price_tick;
179-
self.fill(&mut order, timestamp, true, price_tick)?;
190+
self.fill::<true>(&mut order, timestamp, true, price_tick)?;
180191
}
181192
Ok(())
182193
}
@@ -192,12 +203,12 @@ where
192203
.on_best_ask_update(prev_best_tick, new_best_tick)?;
193204
for mut order in filled {
194205
let price_tick = order.price_tick;
195-
self.fill(&mut order, timestamp, true, price_tick)?;
206+
self.fill::<true>(&mut order, timestamp, true, price_tick)?;
196207
}
197208
Ok(())
198209
}
199210

200-
fn ack_new(&mut self, mut order: Order, timestamp: i64) -> Result<(), BacktestError> {
211+
fn ack_new(&mut self, order: &mut Order, timestamp: i64) -> Result<(), BacktestError> {
201212
if self.queue_model.contains_backtest_order(order.order_id) {
202213
return Err(BacktestError::OrderIdExist);
203214
}
@@ -210,18 +221,19 @@ where
210221
match order.time_in_force {
211222
TimeInForce::GTX => {
212223
order.status = Status::Expired;
213-
214224
order.exch_timestamp = timestamp;
215-
let local_recv_timestamp =
216-
timestamp + self.order_latency.response(timestamp, &order);
217-
self.orders_to.append(order.clone(), local_recv_timestamp);
218225
Ok(())
219226
}
220227
TimeInForce::GTC | TimeInForce::FOK | TimeInForce::IOC => {
221228
// Since this always fills the full quantity, both FOK and IOC
222229
// orders are also fully filled at the best price.
223230
// Takes the market.
224-
self.fill(&mut order, timestamp, false, self.depth.best_ask_tick())
231+
self.fill::<false>(
232+
order,
233+
timestamp,
234+
false,
235+
self.depth.best_ask_tick(),
236+
)
225237
}
226238
TimeInForce::Unsupported => Err(BacktestError::InvalidOrderRequest),
227239
}
@@ -234,19 +246,11 @@ where
234246

235247
self.queue_model
236248
.add_backtest_order(order.clone(), &self.depth)?;
237-
238-
let local_recv_timestamp =
239-
timestamp + self.order_latency.response(timestamp, &order);
240-
self.orders_to.append(order, local_recv_timestamp);
241249
Ok(())
242250
}
243251
TimeInForce::FOK | TimeInForce::IOC => {
244252
order.status = Status::Expired;
245-
246253
order.exch_timestamp = timestamp;
247-
let local_recv_timestamp =
248-
timestamp + self.order_latency.response(timestamp, &order);
249-
self.orders_to.append(order.clone(), local_recv_timestamp);
250254
Ok(())
251255
}
252256
TimeInForce::Unsupported => Err(BacktestError::InvalidOrderRequest),
@@ -255,7 +259,7 @@ where
255259
}
256260
OrdType::Market => {
257261
// Takes the market.
258-
self.fill(&mut order, timestamp, false, self.depth.best_ask_tick())
262+
self.fill::<false>(order, timestamp, false, self.depth.best_ask_tick())
259263
}
260264
OrdType::Unsupported => Err(BacktestError::InvalidOrderRequest),
261265
}
@@ -267,18 +271,19 @@ where
267271
match order.time_in_force {
268272
TimeInForce::GTX => {
269273
order.status = Status::Expired;
270-
271274
order.exch_timestamp = timestamp;
272-
let local_recv_timestamp =
273-
timestamp + self.order_latency.response(timestamp, &order);
274-
self.orders_to.append(order.clone(), local_recv_timestamp);
275275
Ok(())
276276
}
277277
TimeInForce::GTC | TimeInForce::FOK | TimeInForce::IOC => {
278278
// Since this always fills the full quantity, both FOK and IOC
279279
// orders are also fully filled at the best price.
280280
// Takes the market.
281-
self.fill(&mut order, timestamp, false, self.depth.best_bid_tick())
281+
self.fill::<false>(
282+
order,
283+
timestamp,
284+
false,
285+
self.depth.best_bid_tick(),
286+
)
282287
}
283288
TimeInForce::Unsupported => Err(BacktestError::InvalidOrderRequest),
284289
}
@@ -291,19 +296,11 @@ where
291296

292297
self.queue_model
293298
.add_backtest_order(order.clone(), &self.depth)?;
294-
295-
let local_recv_timestamp =
296-
timestamp + self.order_latency.response(timestamp, &order);
297-
self.orders_to.append(order, local_recv_timestamp);
298299
Ok(())
299300
}
300301
TimeInForce::FOK | TimeInForce::IOC => {
301302
order.status = Status::Expired;
302-
303303
order.exch_timestamp = timestamp;
304-
let local_recv_timestamp =
305-
timestamp + self.order_latency.response(timestamp, &order);
306-
self.orders_to.append(order.clone(), local_recv_timestamp);
307304
Ok(())
308305
}
309306
TimeInForce::Unsupported => Err(BacktestError::InvalidOrderRequest),
@@ -312,42 +309,54 @@ where
312309
}
313310
OrdType::Market => {
314311
// Takes the market.
315-
self.fill(&mut order, timestamp, false, self.depth.best_bid_tick())
312+
self.fill::<false>(order, timestamp, false, self.depth.best_bid_tick())
316313
}
317314
OrdType::Unsupported => Err(BacktestError::InvalidOrderRequest),
318315
}
319316
}
320317
}
321318

322-
fn ack_cancel(&mut self, mut order: Order, timestamp: i64) -> Result<(), BacktestError> {
319+
fn ack_cancel(&mut self, order: &mut Order, timestamp: i64) -> Result<(), BacktestError> {
323320
match self
324321
.queue_model
325322
.cancel_backtest_order(order.order_id, &self.depth)
326323
{
327-
Ok(mut exch_order) => {
328-
// Makes the response.
329-
exch_order.status = Status::Canceled;
330-
exch_order.exch_timestamp = timestamp;
331-
let local_recv_timestamp =
332-
timestamp + self.order_latency.response(timestamp, &exch_order);
333-
self.orders_to
334-
.append(exch_order.clone(), local_recv_timestamp);
324+
Ok(exch_order) => {
325+
let _ = std::mem::replace(order, exch_order);
326+
327+
order.status = Status::Canceled;
328+
order.exch_timestamp = timestamp;
335329
Ok(())
336330
}
337331
Err(BacktestError::OrderNotFound) => {
338332
order.req = Status::Rejected;
339333
order.exch_timestamp = timestamp;
340-
let local_recv_timestamp =
341-
timestamp + self.order_latency.response(timestamp, &order);
342-
self.orders_to.append(order, local_recv_timestamp);
343334
Ok(())
344335
}
345336
Err(e) => Err(e),
346337
}
347338
}
348339

349-
fn ack_modify(&mut self, mut order: Order, timestamp: i64) -> Result<(), BacktestError> {
350-
todo!()
340+
fn ack_modify<const RESET_QUEUE_POS: bool>(
341+
&mut self,
342+
order: &mut Order,
343+
timestamp: i64,
344+
) -> Result<(), BacktestError> {
345+
match self
346+
.queue_model
347+
.modify_backtest_order(order.order_id, order, &self.depth)
348+
{
349+
Ok(()) => {
350+
order.exch_timestamp = timestamp;
351+
Ok(())
352+
}
353+
Err(BacktestError::OrderNotFound) => {
354+
order.req = Status::Rejected;
355+
order.exch_timestamp = timestamp;
356+
Ok(())
357+
}
358+
Err(e) => Err(e),
359+
}
351360
}
352361
}
353362

@@ -428,7 +437,7 @@ where
428437
let timestamp = event.exch_ts;
429438
for mut order in filled {
430439
let price_tick = order.price_tick;
431-
self.fill(&mut order, timestamp, true, price_tick)?;
440+
self.fill::<true>(&mut order, timestamp, true, price_tick)?;
432441
}
433442
}
434443
}

hftbacktest/src/backtest/proc/nopartialfillexchange.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,10 @@ where
534534
let mut order_borrowed = self.orders.borrow_mut();
535535
let exch_order = order_borrowed.get_mut(&order.order_id);
536536
let exch_order = exch_order.unwrap();
537+
537538
exch_order.qty = order.qty;
539+
exch_order.exch_timestamp = timestamp;
540+
order.exch_timestamp = timestamp;
538541
}
539542
Ok(())
540543
}

0 commit comments

Comments
 (0)