Skip to content
sigc GitHub

About

Built so the backtest plumbing stops being interesting.

Every quant team that scales past a handful of researchers eventually builds the same thing: a typed, reproducible signal language with deterministic caching, a vectorised operator library, and the same code path for research and production. sigc is that system, open-sourced.

The thesis: a compiler beats a script

Most quant research starts as a notebook. The notebook calls into pandas, pulls some prices, computes a couple of rolling stats, and prints a Sharpe. It works. It also rots: column names drift, calendars disagree, an off-by-one in shift() leaks tomorrow's return into today's signal, and nobody finds out until live PnL contradicts the paper trade.

sigc treats the strategy as a program in its own small language. A .sig file has four blocks: data, params, one or more signal blocks, and a portfolio block. The compiler parses the file, checks dtypes and indices, lowers it to an intermediate representation, and hands that IR to the runtime. The runtime hashes everything, looks up the cache, and either returns a cached result or computes a new one and writes it back.

That is the entire pitch: a compiler that catches the shape errors at parse time, a runtime that caches by content hash, and a single binary that runs both backtest and live.

What is in the box

The repository is a Rust workspace with six crates: sigc (the CLI and main entry point), sig_compiler (DSL parser and type checker), sig_runtime (the execution engine with 120+ operators), sig_types (the core type definitions), sig_cache (the deterministic caching layer on sled + blake3), and sig_lsp (the language server that powers the VS Code extension). A pysigc crate exposes the runtime to Python notebooks.

The operator library covers the surface area a factor researcher actually uses: returns and log-returns, lagging, z-scoring, ranking, winsorising, rolling means and standard deviations, exponential moving averages, RSI, MACD, ATR, VWAP, residualisation against a market factor, sector neutralisation, and the long-short, vol-targeted, and rank-based portfolio constructors that close the loop.

How the backtester is wired

A portfolio block names a weight scheme, a rebalance cadence, a transaction-cost model, an optional benchmark, and a date range. rank(momentum).long_short(top=0.2, bottom=0.2, cap=0.02) takes the named signal, ranks names cross-sectionally, picks the top and bottom 20%, and caps any single position at 2%. scale_vol(signal, target_ann_vol=0.10, lookback=252) scales weights so realised volatility tracks an annualised target. Transaction costs compose: tc.bps(5) + slippage.model("square-root", coef=0.1) applies a 5 bp commission plus a square-root impact model with coefficient 0.1.

The backtest emits Total Return, Sharpe Ratio, Max Drawdown, and Turnover by default. Daily returns and per-name weights are accessible from the Rust API as plain Vec<f64>.

How production is wired

The same binary runs as sigc daemon. The daemon owns the cache exclusively and answers compile and run requests over nng on tcp://127.0.0.1:7240. There is no broker, no Redis, no Kafka. Clients use REQ/REP; if the daemon is busy holding the cache lock, the client retries with exponential backoff.

A sigc.yaml file declares production posture: circuit breakers (max drawdown, max position size, kill switch), order-per-minute rate limits, Slack webhooks, Prometheus metrics on /metrics, and a schedule block with cron-style jobs that name a strategy and a cadence. Audit logs are emitted as structured JSON.

What sigc is not

sigc is not a hosted product. It is a Rust binary and a set of crates, MIT licensed, that you install from crates.io or build from source. It is not an execution broker; it integrates with Alpaca for paper and live trading and assumes you bring your own venues for anything else. It does not provide market data — it loads parquet, CSV, S3, GCS, or Postgres and expects you to keep your own data warm.

It is also not a notebook replacement. pysigc exists for analysts who want to stay in Jupyter but get the compiler's guarantees on the underlying signal computation.

Who builds it

sigc is a project of Skelf-Research. It is developed in the open on GitHub at Skelf-Research/sigc, published to crates.io as the sigc crate (with a sibling VS Code extension that talks to sig_lsp), and documented at docs.skelfresearch.com/sigc.

How to engage

If you are about to write your tenth backtester, cargo install sigc and try the quickstart. If you want the runtime inside a larger Rust system, depend on the sigc crate and call Strategy::from_file. If something is rough or missing, open an issue. PRs welcome; please discuss large changes first.