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.

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.
Nine surfaces, one platform. Backtest, analyze, optimize, modify trades on the fly, and drive the whole thing from an AI agent.

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.
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.


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.
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.
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.
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.

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.

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.

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.

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.
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.

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

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

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

Real Python kernel, not a sandbox. Pull the latest backtest result as a DataFrame; plot inline with matplotlib or plotly.
$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.