Quant ChartsQuant Charts

Quant research without the guardrails.

A Windows desktop app for traders who want to test anything. Native Rust backtest engine, tick-level TBBO data, programmable Volume Profile, embedded Jupyter, and a local MCP server.

$29.99/monthcancel anytimev1.0.7336 commitsnative rust enginetick-level tbbo18 mcp tools1ms resolution
/surfaces

Nine surfaces, one platform. Backtest, analyze, optimize, modify trades on the fly, and drive the whole thing from an AI agent.

tick-fidelity zones, HVN/LVN tags, value-area logic
1ms
Trade-timestamp resolution. Fills are recorded in milliseconds and never snapped to bar boundaries.
7,800
Lines of Python API a hand-written strategy imports against. EMA, ATR, RSI, VWAP, the input builders, signal helpers, the @strategy and @day_start decorators.
6,600
Lines of custom Lightweight Charts primitives written on top of TradingView's library: trade brackets, indicator overlay, volume profile, trade markers.
13
Bundled strategy and indicator starters in the workspace. Plain Python and Rust files; fork them in place.
18
Tools an in-app AI agent can call to read code, query parquet, run backtests, and edit files. Works with Claude Desktop, Cursor, Zed, or any MCP host.
336
Commits and counting.
Programmable volume profile rendered as zones over candles
indicators/built-in/python/volume_profile.py with bid_dom_at_poc tagging.

Volume profile, completely yours

VP here is not a configured component. It is a class with the @indicatordecorator on top, and you get the tick stream, the price ladder, and the chart canvas as primitives. You own the session anchor, the value-area math, the node classification, the zone tags, the per-side bid/ask split, and the regime-conditional bucketing. Render shelves at HVN and LVN, draw a footprint ladder with delta cells, lay down a TPO letter strip, build a market-profile composite split by regime, stack profiles per session and diff them. The chart primitives the platform's own indicators use (canvas drawing, coordinate-aware overlays, multi-pane price scales) are the same ones you have access to.

Bundled starters cover the common cases: a parameterized session VP, a VP-plus-order-flow tagger that emits zone-conditioned signals like bid_dom_at_poc and ask_dom_at_hvn, and Rust zone-trading strategies (vp_zone, vp_shelf, vp_orderflow). Once you fork one, the platform stays out of the way of whatever you replace it with.

Native Rust backtest engine

The engine is a Rust NAPI module. Tick-by-tick on TBBO data, bar-by-bar on OHLC at any timeframe. Single-day backtests run in milliseconds; multi-day sweeps in seconds. Trade timestamps stay in milliseconds end-to-end and never snap to a bar boundary; slippage applies at the tick. Trading-day windows are computed in Eastern Time, so a Monday futures session starts Sunday 6pm ET.

Walk-forward analysis with anchored or rolling windows. Optimization sweeps with 3D heatmap drill-through. MAE/MFE scatter plots with selection brushing. Walk-forward, optimizer, and tag filters all reuse the same engine path, so an in-sample fill and an out-of-sample fill go through identical microstructure.

TBBO bid and ask stepped lines
TBBO replay: red ask line, green bid line, live bid/ask price tags on the right axis.
Trade bracket primitive rendering fills at the actual fill price
TradeBracketPrimitive renders fills at the actual fill price, not the bar close.

Hand-written, on purpose

A strategy is a Python class with init and on_bar or on_tick. Import what you need from quant_charts: the TA primitives (ema, atr, rsi, macd, bb, vwap), the input builders, the signal helpers (cross_above, between, above, below), and the @strategy and @day_start decorators. NumPy, pandas, scikit-learn, polars. Anything you have installed is in scope. There is no DSL between you and the engine.

On top of TradingView Lightweight Charts sit 6,600 lines of custom primitives that the standard library does not give you: TradeBracketPrimitive for entry and exit markers at fill-price coordinates, IndicatorOverlayPrimitive with point decimation that collapses pixel collisions at zoom, VolumeProfilePrimitive, and a coordinate converter that runs binary search over deduped bid+ask timestamps so a tick renders at the right X without going through LWC's bar-aggregation path.

Tag filters route through the engine

When you flip a tag dropdown after a run, the engine re-runs from scratch with a trading mask built from your pre-computed tag arrays. The single-position-at-a-time constraint, the SL/TP cascade, and the order-of-fills carry through the filter the same way they did on the original run.

Tags are anything you compute. A regime label from a classifier, an order-flow dominance flag, a time-of-day bucket, the output of an external model. Compute them once during the strategy run; the engine keeps the arrays around. After the run, combine tags freely to ask which regime your strategy actually works in, without re-executing your strategy code.

