feat(data-layer): TickAggregator (tick-to-candle) in all 10 languages (#309)

* feat(data-layer): TickAggregator in Node, WASM, Python + C ABI hub

First data-layer feature (F2): roll trade ticks up into fixed-timeframe OHLCV
candles, exposed natively and over the C ABI.

- wickra-data wired as a binding dependency (workspace dep; its wickra-core dep
  is default-features=false so it never forces rayon into the rayon-free WASM
  build — native bindings re-enable parallel through their own dependency).
- Node `TickAggregator(bucket, gapFill?)` -> `push(price, size, ts): Candle[]`;
  WASM the same (array of objects); Python `push(...) -> list[tuple]`.
- C ABI: `WickraCandle` struct + `wickra_tick_aggregator_new/push/free` (push
  writes candles into a caller buffer and returns the count), generated via the
  capi generator's new DATA_LAYER section; cbindgen now parses wickra-data so
  `TickAggregator` is a forward-declared opaque; header vendored to bindings/go.

Verified bit-identical across Node/WASM/Python/C/C++ (o=100 h=101 l=100 c=101
v=3 ts=0 for the shared 3-tick probe). WIP: Go/C#/Java/R generated bindings and
the cross-language golden are still pending.

* feat(data-layer): TickAggregator in Go, C#, Java, R (lossless push/drain)

Complete F2 across all 10 languages: the C-ABI tick aggregator now uses a
two-step push/drain so gap-fill candles are never lost, and the four generated
bindings expose it idiomatically.

- C ABI redesigned: opaque TickAggregator handle (inner aggregator + pending
  buffer); push consumes a tick and returns the closed-candle count, drain copies
  them into a count-sized caller buffer.
- Go: NewTickAggregator + Push(price,size,ts) []Candle; C#: TickAggregator +
  Candle[] Push(...); Java: TickAggregator + Candle[] push(...); R: TickAggregator
  constructor + push() S3 generic returning an (n x 6) numeric matrix.
- Candle output record generated per language from WickraCandle.

Verified bit-identical to the native bindings (o=100 h=101 l=100 c=101 v=3 ts=0)
in Go, C#, Java, and R at runtime; R passes R CMD check (pre-existing doc
warnings only). WIP: cross-language data-layer golden + CHANGELOG still pending.

* test(data-layer): cross-language golden for the tick aggregator + CHANGELOG

gen_golden emits a deterministic tick stream (testdata/golden/data_ticks.csv) and
the reference candle streams with and without gap filling (data_candles.csv,
data_candles_gap.csv). Every binding replays the shared ticks through its
TickAggregator and checks the candles bit-for-bit (fp tolerance) against the Rust
reference:

- Node / WASM / Python / Go / C# / Java / R: a dedicated parity test each.
- C / C++: data_layer_test.c (compiled as both, run as ctest).

The gap-fill fixture closes several candles from a single push, exercising the
lossless push/drain path. Records the feature under CHANGELOG [Unreleased].

* fix(examples): rename the CSV-loader candle to WickraBar

