v2.1.0 2.1.0 — fused idioms, one-pass group-by, AVX2 in the portable build

The array language
markets run on.

Amber is a small, fast, self-contained engine written in portable C99: columnar, vectorised, in-memory, with the working vocabulary of q/kdb+ — dictionaries, tables and keyed tables, the full join family including a native as-of kernel, qSQL select/by, and column attributes implemented in C that turn search from O(n) into O(log n).

2261×
find, 5M rows, sorted attribute
0.48×
of C -O3 on 10M reductions
amber — 1-minute VWAP over 5,000,000 trades live
$ git clone https://github.com/BonucciAndrea/amber.git && cd amber && ./a
C99 · gcc + clang/ AVX2 · ARM NEON · scalar/ Apache Arrow C Data Interface/ amberd TCP wire protocol/ AGPLv3
Engine

Built for the shape data actually has

A tick is not a row. It is one value in each of nine columns, and every question you ask of a trading day is a question about columns. Amber is columnar all the way down — storage, evaluation, the wire, and the handoff to Arrow.

Zero-copy memory layout

A column is one contiguous, cache-line-aligned payload. amber_get_vector_ptr() hands you that pointer — not a copy of it. NumPy's base, Arrow's data buffer and the engine's column are the same address, asserted by pointer equality in the test suites.

Native TCP wire protocol

amberd is ~450 lines of C: one engine, many connections, a one-line request and a length-prefixed reply in text, json, jsonc or raw. Small enough to reimplement in an afternoon — which Go, TypeScript and Python clients all have.

Array evaluation, not row loops

Every expression compiles to a flat opcode array and runs on a real stack VM. Vector ops dispatch into AVX2 / NEON kernels and split across cores above 100,000 elements. \disasm decodes the bytecode the compiler actually emitted.

Columnar storage & attributes

All four kdb-style attributes are implemented in C — `s sorted, `u unique, `p parted, `g grouped. Sorted turns ? into a binary search: 1.73 s → 1.4 ms on 2M rows, same answer.

Native as-of join

aj matches each trade to its most recent quote with a branch-free lower_bound over each symbol group's sorted nanosecond slice, off a thread-local 16 MB bump arena that keeps malloc jitter out of the hot path.

Diagnostics that read like Rust

An error[E0104] line, a --> locator, a gutter-aligned source line, ^^^ underlines and a = help: note. One report, never two — and switchable at runtime so a trap loop stays quiet.

Language

q vocabulary, K notation

If you have written q, you already know most of Amber: select … by … from … where …, aj, wj, xbar, wavg, meta, ([]…) table literals and keyed tables all mean what you expect. Bare qSQL works at the prompt with no sel"…" wrapper.

The notation underneath is terse array grammar. Any two-argument function can be applied infix (sz wavg px, 2 3 in 2 4 5) or with brackets (wavg[sz;px]); three-argument functions like aj[c;x;y] use brackets. There is no >= or <=, and symbols cannot contain _ — because _ is a verb.

session.k
/ tables are first-class and render without `show`
t:([]sym:`AAPL`MSFT`AAPL; px:187.3 411.2 187.4; sz:100 250 50)

/ qSQL, typed bare at the prompt
select vwap:wavg[sz;px] by sym from t

/ 1-minute OHLCV bars — the classic tickerplant query
gentq 100000                / sets the globals: trades, quotes
tb:+@[+trades; ,`time; minbar[1]@]
qby[tb; `sym`time;
    `o`h`l`c`v!({first x`px};{max x`px};{min x`px};{last x`px};{sum x`sz})]

/ TAQ: the prevailing quote for every print
m:aj[`sym`time; trades; quotes]

/ sorted attribute => O(log n) lookups
v:asc 2000000?1000000000
`at v                       / `s
v ? 12345 67890             / binary search, ~1244x faster

/ zero-copy Arrow C Data Interface, no libarrow linkage
p:arrow.export t            / (schemaAddr; arrayAddr)
amber-tick

A whole market, generated and stored

amber-tick writes a partitioned, splayed column store the engine reads natively — 38M prints, 89M quotes, ten-level book snapshots and LULD halts across five sessions and 500 names, from a simulator whose realism is checked: twenty-one published stylized facts, all passing on every generated store.

arrivals
discrete-time Hawkes process — bursts, not flat Poisson
quotes first
so a print can never fall outside the NBBO
epoch
nanoseconds since 2000-01-01 — Amber's own, not Unix
files
each column is one -8! value, byte-identical to the engine's
Build a 5M-row store in 60 seconds →
AAPL 187.32 tape 1s · lit + TRF

