Ask how often a trading setup actually worked, on your own market data.
Every answer is one query, P(outcome | conditions), with the sample size and confidence interval attached.
Quickstart · Catalog · Data sources · MCP · Architecture
Edge Stats is a LuxAlgo open source project. Official repository: github.com/LuxAlgo/edge-stats.
Edge Stats answers questions like: how often did a Tuesday gap fill, and how long did the fill take? It syncs intraday bars from your own data source into a local DuckDB store, derives session features once, and then runs any question you can compose as a query. Any outcome in the registry combines with any set of conditions, so the report catalog is simply a folder of preset queries. It ships as a CLI, a local dashboard, and an MCP server; all three run the same engine and return the same result envelope.
$ edgestats query "gapFill WHERE dayOfWeek = Tue AND gapPct BETWEEN 0.05% AND 0.6%" --symbol DEMO_STK
gapFill WHERE dayOfWeek = Tue AND gapPct BETWEEN 0.05% AND 0.6%
DEMO_STK · rth · start → latest
estimate 80.0% N = 30 95% CI [62.7%, 90.5%] (24 hits)
stability: 86.7% (n=15) vs 73.3% (n=15) · halves agree ✓
distribution (minutes, n=24): median 3 · p25 0 · p75 31 · p90 157
per-year: 2023 88.2% (17) · 2024 69.2% (13)
Historical conditional frequencies with sample sizes. Not predictions, not advice.
The demo store is deterministic synthetic data; no keys, no external services.
git clone https://github.com/LuxAlgo/edge-stats && cd edge-stats
pnpm install
pnpm edgestats init --demo # ~900k synthetic bars, derived in seconds
pnpm edgestats query "gapFill WHERE dayOfWeek = Tue" --symbol DEMO_STK
pnpm edgestats report gap-fill --symbol DEMO_FUT --group gapBucket
pnpm edgestats serve # dashboard + API on localhostFor real data, edgestats adapters lists every source and the env keys each one reads. Keys are read from your environment and never logged or sent anywhere else.
Report cards, a query builder that shows the live DSL string, per-report filter pages, a live board, and drill-down from any number to the sessions behind it. The full query is encoded in the URL, so any view can be shared and reproduced.
The synthetic demo store (edgestats init --demo): a session from the gap-fill report on DEMO_STK, gap band between the prior close and the open, the fill marked at 15:19. Not real market data.
Every result lists the sessions it counted, and any of them opens in a session view: that session's 1-minute bars with the query's levels drawn over them, the prior session's high, low, and close, the session open, the opening range for opening-range outcomes, the gap band between the prior close and the open, and a marker at the moment the outcome happened ("filled 15:19", "broke up 09:59"). A "gap filled 80%" is a claim about sessions; this is where you pick one and look. Older and newer step through the matched sessions.
It opens one session at a time, and the bars are read from that session's own (symbol, timeframe, year) parquet partition, so the size of your history has no effect on it: a session out of ten years of 1-minute bars costs the same as one out of ten days. The chart is drawn in the browser by Vela, LuxAlgo's open-source charting library (Apache-2.0), loaded only when a session view opens; until then the dashboard bundle is unchanged. It is a verification tool, not a signal: it shows what one session did, it predicts nothing. Agents get the same bars and levels from the edge_session_bars MCP tool.
Every result carries the same envelope, in the CLI, the dashboard, the API, and over MCP:
- the point estimate with N and a Wilson 95% confidence interval
- minimum-sample guards: a warning below 30 sessions, no estimate below 10
- a first-half vs second-half stability split, and a recency view (last 250 sessions vs full history)
- per-year counts, and the value distribution for continuous outcomes
- the normalized query echoed back, with drill-down to the matching sessions
- a fixed disclaimer: historical frequencies, not predictions
There is no code path that prints a percentage without its sample size.
Session boundaries are computed in exchange time through the IANA timezone database, and DST transitions are covered by test fixtures. Holiday and half-day calendars are versioned data files with cited sources and coverage horizons checked by CI. Overnight futures sessions settle on the correct trade date, and futures roll days are flagged and excluded from gap statistics by construction. Details in docs/session-calendars.md and docs/continuous-futures.md.
Edge Stats computes on data you already have or license. Every adapter normalizes into the same local store; docs/data-sources.md documents each path.
| Adapter | Covers | Vendor cost | Env keys |
|---|---|---|---|
csv |
Anything you can export to a file | none | none |
synthetic |
Deterministic demo bars | none | none |
binance |
Binance spot crypto, full 1m history | free, keyless | none |
coinbase |
Coinbase Exchange crypto, 1m candles | free, keyless | none |
alpaca |
US equities and ETFs, 1m bars | free tier (IEX feed) | ALPACA_KEY_ID, ALPACA_SECRET_KEY |
databento |
CME futures, continuous 1m | pay as you go, with a capped preflight | DATABENTO_API_KEY |
massive |
Massive flat files from disk | covered by your existing subscription | none for flat files |
lse |
Stocks, FX, crypto, commodities, indices, ETFs, futures | free, one free key | LSE_API_KEY |
dukascopy |
FX, index CFDs, commodities, crypto | free, keyless | none |
hyperliquid |
Hyperliquid perp crypto, live tail | free, keyless | none |
The csv adapter covers anything not listed: if your source can export a file, Edge Stats can compute on it. A daily adapter-canaries workflow pulls a small sample from each vendor and fails on schema drift.
Import your own executed trades (read-only, through broker-sdk or a statement CSV) and every query can condition on your real participation:
edgestats trades import --broker kraken # or: --csv statement.csv
edgestats query "eventOccurs('TRADED_WIN') WHERE eventDay('TRADED') AND prevNr7" --symbol ESThat second line is your realized day-win rate on NR7 sessions, with its N and 95% CI, next to which the unconditioned rate is one query away. Setup base rates and your own execution finally share an envelope. Details, conventions, and the exact win/loss definition: docs/trades.md.
@luxalgo/edge-stats-mcp (stdio and streamable HTTP) exposes the engine to agents through ten read-only tools:
| Tool | Returns |
|---|---|
edge_freshness |
Configured symbols, last bar per symbol, calendar versions |
edge_fields |
The registry: every outcome, predicate, and field, with definitions |
edge_query |
Any composed P(outcome given conditions), in the full envelope |
edge_report |
A preset from the catalog, with parameters |
edge_reports_list |
The catalog, with parameter specs |
edge_sessions |
The historical sessions behind a result |
edge_session_bars |
One session's bars with the levels the engine derived for it |
edge_live |
Live Board state: forming, active, and resolved setups |
edge_trades |
Which trade tags your imported trades produced, and how to query them |
edge_export |
CSV or parquet written locally, path returned |
Typical flow: edge_freshness, then edge_fields, then edge_query, then edge_sessions for the underlying sessions, then edge_session_bars to look at the bars behind one of them. That last call reads only the session's own (symbol, timeframe, year) partition, so it costs the same on ten years of history as on ten days.
This local server exists because your store lives on your disk, where no hosted service can reach. For zero-setup access, a nightly workflow publishes a hosted derived store (session statistics only, never raw bars) that the main LuxAlgo MCP serves as hosted edge_* tools; docs/hosted-store.md documents what is published and how to consume it directly.
A preset is one JSON file: an outcome, base conditions, parameters, and definition prose with citations into the LuxAlgo Library. The generated catalog lists 42 presets across 11 categories (121 named variants), and anything the query language can express works without one. Adding a report is a pull request with one file.
Coming from a report site? docs/coming-from-edgeful.md maps the classic session-statistics reports to their preset ids.
- No order execution, ever. The optional trades import uses read-only broker access to read your own trade history; nothing here can place, modify, or cancel an order.
- No tick streaming; session statistics need bars.
- No hosted service, no telemetry, no accounts.
- No scraping of any other product's site or app. The statistics here are generic, well-known trading math, implemented independently from public definitions.
- No predictions and no advice: historical conditional frequencies with sample sizes.
pnpm install
pnpm test:run # golden sessions, calendar edge cases, DSL, stats: 233 tests
pnpm typecheck && pnpm --filter @luxalgo/edge-stats-web typecheck
pnpm lint --max-warnings 0
pnpm edgestats --dir .ci-demo init --demo && pnpm edgestats --dir .ci-demo benchARCHITECTURE.md covers the system design. CONTRIBUTING.md covers adding presets, predicates, and adapters, and the review ground rules.
Code is MIT. The calendar and event data files under data/ are additionally usable under CC BY 4.0 with attribution to LuxAlgo. The dashboard bundles the Geist fonts under the SIL OFL 1.1. See TRADEMARKS.md for name and logo use, and SECURITY.md for private vulnerability reporting.