The example CSV helper (wickra_csv.h) defined its own struct WickraCandle, which
now collides with the public C ABI WickraCandle (the tick aggregator output) in
any example that includes both headers (backtest, multi_timeframe, the strategy
examples). The public type owns the name; rename the example loader's bar to
WickraBar. The generated golden_test.c is untouched (its only match was the
unrelated WickraCandleVolumeOutput).
This commit is contained in:
kingchenc
2026-06-15 21:24:33 +02:00
committed by GitHub
parent fd9f4c8bc6
commit 8a103ef920
48 changed files with 1368 additions and 29 deletions
+22
View File
@@ -0,0 +1,22 @@
open,high,low,close,volume,timestamp
100,106.64642473395035,100,106.64642473395035,6,0
109.33326909627483,112.47494986604055,109.33326909627483,112.47494986604055,10,1000
112.73847630878196,112.73847630878196,110.75463180551151,110.75463180551151,9,2000
108.7737988023383,108.7737988023383,103.92254305856751,103.92254305856751,8,3000
101.57479556705148,101.57479556705148,98.28424227586412,98.28424227586412,12,4000
97.72469882334903,99.24185317672267,97.72469882334903,99.24185317672267,6,5000
101.27235512444012,103.99314457402363,101.27235512444012,103.99314457402363,9,6000
107.20584501801073,114.11541363513378,107.20584501801073,114.11541363513378,6,7000
117.28439764388199,121.87999976774739,117.28439764388199,121.87999976774739,10,8000
122.98543345374605,123.19889810845086,122.5459890808828,122.5459890808828,9,9000
121.12969230082183,121.12969230082183,116.74454423507063,116.74454423507063,8,10000
114.2567321877702,114.2567321877702,110.00125312406458,110.00125312406458,12,11000
108.7030424002833,108.7030424002833,108.7030424002833,108.7030424002833,1,12000
108.19063769933508,108.55447411796011,108.19063769933508,108.55447411796011,5,17000
109.80671474335324,111.88016416080967,109.80671474335324,111.88016416080967,9,18000
114.63427081999565,121.33623047221137,114.63427081999565,121.33623047221137,6,19000
124.77474439137693,130.5378442655162,124.77474439137693,130.5378442655162,10,20000
132.43695669444105,133.65657776549278,132.43695669444105,133.65657776549278,9,21000
132.95746831142935,132.95746831142935,129.46740573130614,129.46740573130614,8,22000
127.07753652299444,127.07753652299444,122.27578013601534,122.27578013601534,12,23000
120.38214657630877,120.38214657630877,118.65934994918358,118.65934994918358,6,24000
1 open high low close volume timestamp
2 100 106.64642473395035 100 106.64642473395035 6 0
3 109.33326909627483 112.47494986604055 109.33326909627483 112.47494986604055 10 1000
4 112.73847630878196 112.73847630878196 110.75463180551151 110.75463180551151 9 2000
5 108.7737988023383 108.7737988023383 103.92254305856751 103.92254305856751 8 3000
6 101.57479556705148 101.57479556705148 98.28424227586412 98.28424227586412 12 4000
7 97.72469882334903 99.24185317672267 97.72469882334903 99.24185317672267 6 5000
8 101.27235512444012 103.99314457402363 101.27235512444012 103.99314457402363 9 6000
9 107.20584501801073 114.11541363513378 107.20584501801073 114.11541363513378 6 7000
10 117.28439764388199 121.87999976774739 117.28439764388199 121.87999976774739 10 8000
11 122.98543345374605 123.19889810845086 122.5459890808828 122.5459890808828 9 9000
12 121.12969230082183 121.12969230082183 116.74454423507063 116.74454423507063 8 10000
13 114.2567321877702 114.2567321877702 110.00125312406458 110.00125312406458 12 11000
14 108.7030424002833 108.7030424002833 108.7030424002833 108.7030424002833 1 12000
15 108.19063769933508 108.55447411796011 108.19063769933508 108.55447411796011 5 17000
16 109.80671474335324 111.88016416080967 109.80671474335324 111.88016416080967 9 18000
17 114.63427081999565 121.33623047221137 114.63427081999565 121.33623047221137 6 19000
18 124.77474439137693 130.5378442655162 124.77474439137693 130.5378442655162 10 20000
19 132.43695669444105 133.65657776549278 132.43695669444105 133.65657776549278 9 21000
20 132.95746831142935 132.95746831142935 129.46740573130614 129.46740573130614 8 22000
21 127.07753652299444 127.07753652299444 122.27578013601534 122.27578013601534 12 23000
22 120.38214657630877 120.38214657630877 118.65934994918358 118.65934994918358 6 24000
+26
View File
@@ -0,0 +1,26 @@
open,high,low,close,volume,timestamp
100,106.64642473395035,100,106.64642473395035,6,0
109.33326909627483,112.47494986604055,109.33326909627483,112.47494986604055,10,1000
112.73847630878196,112.73847630878196,110.75463180551151,110.75463180551151,9,2000
108.7737988023383,108.7737988023383,103.92254305856751,103.92254305856751,8,3000
101.57479556705148,101.57479556705148,98.28424227586412,98.28424227586412,12,4000
97.72469882334903,99.24185317672267,97.72469882334903,99.24185317672267,6,5000
101.27235512444012,103.99314457402363,101.27235512444012,103.99314457402363,9,6000
107.20584501801073,114.11541363513378,107.20584501801073,114.11541363513378,6,7000
117.28439764388199,121.87999976774739,117.28439764388199,121.87999976774739,10,8000
122.98543345374605,123.19889810845086,122.5459890808828,122.5459890808828,9,9000
121.12969230082183,121.12969230082183,116.74454423507063,116.74454423507063,8,10000
114.2567321877702,114.2567321877702,110.00125312406458,110.00125312406458,12,11000
108.7030424002833,108.7030424002833,108.7030424002833,108.7030424002833,1,12000
108.7030424002833,108.7030424002833,108.7030424002833,108.7030424002833,0,13000
108.7030424002833,108.7030424002833,108.7030424002833,108.7030424002833,0,14000
108.7030424002833,108.7030424002833,108.7030424002833,108.7030424002833,0,15000
108.7030424002833,108.7030424002833,108.7030424002833,108.7030424002833,0,16000
108.19063769933508,108.55447411796011,108.19063769933508,108.55447411796011,5,17000
109.80671474335324,111.88016416080967,109.80671474335324,111.88016416080967,9,18000
114.63427081999565,121.33623047221137,114.63427081999565,121.33623047221137,6,19000
124.77474439137693,130.5378442655162,124.77474439137693,130.5378442655162,10,20000
132.43695669444105,133.65657776549278,132.43695669444105,133.65657776549278,9,21000
132.95746831142935,132.95746831142935,129.46740573130614,129.46740573130614,8,22000
127.07753652299444,127.07753652299444,122.27578013601534,122.27578013601534,12,23000
120.38214657630877,120.38214657630877,118.65934994918358,118.65934994918358,6,24000
1 open high low close volume timestamp
2 100 106.64642473395035 100 106.64642473395035 6 0
3 109.33326909627483 112.47494986604055 109.33326909627483 112.47494986604055 10 1000
4 112.73847630878196 112.73847630878196 110.75463180551151 110.75463180551151 9 2000
5 108.7737988023383 108.7737988023383 103.92254305856751 103.92254305856751 8 3000
6 101.57479556705148 101.57479556705148 98.28424227586412 98.28424227586412 12 4000
7 97.72469882334903 99.24185317672267 97.72469882334903 99.24185317672267 6 5000
8 101.27235512444012 103.99314457402363 101.27235512444012 103.99314457402363 9 6000
9 107.20584501801073 114.11541363513378 107.20584501801073 114.11541363513378 6 7000
10 117.28439764388199 121.87999976774739 117.28439764388199 121.87999976774739 10 8000
11 122.98543345374605 123.19889810845086 122.5459890808828 122.5459890808828 9 9000
12 121.12969230082183 121.12969230082183 116.74454423507063 116.74454423507063 8 10000
13 114.2567321877702 114.2567321877702 110.00125312406458 110.00125312406458 12 11000
14 108.7030424002833 108.7030424002833 108.7030424002833 108.7030424002833 1 12000
15 108.7030424002833 108.7030424002833 108.7030424002833 108.7030424002833 0 13000
16 108.7030424002833 108.7030424002833 108.7030424002833 108.7030424002833 0 14000
17 108.7030424002833 108.7030424002833 108.7030424002833 108.7030424002833 0 15000
18 108.7030424002833 108.7030424002833 108.7030424002833 108.7030424002833 0 16000
19 108.19063769933508 108.55447411796011 108.19063769933508 108.55447411796011 5 17000
20 109.80671474335324 111.88016416080967 109.80671474335324 111.88016416080967 9 18000
21 114.63427081999565 121.33623047221137 114.63427081999565 121.33623047221137 6 19000
22 124.77474439137693 130.5378442655162 124.77474439137693 130.5378442655162 10 20000
23 132.43695669444105 133.65657776549278 132.43695669444105 133.65657776549278 9 21000
24 132.95746831142935 132.95746831142935 129.46740573130614 129.46740573130614 8 22000
25 127.07753652299444 127.07753652299444 122.27578013601534 122.27578013601534 12 23000
26 120.38214657630877 120.38214657630877 118.65934994918358 118.65934994918358 6 24000
+61
View File
@@ -0,0 +1,61 @@
price,size,timestamp
100,1,0
103.4552020666134,2,350
106.64642473395035,3,700
109.33326909627483,4,1050
111.32039085967226,5,1400
112.47494986604055,1,1750
112.73847630878196,2,2100
112.13209366648874,3,2450
110.75463180551151,4,2800
108.7737988023383,5,3150
106.41120008059868,1,3500
103.92254305856751,2,3850
101.57479556705148,3,4200
99.62233840816026,4,4550
98.28424227586412,5,4900
97.72469882334903,1,5250
98.0383539116416,2,5600
99.24185317672267,3,5950
101.27235512444012,4,6300
103.99314457402363,5,6650
107.20584501801073,1,7000
110.6681390048435,2,7350
114.11541363513378,3,7700
117.28439764388199,4,8050
119.93667863849153,5,8400
121.87999976774739,1,8750
122.98543345374605,2,9100
123.19889810845086,3,9450
122.5459890808828,4,9800
121.12969230082183,5,10150
119.12118485241757,1,10500
116.74454423507063,2,10850
114.2567321877702,3,11200
111.92464106224679,4,11550
110.00125312406458,5,11900
108.7030424002833,1,12250
108.19063769933508,2,17600
108.55447411796011,3,17950
109.80671474335324,4,18300
111.88016416080967,5,18650
114.63427081999565,1,19000
117.86768208634197,2,19350
121.33623047221137,3,19700
124.77474439137693,4,20050
127.92073514707224,5,20400
130.5378442655162,1,20750
132.43695669444105,2,21100
133.49309388747918,3,21450
133.65657776549278,4,21800
132.95746831142935,5,22150
131.50287840157117,1,22500
129.46740573130614,2,22850
127.07753652299444,3,23200
124.59141418625812,4,23550
122.27578013601534,5,23900
120.38214657630877,1,24250
119.12432966418496,2,24600
118.65934994918358,3,24950
119.07340619529367,4,25300
120.37417550208815,5,25650
1 price size timestamp
2 100 1 0
3 103.4552020666134 2 350
4 106.64642473395035 3 700
5 109.33326909627483 4 1050
6 111.32039085967226 5 1400
7 112.47494986604055 1 1750
8 112.73847630878196 2 2100
9 112.13209366648874 3 2450
10 110.75463180551151 4 2800
11 108.7737988023383 5 3150
12 106.41120008059868 1 3500
13 103.92254305856751 2 3850
14 101.57479556705148 3 4200
15 99.62233840816026 4 4550
16 98.28424227586412 5 4900
17 97.72469882334903 1 5250
18 98.0383539116416 2 5600
19 99.24185317672267 3 5950
20 101.27235512444012 4 6300
21 103.99314457402363 5 6650
22 107.20584501801073 1 7000
23 110.6681390048435 2 7350
24 114.11541363513378 3 7700
25 117.28439764388199 4 8050
26 119.93667863849153 5 8400
27 121.87999976774739 1 8750
28 122.98543345374605 2 9100
29 123.19889810845086 3 9450
30 122.5459890808828 4 9800
31 121.12969230082183 5 10150
32 119.12118485241757 1 10500
33 116.74454423507063 2 10850
34 114.2567321877702 3 11200
35 111.92464106224679 4 11550
36 110.00125312406458 5 11900
37 108.7030424002833 1 12250
38 108.19063769933508 2 17600
39 108.55447411796011 3 17950
40 109.80671474335324 4 18300
41 111.88016416080967 5 18650
42 114.63427081999565 1 19000
43 117.86768208634197 2 19350
44 121.33623047221137 3 19700
45 124.77474439137693 4 20050
46 127.92073514707224 5 20400
47 130.5378442655162 1 20750
48 132.43695669444105 2 21100
49 133.49309388747918 3 21450
50 133.65657776549278 4 21800
51 132.95746831142935 5 22150
52 131.50287840157117 1 22500
53 129.46740573130614 2 22850
54 127.07753652299444 3 23200
55 124.59141418625812 4 23550
56 122.27578013601534 5 23900
57 120.38214657630877 1 24250
58 119.12432966418496 2 24600
59 118.65934994918358 3 24950
60 119.07340619529367 4 25300
61 120.37417550208815 5 25650