PineScript v6 to C++ transpiler that targets the pineforge-engine runtime.
Project description
pineforge-codegen
PineScript v6 → C++ transpiler that emits against the pineforge-engine runtime.
A pure-Python library that turns a PineScript v6 strategy into a complete C++
source file you can compile against the pineforge-engine
runtime — a deterministic native backtester validated trade-for-trade against
TradingView (231/232 corpus parity).
It is source-available and free for personal trading — research, backtest, and trade your own account with your own capital at no cost. See License for the line between personal and commercial use.
- Pure Python, zero runtime dependencies — one function,
transpile(). - Fails loud, never silent — a support checker rejects Pine the engine can't
faithfully run before codegen, with a
file:line:colerror. You never get silently-wrong C++. - First complete PineScript v6 → C++ transpiler with a real support checker (to our knowledge).
Install
pip install pineforge-codegen
Requires Python ≥ 3.11. No runtime dependencies.
From source (development / contributing):
git clone https://github.com/pineforge-4pass/pineforge-codegen-oss.git
cd pineforge-codegen-oss
pip install -e ".[dev]"
Quick start
from pineforge_codegen import transpile
pine = """
//@version=6
strategy("SMA cross", overlay=true)
fast = ta.sma(close, 10)
slow = ta.sma(close, 30)
if ta.crossover(fast, slow)
strategy.entry("long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("long")
"""
cpp = transpile(pine)
print(cpp) # complete C++ source string
The output #includes <pineforge/engine.hpp>, <pineforge/ta.hpp>, … and
compiles into a .so exposing the engine's documented C-ABI.
Usage
The transpile() function
transpile(
pine_source: str,
*,
check_support: bool = True, # run the support checker before codegen
filename: str = "<input>", # name used in error locations
) -> str
Returns the generated C++ source as a string. Raises
pineforge_codegen.errors.CompileError on any unsupported construct or syntax
error.
Transpile a file to a .cpp
from pathlib import Path
from pineforge_codegen import transpile
pine = Path("strategy.pine")
cpp = transpile(pine.read_text(), filename=pine.name) # filename → better errors
Path("strategy.generated.cpp").write_text(cpp)
Handle unsupported features
The support checker raises a CompileError with the exact source location
instead of emitting broken C++:
from pineforge_codegen import transpile
from pineforge_codegen.errors import CompileError
try:
transpile('//@version=6\nindicator("x")\n')
except CompileError as e:
print(e)
# <input>:2:1: indicator() declarations are not supported; PineForge runs strategies only.
try:
transpile('//@version=6\nstrategy("x")\n'
'x = request.financial("AAPL", "REV", "FQ")\n')
except CompileError as e:
print(e)
# <input>:3:22: request.financial(...) is not supported.
Pass filename= so the location points back at the user's file:
transpile(src, filename="my_strategy.pine")
# raises e.g. my_strategy.pine:12:5: ...
Skip the support checker
check_support=False bypasses the gate (intended only for tests of legacy
fixtures — it can produce C++ the engine won't accept):
cpp = transpile(src, check_support=False)
Trace intermediate expressions (@pf-trace)
A // @pf-trace name=expr comment makes the engine emit name's per-bar value
in the backtest report — useful for debugging parity against TradingView:
pine = """
//@version=6
strategy("traced")
// @pf-trace rsi=ta.rsi(close, 14)
e = ta.ema(close, 20)
if close > e
strategy.entry("L", strategy.long)
"""
cpp = transpile(pine) # emitted on_bar tail records `rsi` each bar
Advanced: run the pipeline stages directly
transpile() is a thin wrapper over five passes. Drive them yourself to inspect
tokens, the AST, or the analyzer context:
from pineforge_codegen import (
Lexer, Parser, Analyzer, CodeGen,
extract_pf_trace_pragmas, check_support_or_raise,
)
src = open("strategy.pine").read()
pragmas = extract_pf_trace_pragmas(src)
tokens = Lexer(src, filename="strategy.pine").tokenize()
ast = Parser(tokens, source=src, filename="strategy.pine").parse()
check_support_or_raise(ast, filename="strategy.pine")
ctx = Analyzer(ast, filename="strategy.pine").analyze()
ctx.pf_trace_pragmas = pragmas
cpp = CodeGen(ctx).generate()
How it works
transpile() runs five passes, in order:
pine source
│
├─ 1. extract_pf_trace_pragmas // @pf-trace comments pulled out first
├─ 2. Lexer → Parser token stream → Pine v6 AST
├─ 3. support_checker reject anything the engine can't run faithfully
├─ 4. Analyzer type inference, scope resolution, TA bookkeeping
└─ 5. CodeGen → C++ source string
Compile & run against the engine
The emitted C++ targets the C-ABI in <pineforge/pineforge.h>. To build and run
a strategy:
# Get the runtime (Apache-2.0) next to this repo
git clone https://github.com/pineforge-4pass/pineforge-engine.git
Follow the engine's tutorial/
to build libpineforge.a, compile your transpiled .cpp into a strategy .so,
feed it OHLCV, and read back the closed-trade list. The codegen version must
target a matching engine ABI (see VERSION).
Prefer no local build? A hosted transpile API + MCP server is available so AI agents can transpile and backtest for you — see https://www.pineforge.dev.
Running tests
pip install -e ".[dev]"
pytest
The pure-transpiler suite is fast (< 1 s) and has no native dependencies — it checks token streams, parse trees, analyzer output, and canonical C++ strings without invoking a C++ compiler.
Opt-in compile checks (tests/test_compile_smoke.py, tests/test_compile_corpus.py)
run g++ -fsyntax-only on transpiled C++ against the engine headers. They
auto-detect a sibling ../pineforge-engine checkout, or set the path explicitly:
export PINEFORGE_ENGINE_INCLUDE=/path/to/pineforge-engine/include
pytest
Without an engine checkout these tests skip cleanly, so CI stays green.
License
Source-available under the PolyForm Noncommercial License 1.0.0, with
two supplemental terms (the LICENSE file is the controlling text):
- Personal Trading exception — free to research, backtest, and trade for your own account with your own capital.
- Commercial use — companies, funds, managing third-party capital, embedding in a product, or operating a hosted / public-facing service requires a commercial license.
Competing hosted services are not permitted under the noncommercial terms. This is source-available, not OSI open source.
Buying a commercial license
Commercial licenses are available — flexible terms for funds, products, and hosted/embedded use. Email luis@4pass.com.tw with your use case for a quote.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pineforge_codegen-0.6.5.tar.gz.
File metadata
- Download URL: pineforge_codegen-0.6.5.tar.gz
- Upload date:
- Size: 255.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5a5015c45d9e961258ff688286cbd41466abf5398dc24c6a69d16f11be2db30
|
|
| MD5 |
8b4ad036a0b03eb2572420be6f094b53
|
|
| BLAKE2b-256 |
5bc19c68a552d79e8ffa71e65b2a3fcda1befcd474f7c648999c59455c084abb
|
Provenance
The following attestation bundles were made for pineforge_codegen-0.6.5.tar.gz:
Publisher:
release.yml on pineforge-4pass/pineforge-codegen-oss
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pineforge_codegen-0.6.5.tar.gz -
Subject digest:
d5a5015c45d9e961258ff688286cbd41466abf5398dc24c6a69d16f11be2db30 - Sigstore transparency entry: 1710782997
- Sigstore integration time:
-
Permalink:
pineforge-4pass/pineforge-codegen-oss@646d0ee72524b4be7c355cf3b3e35dbf4e67047b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pineforge-4pass
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@646d0ee72524b4be7c355cf3b3e35dbf4e67047b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file pineforge_codegen-0.6.5-py3-none-any.whl.
File metadata
- Download URL: pineforge_codegen-0.6.5-py3-none-any.whl
- Upload date:
- Size: 197.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d349d159140397bbc512f42426f92a0e247130d76bafc1fa7293f5b0eee370c
|
|
| MD5 |
eead81ebaa8e4f5acaf36aee25f120c8
|
|
| BLAKE2b-256 |
4a1eef57a1d553622583991c7d2b5a3062a4281db2c2b0e9bab11acaf4606a07
|
Provenance
The following attestation bundles were made for pineforge_codegen-0.6.5-py3-none-any.whl:
Publisher:
release.yml on pineforge-4pass/pineforge-codegen-oss
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pineforge_codegen-0.6.5-py3-none-any.whl -
Subject digest:
2d349d159140397bbc512f42426f92a0e247130d76bafc1fa7293f5b0eee370c - Sigstore transparency entry: 1710783027
- Sigstore integration time:
-
Permalink:
pineforge-4pass/pineforge-codegen-oss@646d0ee72524b4be7c355cf3b3e35dbf4e67047b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pineforge-4pass
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@646d0ee72524b4be7c355cf3b3e35dbf4e67047b -
Trigger Event:
workflow_dispatch
-
Statement type: