feat: trade-flow microstructure indicators (part 2 of 4) (#113)

* feat(core): add 3 trade-flow microstructure indicators

SignedVolume (per-trade size signed by aggressor), CumulativeVolumeDelta
(running signed-volume total), and TradeImbalance (rolling buy/sell volume
imbalance over a trade window). All consume the Trade type, with full unit
coverage. Extends the Microstructure family.

* feat(bindings): expose trade-flow microstructure indicators

Python, Node and WASM bindings for SignedVolume, CumulativeVolumeDelta and
TradeImbalance. Each takes a trade via update(price, size, is_buy); Python and
Node expose a batch over three parallel arrays, WASM exposes per-trade update.
Regenerates node index.d.ts/.js.

* test(bindings,fuzz,bench): cover trade-flow microstructure indicators

Python and Node: reference values, streaming-vs-batch, lifecycle/repr and input
validation (zero window, negative size, non-positive price, mismatched batch
lengths). New indicator_update_trade fuzz target. Synthetic trade-tape benches
(signed_volume cheapest, trade_imbalance windowed/expensive).

* docs: add trade-flow indicators + bump counter to 227

README Microstructure family row gains signed volume / CVD / trade imbalance and
the counter goes 224 -> 227; CHANGELOG records the trade-flow indicators.
This commit is contained in:
kingchenc
2026-06-01 16:38:48 +02:00
committed by GitHub
parent 2be21df803
commit 5867f71450
23 changed files with 1141 additions and 33 deletions
+22
View File
@@ -150,3 +150,25 @@ def test_orderbook_lifecycle():
def test_orderbook_topn_repr():
assert repr(ta.OrderBookImbalanceTopN(5)) == "OrderBookImbalanceTopN(levels=5)"
def test_tradeflow_lifecycle():
for ind in [ta.SignedVolume(), ta.CumulativeVolumeDelta()]:
assert ind.warmup_period() == 1
assert not ind.is_ready()
ind.update(100.0, 1.0, True)
assert ind.is_ready()
ind.reset()
assert not ind.is_ready()
def test_trade_imbalance_lifecycle_and_repr():
ti = ta.TradeImbalance(3)
assert ti.warmup_period() == 3
assert not ti.is_ready()
for _ in range(3):
ti.update(100.0, 1.0, True)
assert ti.is_ready()
ti.reset()
assert not ti.is_ready()
assert repr(ta.TradeImbalance(4)) == "TradeImbalance(window=4)"