feat: order-book microstructure indicators (part 1 of 4) (#112)
* feat(core): add microstructure input types (OrderBook, Trade, TradeQuote) New non-OHLCV value types for the order-book / trade-flow indicator family: Level, OrderBook (sorted, uncrossed depth snapshot), Side, Trade (with aggressor side), and TradeQuote (trade paired with prevailing mid). Each has a validating constructor plus a new_unchecked hot-path constructor, with full unit coverage. Adds InvalidOrderBook / InvalidTrade error variants. * feat(core): add 5 order-book microstructure indicators OrderBookImbalanceTop1/TopN/Full (signed depth imbalance), Microprice (size-weighted fair value), and QuotedSpread (top-of-book spread in bps). All consume the OrderBook snapshot type, emit f64, are stateless and ready after the first snapshot, with full unit coverage. Registers a new Microstructure family in the taxonomy. * feat(bindings): expose order-book microstructure indicators Python, Node, and WASM bindings for OrderBookImbalanceTop1/TopN/Full, Microprice and QuotedSpread. Each takes a depth snapshot via four equal-length (bid_px, bid_sz, ask_px, ask_sz) arrays. Python and Node expose a batch over a list of snapshots; WASM exposes per-snapshot update (the streaming model that fits a browser book feed). Regenerates node index.d.ts/.js and registers the new InvalidOrderBook/InvalidTrade arms in the Python error mapping. * test(bindings,fuzz): cover order-book microstructure indicators Python: smoke, reference values, streaming-vs-batch, lifecycle/repr and input validation (mismatched lengths, crossed book, misordered levels, zero levels) for all five order-book indicators. Node: reference values, streaming-vs-batch, and rejection cases. Adds an indicator_update_orderbook fuzz target driving every order-book indicator over arbitrary (incl. degenerate) snapshots. * bench(microstructure): synthetic order-book benchmarks Add a bench_orderbook_input harness and synthesise a five-level book around each candle close (no order-book dataset ships with the repo). Benches the cheapest (top-of-book imbalance) and most-expensive (full-depth imbalance) plus microprice, matching the curated cheapest/expensive-per-family approach. * docs: add Microstructure family + bump indicator counter to 224 README gains the Microstructure family row (order-book imbalance, microprice, quoted spread) and the indicator counter goes 219 -> 224 across seventeen families; CHANGELOG records the new order-book indicators and value types.
This commit is contained in:
@@ -34,12 +34,12 @@ use std::hint::black_box;
|
||||
use wickra::{
|
||||
Adx, Atr, Autocorrelation, BatchExt, BollingerBands, BollingerOutput, CalmarRatio, Candle, Cci,
|
||||
ClassicPivots, ConnorsRsi, Ema, EmpiricalModeDecomposition, Engulfing, Frama,
|
||||
HilbertDominantCycle, HurstExponent, Ichimoku, IchimokuOutput, Indicator, Jma,
|
||||
LinearRegression, MacdIndicator, MacdOutput, Mama, MamaOutput, MaxDrawdown, Obv,
|
||||
ParkinsonVolatility, Ppo, Psar, RollingVwap, Rsi, SharpeRatio, Sma, Stc, SuperTrend,
|
||||
SuperTrendOutput, TdSequential, TdSequentialOutput, TtmSqueeze, TtmSqueezeOutput, ValueArea,
|
||||
ValueAreaOutput, ValueAtRisk, Vwap, VwapStdDevBands, VwapStdDevBandsOutput, WaveTrend,
|
||||
YangZhangVolatility, T3,
|
||||
HilbertDominantCycle, HurstExponent, Ichimoku, IchimokuOutput, Indicator, Jma, Level,
|
||||
LinearRegression, MacdIndicator, MacdOutput, Mama, MamaOutput, MaxDrawdown, Microprice, Obv,
|
||||
OrderBook, OrderBookImbalanceFull, OrderBookImbalanceTop1, ParkinsonVolatility, Ppo, Psar,
|
||||
RollingVwap, Rsi, SharpeRatio, Sma, Stc, SuperTrend, SuperTrendOutput, TdSequential,
|
||||
TdSequentialOutput, TtmSqueeze, TtmSqueezeOutput, ValueArea, ValueAreaOutput, ValueAtRisk,
|
||||
Vwap, VwapStdDevBands, VwapStdDevBandsOutput, WaveTrend, YangZhangVolatility, T3,
|
||||
};
|
||||
use wickra_data::csv::CandleReader;
|
||||
|
||||
@@ -114,6 +114,28 @@ where
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn bench_orderbook_input<I, F, O>(c: &mut Criterion, name: &str, books: &[OrderBook], make: F)
|
||||
where
|
||||
F: Fn() -> I,
|
||||
I: Indicator<Input = OrderBook, Output = O>,
|
||||
{
|
||||
let mut group = c.benchmark_group(name);
|
||||
for &n in SIZES {
|
||||
let n = n.min(books.len());
|
||||
let series = &books[..n];
|
||||
group.throughput(Throughput::Elements(n as u64));
|
||||
group.bench_with_input(BenchmarkId::new("streaming", n), series, |b, books| {
|
||||
b.iter(|| {
|
||||
let mut ind = make();
|
||||
for book in books {
|
||||
black_box(ind.update(book.clone()));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn bench_scalar_multi<I, F, O>(c: &mut Criterion, name: &str, prices: &[f64], make: F)
|
||||
where
|
||||
F: Fn() -> I,
|
||||
@@ -265,6 +287,28 @@ fn benches(c: &mut Criterion) {
|
||||
bench_scalar(c, "value_at_risk", &closes, || {
|
||||
ValueAtRisk::new(50, 0.95).unwrap()
|
||||
});
|
||||
|
||||
// === Family — Microstructure ===
|
||||
// No order-book dataset ships with the repo, so synthesise a five-level
|
||||
// book around each candle close. Benches the cheapest (top-of-book) and the
|
||||
// most-expensive (full-depth sum) representatives of the family.
|
||||
let books: Vec<OrderBook> = candles
|
||||
.iter()
|
||||
.map(|candle| {
|
||||
let mid = candle.close;
|
||||
let tick = (mid * 0.0001).max(0.01);
|
||||
let bids = (0..5u32)
|
||||
.map(|i| Level::new_unchecked(mid - tick * f64::from(i + 1), 1.0 + f64::from(i)))
|
||||
.collect();
|
||||
let asks = (0..5u32)
|
||||
.map(|i| Level::new_unchecked(mid + tick * f64::from(i + 1), 1.0 + f64::from(i)))
|
||||
.collect();
|
||||
OrderBook::new_unchecked(bids, asks)
|
||||
})
|
||||
.collect();
|
||||
bench_orderbook_input(c, "ob_imbalance_top1", &books, OrderBookImbalanceTop1::new);
|
||||
bench_orderbook_input(c, "ob_imbalance_full", &books, OrderBookImbalanceFull::new);
|
||||
bench_orderbook_input(c, "microprice", &books, Microprice::new);
|
||||
}
|
||||
|
||||
criterion_group!(name = wickra_benches; config = Criterion::default(); targets = benches);
|
||||
|
||||
Reference in New Issue
Block a user