Skip to main content

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.

PyPI Python License Personal use

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:col error. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pineforge_codegen-0.7.3.tar.gz (412.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pineforge_codegen-0.7.3-py3-none-any.whl (205.7 kB view details)

Uploaded Python 3

File details

Details for the file pineforge_codegen-0.7.3.tar.gz.

File metadata

  • Download URL: pineforge_codegen-0.7.3.tar.gz
  • Upload date:
  • Size: 412.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pineforge_codegen-0.7.3.tar.gz
Algorithm Hash digest
SHA256 582d14be7d4adca34aac298a49ab41bbd2d1dca30a9b55cf5dbdc45a25e0d066
MD5 c16c93c1bdc6374d00d5b189f050475c
BLAKE2b-256 53b5e8521f918b13a5e49e8c343fa36b46d0e8461641b53cdc5c49a42e7b5fc1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pineforge_codegen-0.7.3.tar.gz:

Publisher: release.yml on pineforge-4pass/pineforge-codegen-oss

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pineforge_codegen-0.7.3-py3-none-any.whl.

File metadata

File hashes

Hashes for pineforge_codegen-0.7.3-py3-none-any.whl
Algorithm Hash digest
SHA256 52cf40ba3a0574a80f27ba82dfe143d6f5101e75113ebe75b33fead67cd37e5c
MD5 5def498aa7cf85d11815c0ebbcca2cd1
BLAKE2b-256 ae484a80aabf1b8d115989dff8833911723f1db6938ec1a43603653e8dd10c86

See more details on using hashes here.

Provenance

The following attestation bundles were made for pineforge_codegen-0.7.3-py3-none-any.whl:

Publisher: release.yml on pineforge-4pass/pineforge-codegen-oss

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page