Skip to content

Pine Script backtest run locally: 48 identical trades

Side, times, prices and net P&L match TradingView’s export, row for row.

4,2004,4004,6004,800
Aug 22Aug 23
USDT

Tap or drag the chart to read any point.

Source: probe composite-vcp-fvg-active-zones-01, pineforge-corpus d75b4fa, 2025-03-31 to 2026-05-01: CSV files, gallery page.

The chart as a table

48 consecutive trades of the same strategy on the 178 Binance ETHUSDT perpetual 15-minute candles around them. TradingView’s export and PineForge’s trade book agree on side, entry and exit time, entry and exit price and net P&L, row for row.

TradeSideEntry, TradingViewEntry, PineForgeExit, TradingViewExit, PineForgeNet P&L, TradingViewNet P&L, PineForge
4,100long4,306.954,306.954,296.644,296.64−10.31−10.31
4,106long4,279.174,279.174,276.804,276.80−2.37−2.37
4,112long4,327.734,327.734,315.744,315.74−11.99−11.99
4,118long4,272.714,272.714,242.194,242.19−30.52−30.52
4,124long4,779.504,779.504,760.734,760.73−18.77−18.77
4,129long4,749.874,749.874,738.934,738.93−10.94−10.94
4,135long4,718.894,718.894,731.004,731.0012.1112.11
4,141long4,723.344,723.344,718.714,718.71−4.63−4.63
4,147long4,752.764,752.764,745.124,745.12−7.64−7.64
How this is measured

Probe composite-vcp-fvg-active-zones-01 in pineforge-corpus at commit d75b4fa: Binance ETHUSDT perpetual, 15-minute bars, 2025-03-31 to 2026-05-01. PineForge’s trade list there was written on 2026-10-02 by engine v1.0.1. See the CSV files or open it in the gallery.

PineForge backtests Pine Script outside TradingView, offline in one Docker image, with repeatable trades.

Why offline?

Browser-based backtesting is great for chart-side iteration. Offline backtesting is what you reach for when the next step is shipping money behind the strategy: when you need an audit trail, when CI has to gate every commit, when a result from two months ago has to reproduce today, trade for trade.

Running backtests offline gives you the things browser-based testers can’t: results are deterministic: the same script, data and image version give the same trades. You pin the image version, check reports into a repository, diff trade lists between commits and run it all headless in CI. The CSV you feed in is yours, the engine runs locally, and the report records a fingerprint of what produced it.

The practical list: pinned image versions, so a commit from two months ago gives the same trade list today; your own data, from exchange candles to a vendor’s point-in-time prices, as long as it is OHLCV; CI checks that fail the build on a regression; and a strategy that is a file, not tied to one platform.

If you’ve ever needed to share a backtest result with a colleague and realized the only way to “share” it was to screenshot a chart, offline running is what you’re missing.

How to backtest Pine Script offline

PineForge transpiles PineScript v6 to native C++ and runs it on your machine in one Docker image.

Three steps. The image is pulled once; after that, everything runs offline.

Step 1: Pull the runtime

One image, ghcr.io/pineforge-4pass/pineforge-release. No pip, no key, no signup: transpile, compile and backtest all run inside it, offline. The engine inside is Apache-2.0; the bundled transpiler is free for personal trading.

Step 2: Transpile your Pine to C++

Run the image in transpile-only mode and it turns your PineScript v6 into a complete C++ source file, locally. No Pine interpreter runs at backtest time: the image compiles the C++ to native code.

docker run --rm --network=none \
  -e PINEFORGE_TRANSPILE_ONLY=1 \
  -v "$(pwd)/my_strategy.pine":/in/strategy.pine:ro \
  ghcr.io/pineforge-4pass/pineforge-release:1.4.0 > strategy.cpp

Step 3: Backtest

Mount your OHLCV CSV next to the generated C++ and run the image. The CSV needs the header timestamp,open,high,low,close,volume, with timestamps in UNIX milliseconds. The engine executes the strategy bar by bar and writes a JSON report to stdout. You can also skip step 2: mount strategy.pine instead and the image transpiles it first.

docker run --rm --network=none \
  -v "$(pwd)/strategy.cpp":/in/strategy.cpp:ro \
  -v "$(pwd)/ohlcv.csv":/in/ohlcv.csv:ro \
  ghcr.io/pineforge-4pass/pineforge-release:1.4.0 > report.json

The JSON report has a summary block (total trades, wins and losses, win rate, net P&L, max drawdown), the full trade list (entry and exit times, prices, quantity, P&L and bar indices), metrics such as profit factor, Sharpe and Sortino, the equity curve, and a fingerprint of the engine, transpiler, inputs and data behind the run (null if it could not be computed).

That’s the entire workflow. No GUI, no account re-authentication, no chart loading. If you can run Docker, you can run PineForge offline backtests.

What you can backtest

The short answer: anything you can serialize as OHLCV. PineForge is not connected to any market data provider. You bring the data; the engine runs the strategy.

  • Crypto from your exchange. Pull raw trade data from Binance, Bybit, Kraken, or any exchange with a REST or WebSocket API. Aggregate to whatever timeframe your strategy uses. Feed the CSV directly. Test on the exact pair-and-venue combination you’ll trade.
  • Equities from your data vendor. Polygon, Norgate, Barchart, Tiingo: pick your source, export point-in-time adjusted prices, and backtest on your own survivorship-bias-free universe.
  • Bars built from ticks. If you build bars from tick or order-book data, pass them in as OHLCV. The engine does not care where the bars came from.
  • Other series. The engine reads only timestamp, open, high, low, close and volume; extra columns are ignored. A sentiment score or an on-chain metric can be backtested only if you encode it in those columns.

The 312 strategies in the gallery come from the open corpus, each graded against TradingView’s own export. On engine main, the corpus check pins 311 of them at excellent: the same trade count, prices within 0.01 % and P&L within 1 % at the 90th percentile, with looser exit-price and P&L limits for the 7 strategies whose trail_* exits are graded with the production profile. The remaining one is a declared anomaly. For excellent, where TradingView shows two or more distinct entry Signals at one exact time, price and direction, the engine shows as many distinct entries there (distinct-entry identity).

Next steps