# Flip a tag dropdown after the run, the engine re-runs with a
# trading mask built from your pre-computed tag arrays. The
# single-position-at-a-time constraint carries through the filter.
mask = (trades.tags["bid_dom_at_poc"]
        & trades.tags["regime_low_vol"]
        & ~trades.tags["news_window"])

filtered = analyzer.rerun(mask)
filtered.equity_curve.plot()
filtered.mae_mfe.scatter(brush=True)

notebooks/built-in/getting_started.ipynb, abridged.

What ships in the box

Four surfaces sit alongside the chart, all included at the same price. They share the same workspace, the same Python kernel, and the same data layer.

Optimizer

Cross-product parameter sweeps render as a 3D heatmap. Click any cell to drill through to that run's full equity curve and trade list.

Optimizer

Analyzer

Walk-forward analysis with anchored or rolling splits. MAE/MFE scatter with selection brushing. Tag-filter the trade set and the engine re-runs cascade-correct.

Analyzer

AI agents

Claude Opus 4.7 and Gemini 2.5 Pro run inside the app with read-write workspace access. Every diff lands as a Monaco preview before write. Paste an Anthropic or Google key in settings.

AI agents

MCP server

Claude Desktop, Cursor, Zed, or any MCP host drives Quant Charts directly. 18 tools to read code, query parquet, run backtests, and edit notebooks; 3 resources expose the workspace and the last backtest summary.

MCP server

Strategies are Python files

A strategy is a Python class with init and on_bar / on_tick. For TBBO performance work, it can be a Rust file instead. Indicators expose overlay and subpane primitives you draw into directly. Use NumPy, pandas, scikit-learn, or any other Python package you have installed.

Today the strategy contract is single-asset, single-stream, single-session. Multi-day, multi-stream, arbitrage, cross-asset, and live execution are on the roadmap.

from quant_charts import strategy, day_start, input, ta, cross_above, cross_below, Timeframe
import numpy as np

@strategy(name="Optimize", overlay=True, timeframe=Timeframe.M1, data_mode="ohlc",
          required_columns=["high", "low", "close"], uses_sltp=False)
class Optimize:
    fast_ema = input.int(9, "Fast EMA", min=2, max=10000)
    slow_ema = input.int(21, "Slow EMA", min=2, max=10000)
    regime_atr_mult = input.float(1.5, "Regime ATR Mult", min=0.0, max=100.0, step=0.1)

    @day_start
    def prep(self, df):
        close = np.asarray(df["close"], dtype=np.float64)
        atr14 = ta.atr(df["high"], df["low"], df["close"], 14)
        median_atr = float(np.median(atr14[np.isfinite(atr14)]))
        return {"close": close, "atr14": atr14, "median_atr": median_atr}

    def calculate(self, df):
        close = self._day["close"]
        in_regime = self._day["atr14"] > self._day["median_atr"] * self.regime_atr_mult
        fast = ta.ema(close, self.fast_ema)
        slow = ta.ema(close, self.slow_ema)
        return {
            "entry_long":  cross_above(fast, slow) & in_regime,
            "exit_long":   cross_below(fast, slow),
            "entry_short": cross_below(fast, slow) & in_regime,
            "exit_short":  cross_above(fast, slow),
        }

templates/workspace/strategies/built-in/python/optimize.py, abridged.

Bundled starters

Every workspace ships with a set of reference files, copied into your local workspaces/default/ on first launch. Open one, hit run, then fork it and edit in place.

EMA cross with ATR regime
strategies/built-in/python/optimize.py

EMA cross with ATR regime

Canonical day-start hoisting reference. Two EMA periods plus a regime threshold, swept across hundreds of combos per day.

Volume-profile zone trading
strategies/built-in/rust/vp_zone.rs

Volume-profile zone trading

Tick-fidelity Rust strategy. Trades against POC, HVN, and LVN zones using the order-flow tagger.

Programmable volume profile
indicators/built-in/python/volume_profile.py

Programmable volume profile

Session VP with custom value-area math. Emits zone tags like bid_dom_at_poc and ask_dom_at_hvn for post-hoc filtering.

Jupyter, in the workspace
notebooks/built-in/getting_started.ipynb

Jupyter, in the workspace

Real Python kernel, not a sandbox. Pull the latest backtest result as a DataFrame; plot inline with matplotlib or plotly.

Get Quant Charts

$29.99 a month. Windows desktop. Cancel anytime. Lemon Squeezy, LLC handles the transaction; the app talks to your local disk for everything else. Create an account, or read the pricing details.