Simulated tape: mean-reverting tick returns (bid-ask bounce) with clustered arrivals.

Architecture

One engine, three seams

Everything that consumes Amber lives outside the engine repository and reaches it through libamber.so, the in-process ext/ registry, or a TCP socket. The engine gained one build flag, one export map and one header section for all of it.

Amber engine portable C99 · gcc + clang a.c b.c evaluator + VM simd.c parallel.c kernels arena.c 16 MB HFT arena ser.c -8! / -9! binary ar.c Arrow C Data Interface ext.h the extension seam libamber.so ~60 amber_* entry points ext/ registry in-process · runtime verbs amberd :5010 TCP · text json jsonc raw python-amber — NumPy · pandas · Polars amber-arrow — ArrowArrayStream · Flight amber-jupyter — one process, one heap amber-ai — local co-pilot, loopback only grafana-amber — Go backend, columnar vscode-amber — LSP, \parse only amber-tick — tickerplant · RDB · HDB
Benchmarks

Measured against C, and against everyone else

Seven engines, four workloads, one specification. Every answer is an integer that fits float64 exactly, so summation order cannot change it — the harness compares answers bit-exactly against the C reference and prints WRONG instead of a time for any engine that disagrees.

Workload (10M rows unless noted) C -O3AmberAmber qSQL CBQNNumPyDuckDBngn/k
Vector arithmetic + mask10.0622.0652.7835.7332.0229.00320.10
Reductions — sum + max + dot28.2713.4669.085.6210.2138.00299.92
Group-by — 100 groups8.2776.67210.1438.2814.9818.00348.73
Inner join — 1M × 1,000 sparse keys1.074.398.412.3814.6911.00452.92

Median of 5 timed runs after 2 warm-ups, milliseconds, kernel time only; the 2.1.0 build, regenerated by CI (the group-by row still spells the aggregate with the pre-2.1 idiom and refreshes on the next run; the fused gsum path measures 21 ms on the scout matrix). Amber is reported twice on purpose: array-primitive code is the fair peer of ngn/k and CBQN; the qSQL layer is the fair peer of DuckDB's planner. The gap between the rows is the query layer's overhead, and it is meant to be visible. Full results →

Ecosystem

Nothing here patches the engine

Each satellite reaches Amber through a published seam and nothing else. Delete any of them and the engine is byte-for-byte what it was.

python-amber

libamber.so

The engine in your Python process. pip install amber, then NumPy views that point at the engine's own column buffers — no server, no socket, no serialisation.

Read more →

amber-arrow

libamber.so

An ArrowArrayStream whose batches are windows onto one export, not slices of it. Plus amberd, the TCP query server, and an Arrow Flight daemon.

Read more →

amber-jupyter

python-amber

Amber cells and %%python cells in one process, so a column crosses the boundary as a pointer. HTML grids with type tags, capped at 500 rows on purpose.

Read more →

amber-tick

store + runtime

A US-equity simulator, a splayed partitioned store, TAQ analytics, and a live tickerplant → RDB → HDB pipeline with a replayable sequenced log.

Read more →

grafana-amber

amberd socket

Live dashboards over bare qSQL, column-oriented on the wire. A Go backend, a mage build, and time macros that speak Amber's epoch rather than Unix's.

Read more →

vscode-amber

LSP

qSQL-aware completion where the clause decides the vocabulary, hovers that explain idioms like x@<x, and diagnostics that never evaluate your code.

Read more →

amber-ai

ext/ seam

A schema-aware co-pilot that reads your live tables before it answers, talks only to 127.0.0.1:11434, and cannot hang or break the REPL.

Read more →

amber-flame

profiler

A visual profiler: flamegraphs, Speedscope and Chrome tracing, built on the engine's own \trace.

View on GitHub →

Tutorials

start here

Three end-to-end walkthroughs: a 5-million-row tick store, a Grafana dashboard pipeline, and Arrow record batches into Python without a copy.

Read more →

One command. No install.

Amber compiles from source on first run and installs nothing system-wide. There is no bin/, no QHOME, no dotfile — deleting the folder uninstalls it completely.

bash
git clone https://github.com/BonucciAndrea/amber.git
cd amber
chmod +x a build.sh install.sh
./a                      # builds with -O3, then opens the REPL