mirror of
https://github.com/KhizarImran/backtestingfx.git
synced 2026-11-02 11:36:31 +00:00
perf: process batch SL/TP exits in linear time
Codex 🤖, On behalf of Khizar
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# Batch SL/TP benchmark
|
||||
|
||||
Run `cargo run --release --example benchmark_sl_tp` from the repository root.
|
||||
The example opens positions before timing, then measures one `check_sl_tp`
|
||||
call with all stops triggered. Each of nine repetitions uses a fresh broker;
|
||||
results are medians. Assertions check that every position closes and trade
|
||||
order matches submission order. Trade allocation and settlement are included.
|
||||
|
||||
Measured on an Intel Core i5-8350U (4 cores / 8 threads), Linux x86_64,
|
||||
Rust 1.98.1, PyO3 0.28.3, CPython 3.14.4, default Cargo release profile.
|
||||
The benchmark itself executes entirely in Rust on one thread.
|
||||
Before uses the repeated `Vec::remove` implementation at commit `867eee6`;
|
||||
after uses stable in-place compaction. Both use the same example and settings.
|
||||
|
||||
| Positions | Before (microseconds) | After (microseconds) |
|
||||
| ---: | ---: | ---: |
|
||||
| 1,000 | 521.215 | 7.622 |
|
||||
| 2,000 | 2,245.135 | 54.041 |
|
||||
| 4,000 | 10,763.030 | 109.674 |
|
||||
| 8,000 | 52,533.606 | 222.399 |
|
||||
| 16,000 | 232,879.797 | 484.124 |
|
||||
| 32,000 | 966,525.622 | 980.658 |
|
||||
|
||||
From 2,000 through 32,000 positions, the new implementation takes roughly
|
||||
27–31 ns per position, consistent with linear scaling. The 1,000-position
|
||||
case fits a smaller working set and is faster per position. At 32,000 positions
|
||||
the measured batch-close speedup is about 986x. These are local microbenchmark
|
||||
results, not an end-to-end backtest speedup; strategies with few open positions
|
||||
will see much smaller gains. Timing varies with hardware and system load.
|
||||
@@ -0,0 +1,37 @@
|
||||
//! Run with `cargo run --release --example benchmark_sl_tp`.
|
||||
//! Position setup is excluded; each repetition uses a fresh broker.
|
||||
use _backtestingfx::broker::Broker;
|
||||
use _backtestingfx::types::Bar;
|
||||
use std::hint::black_box;
|
||||
use std::time::Instant;
|
||||
|
||||
fn main() {
|
||||
const REPEATS: usize = 9;
|
||||
println!("All positions hit SL on one bar; median of {REPEATS} runs");
|
||||
for count in [1_000, 2_000, 4_000, 8_000, 16_000, 32_000] {
|
||||
let mut times = Vec::with_capacity(REPEATS);
|
||||
for _ in 0..REPEATS {
|
||||
let mut broker = Broker::new(10_000.0, 7.0, 0.0001, 100_000.0, 1.27);
|
||||
for i in 0..count {
|
||||
broker.buy(1.1, 0.01, i as i64, Some(1.09), None);
|
||||
}
|
||||
let bar = Bar::new(count as i64, 1.1, 1.11, 1.08, 1.1, 0.0);
|
||||
let start = Instant::now();
|
||||
broker.check_sl_tp(black_box(&bar));
|
||||
times.push(start.elapsed());
|
||||
assert!(broker.positions.is_empty());
|
||||
assert_eq!(broker.trade_history.len(), count);
|
||||
for (i, trade) in broker.trade_history.iter().enumerate() {
|
||||
assert_eq!(trade.entry_timestamp, i as i64);
|
||||
}
|
||||
black_box(&broker);
|
||||
}
|
||||
times.sort_unstable();
|
||||
let median = times[REPEATS / 2];
|
||||
println!(
|
||||
"{count:>6} positions: {:>12.3} us ({:.1} ns/position)",
|
||||
median.as_secs_f64() * 1e6,
|
||||
median.as_secs_f64() * 1e9 / count as f64
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user