{"slug": "we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible", "title": "We Transpiled PineScript v6 to C++ So Backtests Are Actually Reproducible", "summary": "A developer built PineForge, a transpiler that converts TradingView's PineScript v6 source code into C++ for offline backtesting on any OHLCV CSV data. The system achieved trade-for-trade parity with TradingView on 245 out of 246 reference strategies, validating over 375,000 trades with zero engine bugs. The single failing strategy was traced to a confirmed TradingView-side anomaly in bar-close ordering for a multi-timeframe edge case.", "body_md": "TradingView's PineScript is the most widely used language for writing trading strategies. Millions of scripts. One problem: you can't run them anywhere except TradingView.\n\nThat means:\n\nWe built PineForge to fix this. The core idea: **transpile PineScript v6 source to C++, compile it, run it offline on any OHLCV CSV.**\n\nHere's how the pipeline works and what we learned building it.\n\n```\nPineScript v6 source\n        │\n        ▼\n    Lexer / Tokenizer\n        │\n        ▼\n    Parser → AST\n        │\n        ▼\n    Semantic Analyzer\n    (type inference, series detection, scope resolution)\n        │\n        ▼\n    Codegen\n        │\n        ▼\n    C++ class (extends BacktestEngine)\n        │\n        ▼\n    g++ / clang++ → native binary\n```\n\nEach Pine script becomes a C++ class that extends our `BacktestEngine`\n\nbase. TA call-sites (`ta.sma`\n\n, `ta.rsi`\n\n, `ta.crossover`\n\n, etc.) resolve to inlined C++ implementations. Pine's `series[]`\n\ntype — which is really a lazy reverse-index into a rolling buffer — becomes a fixed-size ring buffer with bounds checking.\n\nThe trickiest part wasn't the TA functions. It was **Pine's execution model**.\n\nPine evaluates top-to-bottom on every bar, with implicit state accumulation. There's no explicit loop — the runtime loops over bars for you, and every `var`\n\n-prefixed declaration persists across bars.\n\n``` js\n//@version=6\nstrategy(\"Example\")\n\nvar float cumulative = 0.0\ncumulative += close\n\nsma20 = ta.sma(close, 20)\n\nif ta.crossover(close, sma20)\n    strategy.entry(\"Long\", strategy.long)\n```\n\nIn C++, this becomes something like:\n\n```\nclass ExampleStrategy : public BacktestEngine {\n    float cumulative = 0.0f;  // var → class member, initialized once\n\n    void onBar() override {\n        cumulative += close();  // series access via method\n\n        float sma20 = ta_sma(close_series, 20);\n\n        if (ta_crossover(close_series, sma20_series)) {\n            strategy_entry(\"Long\", Direction::LONG);\n        }\n    }\n};\n```\n\n`var`\n\ndeclarations become class members. Non-`var`\n\nlocals get re-initialized every bar. Series lookbacks (`close[1]`\n\n, `close[5]`\n\n) become ring buffer accesses with automatic history tracking.\n\nWriting a transpiler is one thing. Making it *match* TradingView trade-for-trade is another.\n\nWe built a corpus of **246 reference strategies** — everything from classic MACD crossovers to multi-timeframe trend followers with complex entry/exit logic. For each:\n\n**Current result: 245/246 strategies at strict parity. 375,000+ trades validated. Zero engine bugs.**\n\nThe one failing strategy hits a confirmed TradingView-side anomaly (their bar-close ordering in a specific multi-timeframe edge case). We've documented it; it's not our bug.\n\nGetting from \"mostly works\" to 245/246 required fixing:\n\n`strategy.close_all`\n\ntiming`calc_on_every_tick`\n\nmode`barstate.isconfirmed`\n\nsemantics`barstate.islast`\n\nin historical replay`request.security`\n\nbar alignmentTradingView's \"Bar Magnifier\" (premium feature) lets you simulate limit fills inside a bar. We implemented this with six distribution modes:\n\n| Mode | Description |\n|---|---|\n`uniform` |\nEqual probability across the bar range |\n`cosine` |\nBell-shaped, price spends more time near midpoint |\n`triangle` |\nLinear taper from open to close |\n`endpoints` |\nBimodal, price near open/close |\n`front_loaded` |\nHigher probability near open |\n`back_loaded` |\nHigher probability near close |\n\nAll modes support optional volume weighting. A limit order at $100 inside a $95–$105 bar fills at *exactly* $100 if the simulated path crosses it — no last-tick approximation.\n\nPine strategies have parameters. Finding good ones via grid search is slow. We wired in [Optuna](https://optuna.org/) with a custom objective interface:\n\n``` python\n# Any objective you want the optimizer to chase\ndef objective(trades):\n    returns = [t.pnl_pct for t in trades]\n    sharpe = mean(returns) / std(returns) * sqrt(252)\n    max_dd = compute_max_drawdown(trades)\n    return sharpe - 2.0 * max_dd  # penalize drawdown heavily\n```\n\nTPE sampler, pruning via MedianPruner, parallel trials via `n_jobs`\n\n. The optimizer calls the compiled C++ binary directly — no Python overhead on the hot path.\n\nOne Docker container. No API key. No account.\n\n```\n# Transpile Pine to C++\ndocker run --rm -v $(pwd):/workspace pineforge/engine:latest \\\n  transpile --input /workspace/my_strategy.pine --output /workspace/out/\n\n# Backtest against your OHLCV CSV\ndocker run --rm -v $(pwd):/workspace pineforge/engine:latest \\\n  backtest \\\n    --strategy /workspace/out/my_strategy \\\n    --data /workspace/BTCUSDT_1h.csv \\\n    --from 2022-01-01 --to 2024-01-01\n```\n\nOutput: JSON trade list, equity curve, summary stats. Pipe it anywhere.\n\n`.so`\n\nbinaries; buyers tune exposed inputs, never see source. AES-256-GCM encrypted, Ed25519-signed, machine-bound licenses.The engine is open-core (Apache 2.0). The codegen is on GitHub. The 246-strategy parity corpus is public.\n\nIf you've ever hit TradingView's runtime ceiling — wrong fills, irreproducible results, locked data — this is the escape hatch.\n\n*Questions about the transpiler architecture, parity methodology, or the optimizer integration? Ask in the comments.*\n\nWorth being explicit about this since it trips people up.\n\n** pineforge-engine** — Apache 2.0. The C++ runtime, the backtest engine, the ABI-stable\n\n`.so`\n\ninterface. Full open source. CI runs on Ubuntu + macOS, 93.06% line coverage, 16 ctest binaries on every commit. Free to audit, fork, deploy.** pineforge-codegen** — the Python transpiler package — is source-available under\n\nShort version: the engine is fully open. The transpiler is free for personal trading, source-available, paid for commercial use.", "url": "https://wpnews.pro/news/we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible", "canonical_source": "https://dev.to/pineforge/we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible-5chf", "published_at": "2026-06-06 17:31:31+00:00", "updated_at": "2026-06-06 18:11:58.299401+00:00", "lang": "en", "topics": ["ai-tools", "ai-products", "ai-infrastructure", "ai-research", "ai-startups"], "entities": ["TradingView", "PineScript", "PineForge", "BacktestEngine"], "alternates": {"html": "https://wpnews.pro/news/we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible", "markdown": "https://wpnews.pro/news/we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible.md", "text": "https://wpnews.pro/news/we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible.txt", "jsonld": "https://wpnews.pro/news/we-transpiled-pinescript-v6-to-c-so-backtests-are-actually-reproducible.jsonld"}}