Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ This is the **source-available** half of the PineForge stack (PineForge
Source License 1.1 — see `LICENSE`). The runtime half (`pineforge-engine`,
Apache-2.0) lives in a sibling repo and is typically checked out at
`../pineforge-engine`. From 1.0.0 on, a released codegen `X.Y.Z` pairs only
with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.1.0 pairs with
engine `v1.1.0` (the `pineforge-release` image `1.1.0`), codegen 1.0.1 with
engine `v1.0.1` (the image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0`
(the image `1.0.0`). On the 0.x line the versions are independent: the last
0.x release, codegen 0.10.4, pairs with engine `v0.13.1` (the
`pineforge-release` image `0.1.25`). Use the paired release's generated
headers and static library, and regenerate C++ and relink on every pair
change. Equal `PF_ABI_VERSION` values are insufficient. Engines `v1.0.0`,
`v1.0.1` and `v1.1.0` use the `engine_script_run_v19` C++ namespace; see
`README.md` and `CONTRIBUTING.md`.
with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.2.0 pairs with
engine `v1.2.0` (the `pineforge-release` image `1.2.0`), codegen 1.1.0 with
engine `v1.1.0` (the image `1.1.0`), codegen 1.0.1 with engine `v1.0.1` (the
image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0` (the image `1.0.0`). On
the 0.x line the versions are independent: the last 0.x release, codegen
0.10.4, pairs with engine `v0.13.1` (the `pineforge-release` image `0.1.25`).
Use the paired release's generated headers and static library, and regenerate
C++ and relink on every pair change. Equal `PF_ABI_VERSION` values are
insufficient. Engines `v1.0.0`, `v1.0.1`, `v1.1.0` and `v1.2.0` use the
`engine_script_run_v19` C++ namespace; see `README.md` and `CONTRIBUTING.md`.

## Pipeline

Expand Down
283 changes: 238 additions & 45 deletions CHANGELOG.md

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ This is the **source-available** half of the PineForge stack (PineForge
Source License 1.1 — see `LICENSE`). The runtime half (`pineforge-engine`,
Apache-2.0) lives in a sibling repo and is typically checked out at
`../pineforge-engine`. From 1.0.0 on, a released codegen `X.Y.Z` pairs only
with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.1.0 pairs with
engine `v1.1.0` (the `pineforge-release` image `1.1.0`), codegen 1.0.1 with
engine `v1.0.1` (the image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0`
(the image `1.0.0`). On the 0.x line the versions are independent: the last
0.x release, codegen 0.10.4, pairs with engine `v0.13.1` (the
`pineforge-release` image `0.1.25`). Use the paired release's generated
headers and static library, and regenerate C++ and relink on every pair
change. Equal `PF_ABI_VERSION` values are insufficient. Engines `v1.0.0`,
`v1.0.1` and `v1.1.0` use the `engine_script_run_v19` C++ namespace; see
`README.md` and `CONTRIBUTING.md`.
with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.2.0 pairs with
engine `v1.2.0` (the `pineforge-release` image `1.2.0`), codegen 1.1.0 with
engine `v1.1.0` (the image `1.1.0`), codegen 1.0.1 with engine `v1.0.1` (the
image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0` (the image `1.0.0`). On
the 0.x line the versions are independent: the last 0.x release, codegen
0.10.4, pairs with engine `v0.13.1` (the `pineforge-release` image `0.1.25`).
Use the paired release's generated headers and static library, and regenerate
C++ and relink on every pair change. Equal `PF_ABI_VERSION` values are
insufficient. Engines `v1.0.0`, `v1.0.1`, `v1.1.0` and `v1.2.0` use the
`engine_script_run_v19` C++ namespace; see `README.md` and `CONTRIBUTING.md`.

## Pipeline

Expand Down
11 changes: 6 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ before treating a run as complete.

## Engine pairing

Codegen `main` is developed and tested against engine `main`. Codegen 1.1.0
pairs with engine `v1.1.0`, the pair the
Codegen `main` is developed and tested against engine `main`. Codegen 1.2.0
pairs with engine `v1.2.0`, the pair the
[`pineforge-release`](https://github.com/pineforge-4pass/pineforge-release)
image `1.1.0` ships, codegen 1.0.1 with engine `v1.0.1`, the pair of the image
`1.0.1`, and codegen 1.0.0 with engine `v1.0.0`, the pair of the image
`1.0.0`. On the 0.x line the two version lineages are independent:
image `1.2.0` ships, codegen 1.1.0 with engine `v1.1.0`, the pair of the image
`1.1.0`, codegen 1.0.1 with engine `v1.0.1`, the pair of the image `1.0.1`,
and codegen 1.0.0 with engine `v1.0.0`, the pair of the image `1.0.0`. On the
0.x line the two version lineages are independent:
the last 0.x release, codegen 0.10.4, pairs with engine `v0.13.1`, the pair
the `pineforge-release` image `0.1.25` ships.

Expand Down
37 changes: 19 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@

[![PyPI](https://img.shields.io/pypi/v/pineforge-codegen.svg)](https://pypi.org/project/pineforge-codegen/)
[![Python](https://img.shields.io/pypi/pyversions/pineforge-codegen.svg)](https://pypi.org/project/pineforge-codegen/)
[![License](https://img.shields.io/badge/license-PineForge%20Source%201.0-orange.svg)](https://github.com/pineforge-4pass/pineforge-codegen-oss/blob/main/LICENSE)
[![License](https://img.shields.io/badge/license-PineForge%20Source%201.1-orange.svg)](https://github.com/pineforge-4pass/pineforge-codegen-oss/blob/main/LICENSE)
[![Personal use](https://img.shields.io/badge/personal%20trading-free-22c55e.svg)](#license)

A pure-Python library that turns a PineScript v6 strategy into a complete C++
source file you can compile against the [`pineforge-engine`](https://github.com/pineforge-4pass/pineforge-engine)
runtime.

**Measured <!-- pf:scoreboard.date -->2026-10-04<!-- /pf -->** on main engine <!-- pf:scoreboard.engineCommit|short-code -->`6b77f061`<!-- /pf --> with codegen-oss <!-- pf:scoreboard.codegenCommit|short-code -->`285ac035`<!-- /pf --> (baseline <!-- pf:scoreboard.id|code -->`pineforge-parity-baseline-20261004-engine-6b77f061`<!-- /pf -->, snapshot <!-- pf:scoreboard.snapshotSha256|short-code -->`21639bad`<!-- /pf -->): <!-- pf:scoreboard.excellent|int -->7,970<!-- /pf --> of <!-- pf:scoreboard.graded|int -->7,989<!-- /pf --> TradingView probes
**Measured <!-- pf:scoreboard.date -->2026-10-05<!-- /pf -->** on main engine <!-- pf:scoreboard.engineCommit|short-code -->`52292db9`<!-- /pf --> with codegen-oss <!-- pf:scoreboard.codegenCommit|short-code -->`48e7a13b`<!-- /pf --> (baseline <!-- pf:scoreboard.id|code -->`pineforge-parity-baseline-20261005-engine-52292db9`<!-- /pf -->, snapshot <!-- pf:scoreboard.snapshotSha256|short-code -->`7161ebdc`<!-- /pf -->): <!-- pf:scoreboard.excellent|int -->7,970<!-- /pf --> of <!-- pf:scoreboard.graded|int -->7,989<!-- /pf --> TradingView probes
graded excellent and <!-- pf:scoreboard.strong|int -->19<!-- /pf --> strong, with <!-- pf:scoreboard.belowStrong|int -->0<!-- /pf --> below strong; <!-- pf:scoreboard.anomaliesExcluded|int -->17<!-- /pf --> more probes are held out as TradingView-side anomalies.
A probe is a strategy exported from TradingView with its trade list and replayed
trade for trade on the same bars.

Release **1.1.0 grades <!-- pf:releases[1.1.0].scoreboard.excellent|int -->7,951<!-- /pf --> excellent / <!-- pf:releases[1.1.0].scoreboard.strong|int -->38<!-- /pf --> strong until the next release**, on <!-- pf:releases[1.1.0].scoreboard.graded|int -->7,989<!-- /pf --> probes (baseline <!-- pf:releases[1.1.0].scoreboard.id|code -->`pineforge-parity-baseline-20261004-engine-7b596622`<!-- /pf -->, <!-- pf:releases[1.1.0].scoreboard.date -->2026-10-04<!-- /pf -->). A main scoreboard advance does not change release results.
Release **1.2.0 grades <!-- pf:releases[1.2.0].scoreboard.excellent|int -->7,970<!-- /pf --> excellent / <!-- pf:releases[1.2.0].scoreboard.strong|int -->19<!-- /pf --> strong until the next release**, on <!-- pf:releases[1.2.0].scoreboard.graded|int -->7,989<!-- /pf --> probes (baseline <!-- pf:releases[1.2.0].scoreboard.id|code -->`pineforge-parity-baseline-20261005-engine-52292db9`<!-- /pf -->, <!-- pf:releases[1.2.0].scoreboard.date -->2026-10-05<!-- /pf -->). A main scoreboard advance does not change release results.

The quantities above render from the public [facts tokens](https://github.com/pineforge-4pass/pineforge-release/blob/main/facts/facts.json). Maintain them with `lab facts render --repo . --facts <local facts file or pinned raw URL>`; `lab facts check` with the same inputs reports drift. Grades are registry-derived; the authored-script and closed-trade inventory is explicitly sourced to a historical public README for the identical population, not to registry row or slug totals.

Expand All @@ -40,7 +40,7 @@ for the changes in each release from 1.0.0 on and the release-note policy.
## Releases and this README

<!-- Release lane: before a release is tagged, add it to the Engine pairing
table and update every line that names `1.1.0` or `v1.1.0` as the current
table and update every line that names `1.2.0` or `v1.2.0` as the current
release or pair (this section's version and date, the baseline paragraph at
the top, the engine `src/source/` link, the `@pf-trace` note, the clone
command and its example output, "This section describes …", the timing note)
Expand All @@ -50,7 +50,7 @@ hosted-server line name no version. -->

This README ships with each release as its package description on PyPI
(`pineforge-codegen`); releases from 0.7.0 on are also on npm as
`@pineforge/codegen-pyodide`. It describes 1.1.0 (2026-10-04) and what changed
`@pineforge/codegen-pyodide`. It describes 1.2.0 (2026-10-05) and what changed
since 0.10.4. The
[PyPI release history](https://pypi.org/project/pineforge-codegen/#history)
lists every release; the
Expand Down Expand Up @@ -90,8 +90,8 @@ It does **not** own execution semantics. Order lifecycle, bracket legs,
fill-price and slippage rules, `process_orders_on_close` / `calc_on_order_fills`,
margin revival and trail/stop behaviour — everything TradingView parity depends
on at run time — live in the engine's source-adapter runtime
([`src/source/`](https://github.com/pineforge-4pass/pineforge-engine/tree/v1.1.0/src/source)
in engine `v1.1.0`), which maps them onto the engine's Pine-agnostic kernel. See
([`src/source/`](https://github.com/pineforge-4pass/pineforge-engine/tree/v1.2.0/src/source)
in engine `v1.2.0`), which maps them onto the engine's Pine-agnostic kernel. See
the engine's [architecture notes](https://github.com/pineforge-4pass/pineforge-engine#architecture-kernel-vs-parity).

---
Expand Down Expand Up @@ -344,7 +344,7 @@ fields, such as `// @pf-trace gap=close - e` or
`// @pf-trace body=math.abs(close - open)`. A `ta.*` call written in the
pragma itself is not computed: `// @pf-trace rsi=ta.rsi(close, 14)` records
`na` on every bar, and its C++ carries an `/* unsupported: ta.rsi */` marker.
0.10.4, 1.0.0, 1.0.1 and 1.1.0 all behave this way.
0.10.4, 1.0.0, 1.0.1, 1.1.0 and 1.2.0 all behave this way.

### Advanced: run the pipeline stages directly

Expand Down Expand Up @@ -389,9 +389,9 @@ does not bypass them.

The last column was measured on 2026-09-29 with 70c2b4a (the same code as
1.0.0) on CPython 3.14 on an Apple M4 Max, over the engine corpus that engine
35db01c8 pins (as `v1.0.0`, `v1.0.1` and `v1.1.0` do) and this repository's
`tests/gate-corpus`. On 2026-10-04, on CPython 3.14 on an Apple M4 Max, 1.1.0
transpiled each of those sources in under 0.1 seconds.
35db01c8 pins (as `v1.0.0`, `v1.0.1`, `v1.1.0` and `v1.2.0` do) and this
repository's `tests/gate-corpus`. On 2026-10-05, on CPython 3.14 on an Apple
M4 Max, 1.2.0 transpiled each of those sources in under 0.1 seconds.

Nesting counts brackets, indented blocks, prefix operators, `?:` and
`else if` chains, and the depth of the parsed syntax tree, in which an
Expand Down Expand Up @@ -441,6 +441,7 @@ Generated C++ compiles only against the engine it was generated for:
| 1.0.0 (PyPI, 2026-09-30) | `v1.0.0` | The pair the `pineforge-release` image `1.0.0` ships. Its C++ needs `pineforge/source/pine_strategy_host.hpp`, which engine `v0.13.1` does not have. |
| 1.0.1 (PyPI, 2026-10-02) | `v1.0.1` | The pair the `pineforge-release` image `1.0.1` ships. Engine `v1.0.1` changes only documentation since `v1.0.0`; regenerate and relink all the same. |
| 1.1.0 (PyPI, 2026-10-04) | `v1.1.0` | The pair the `pineforge-release` image `1.1.0` ships. Its C++ defines the checked settings functions that engine `v1.1.0` adds to `<pineforge/pineforge.h>`; regenerate and relink. |
| 1.2.0 (PyPI, 2026-10-05) | `v1.2.0` | The pair the `pineforge-release` image `1.2.0` ships. Its C++ defines the compiled execution capability functions that engine `v1.2.0` adds to `<pineforge/pineforge.h>`; regenerate and relink. |
| Later `X.Y.Z` releases | `vX.Y.Z` of the same version | See below. |

On the 0.x line the engine and codegen versions are independent, and the
Expand All @@ -466,8 +467,8 @@ Pine as `strategy.pine`, write `strategy.generated.cpp` with the
[file example](#transpile-a-file-to-a-cpp) above, then from the same directory:

```bash
# 1.1.0 pairs with engine v1.1.0. For 0.10.4 use --branch v0.13.1.
git clone --branch v1.1.0 https://github.com/pineforge-4pass/pineforge-engine.git
# 1.2.0 pairs with engine v1.2.0. For 0.10.4 use --branch v0.13.1.
git clone --branch v1.2.0 https://github.com/pineforge-4pass/pineforge-engine.git
cd pineforge-engine
cp ../strategy.generated.cpp tutorial/macd/generated.cpp # the tutorial's strategy slot
bash tutorial/run.sh # needs cmake, a C++17 compiler and python3
Expand All @@ -476,7 +477,7 @@ bash tutorial/run.sh # needs cmake, a C++17 compiler and python3
`run.sh` configures CMake once, builds `libpineforge.a` and
`tutorial/macd/strategy.so`, and runs `tutorial/run.py`, which loads the `.so`,
feeds it the bars and reads back the closed trades. For the quick-start SMA
cross, 1.1.0 with engine `v1.1.0` prints:
cross, 1.2.0 with engine `v1.2.0` prints:

```
MACD(12,26,9) on BTCUSDT 15m — 672 bars, 2026-04-29 18:15 → 2026-05-06 18:00 UTC
Expand All @@ -494,7 +495,7 @@ order sizing: 1.0.0 gives an omitted
`initial_capital`, `default_qty_type` and `default_qty_value` TradingView's
Pine v6 defaults (100,000, `strategy.percent_of_equity`, 100), where 0.10.4
leaves the engine's own (1,000,000 and 1 contract). Declaring those in
`strategy()` books the same 13 trades on 1.1.0.
`strategy()` books the same 13 trades on 1.2.0.

Since 1.0.0, generated strategies reset persistent Pine state before each new
batch or stream warmup through the engine's script-run preparation hook. Input
Expand Down Expand Up @@ -574,7 +575,7 @@ quote. The commercial-license store (coming soon) will take orders online.

## Explicit Pine execution attachment

This section describes 1.1.0 and engine `v1.1.0`. The Pine execution adapter is
This section describes 1.2.0 and engine `v1.2.0`. The Pine execution adapter is
the engine's full Pine execution runtime (`PineExecutionAdapter` and
`PineStrategyHost` in the engine's `src/source/`): order lifecycle, bracket
legs, fill-price and slippage rules, POOC / `calc_on_order_fills`, margin
Expand All @@ -597,9 +598,9 @@ Regenerate old generated C++ before using a new engine for Pine execution. C++
generated before the source-layer cut
([#129](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/129)),
0.10.4's included, derives from `BacktestEngine` and does not compile against
engine `v1.1.0`; old cap-only C++ does not attach the priority rule, and
engine `v1.2.0`; old cap-only C++ does not attach the priority rule, and
metadata cannot silently restore it. Rebuild all modules against the
new matching C++ layout (`engine_script_run_v19` in engine `v1.1.0`); old
new matching C++ layout (`engine_script_run_v19` in engine `v1.2.0`); old
fingerprint versions are not comparable. The extraction preserves Pine policy
under explicit attachment; it does not implement the generic native
child-activation scheduler or prove campaign neutrality. Compile-only corpus
Expand Down
26 changes: 18 additions & 8 deletions docs/PUBLIC_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## Optional compiled execution capabilities

Availability: **since the next release**, with the paired engine's capability
extension and receipt-based runner admission policy.
Availability: **since 1.2.0**, with engine `v1.2.0`'s capability extension and
the receipt-based admission policy of its live runner.

The receipt proves declarations only, not general live-versus-batch equivalence.
Its `strategy()` positional arguments follow Pine signature order independently
Expand All @@ -24,8 +24,9 @@ All six builtin uses are refused including display-only use (plots, labels,
tables): the receipt records their use conservatively rather than certifying
that display-only code cannot influence strategy execution.

Paired development headers defining `PF_CAPABILITIES_API_VERSION` add
`strategy_capabilities_api_version()` (version 1) and
From 1.2.0 on, C++ compiled against headers that define both
`PF_SETTINGS_API_VERSION` and `PF_CAPABILITIES_API_VERSION`, as engine
`v1.2.0`'s do, adds `strategy_capabilities_api_version()` (version 1) and
`strategy_capabilities_receipt(handle, json, capacity, required, error, error_capacity)`.
The receipt uses the checked-settings status and buffer protocol: NULL/0 queries
return `PF_SETTINGS_BUFFER_TOO_SMALL`, `required` includes the NUL, and short
Expand All @@ -41,7 +42,9 @@ feed source. Requirements name historical-only data and intrabar persistence;
nonliteral contexts remain explicit rather than silently assuming defaults.
See the paired engine's `docs/strategy-capabilities.md` for the exact schema and
live-runner refusal policy. No batch dispatch, strategy calculation, matching,
margin or numeric behavior changes. Old paired headers emit no capability extension.
margin or numeric behavior changes. C++ compiled against headers without
`PF_CAPABILITIES_API_VERSION`, such as engine `v1.1.0`'s, has no capability
extension.

## Optional generated settings extension

Expand Down Expand Up @@ -77,7 +80,8 @@ reports remain empty; checked batch returns `PF_SETTINGS_RUN_FAILED`. Free and
recreate the handle to recover. Legacy setters that do not throw keep their
existing permissive behaviour.

Engine `v1.1.0`, the pair of codegen 1.1.0, provides that header. Settings
Engines `v1.1.0` and `v1.2.0`, the pairs of codegen 1.1.0 and 1.2.0, provide
that header. Settings
helper references are root-qualified and guarded by `PF_SETTINGS_API_VERSION`;
old headers retain the standard-exception fallback and legacy batch precheck.
Paired batch and stream refusals report NOT_COMPLETED through the shared native
Expand Down Expand Up @@ -143,7 +147,12 @@ released 2026-10-02, implements unchanged. 1.1.0, released 2026-10-04,
implements it with the generated settings extension and request discovery
above added: `transpile_full()`'s result and the JSON success envelope gain
`requests`, and `input.symbol` manifest entries gain `kind`. No argument,
result key or envelope is removed or renamed.
result key or envelope is removed or renamed. 1.2.0, released 2026-10-05,
implements it with the compiled execution capabilities and the diagnostic
codes described here added: each `Diagnostic` and each JSON diagnostic gain
`code` and `args`, and `pineforge_codegen` exports `diagnostics_catalog()`
and `render_diagnostic()`. No argument, result key or envelope is removed or
renamed.
The last 0.x release, 0.10.4, has
neither the `libraries` argument nor the `diagnostics` key described below.

Expand Down Expand Up @@ -263,7 +272,8 @@ Since 1.2.0 every `Diagnostic` (in `transpile_full(...)["diagnostics"]`, in a

`diagnostics_catalog()` returns the catalog, which ships as
`pineforge_codegen/diagnostics_catalog.json` (schema
`pineforge-diagnostics-catalog/v1`) and is attached to each GitHub release.
`pineforge-diagnostics-catalog/v1`) and is attached to each GitHub release
(`diagnostics_catalog-v1.2.0.json` for 1.2.0).
Per code it gives `severity`, `area`, the English ICU MessageFormat `message`
template, the `hint` template or `null`, a one-line `explanation`, and `args`:
per argument its `kind` — `identifier`, `type`, `keyword`, `number`, `vocab`
Expand Down
Loading
Loading