diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e0e251a..1173184c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,47 +5,171 @@ README's *Releases* section and on the GitHub releases page. From 1.0.0 the version number follows semantic versioning over the surfaces the [public contract](docs/pages/public-contract.md) lists. -## Unreleased - -- **Harness lot grid:** `docker/run_json.py` applies `mincontract` from the - `--syminfo` (`PINEFORGE_SYMINFO`) file as the engine's lot grid, the metadata key - `qty_step` plus the `mincontract` key a script's `syminfo.mincontract` reads, so a - percent-of-equity strategy no longer trades sub-lot quantities. Absent or `null` - changes nothing: the report and its fingerprint are as before, apart from - `elapsed_seconds`. A value that is not a positive finite number, or, when - `mincontract` is set, a strategy library without - `strategy_set_syminfo_metadata`, fails the run (one +## 1.1.0 — 2026-10-04 + +A minor release: it adds to the C ABI. `` declares six +more functions, the checked settings calls that a strategy generated by +pineforge-codegen 1.1.0 exports ([#317]). It also fixes the v1.0.0 and v1.0.1 +known issue of stale `request.security` values in live streams ([#325]). Engine +v1.1.0 pairs with pineforge-codegen 1.1.0, the pair the release hub's image +`ghcr.io/pineforge-4pass/pineforge-release:1.1.0` carries; codegen 1.1.0 also +lists the other symbols' feeds a script requests +(`transpile_full()["requests"]`), the feeds the harness's `--symbol-feeds` +installs ([#327]). The GitHub release attaches the three prebuilt tarballs, +`pineforge-v1.1.0-linux-x86_64.tar.gz`, `pineforge-v1.1.0-linux-aarch64.tar.gz` +and `pineforge-v1.1.0-macos-universal.tar.gz`, each with a `.sha256`. +`PF_ABI_VERSION` stays 4: `pineforge.h` only gains declarations, and +`native_c_api.h` and the native C++ host headers are unchanged, so no published +layout moves; the frozen historical headers and archives are untouched. The +script ABI epoch stays `engine_script_run_v19` and the state hashes keep their +domain tags; *State hashes* below lists every change to their values. The +installed header `pineforge/live_parser.h` is removed with the runner's parser +plugins ([#320]); no surface of the [public +contract](docs/pages/public-contract.md) covers it. The four rows of the 1.0 C +boundary that were scheduled for 1.1.0 (C-SURFACE-2: a non-mutating execution +preview, the origin and label of an applied event, a closed-trade entry-comment +accessor and a replace-options word) are not in this release. + +- **Checked strategy settings ([#317]).** The six functions are + `strategy_settings_api_version`, `strategy_create_checked`, + `strategy_set_input_checked`, `strategy_set_override_checked`, + `strategy_get_effective_settings` and `run_backtest_full_checked`, with the + status codes `pf_settings_status_t` and `PF_SETTINGS_API_VERSION` 1. With them + a C host refuses a bad input or override before a run (an unknown or ambiguous + key, an invalid enum, boolean or number, a declared range violation) with a + status code and a message, keeping the previous value; reads a JSON receipt of + every declared input and supported override with its default and effective + value; and runs a batch backtest that returns a status instead of letting a + C++ exception out. Look up `strategy_settings_api_version` with `dlsym`: a + module generated by an earlier codegen lacks all six and keeps the legacy + calls. The generated code uses `include/pineforge/checked_settings.hpp`; + [docs/checked-settings.md](docs/checked-settings.md) is the guide. + +- **C++ exceptions stop at the C ABI ([#317]).** A module generated by codegen + 1.1.0 catches them at every C entry point, the legacy ones included: a legacy + run or setter that throws leaves the entry point and the message in + `strategy_get_last_error`, and a batch call returns the existing empty-report + failure. Two behaviours change. A legacy setter that throws refuses every + later batch run and stream begin on that handle; recreate the handle. A + stream begin whose script preparation throws fails, with NOT_COMPLETED from + `strategy_last_run_status`, instead of starting; batch keeps its behaviour + for those exceptions. `pineforge-live` uses the checked calls when the + strategy has them: it refuses bad settings before it opens the ledger, and it + adds the effective-settings receipt to the deployment identity and to the run + summary (`effective_settings`). A strategy regenerated with codegen 1.1.0 + therefore cannot resume a ledger its earlier build wrote. With a strategy + from an earlier codegen the runner warns and keeps the legacy behaviour. + +- **Confirmed-bar streams compute what the batch computes ([#325]).** A native + stream fed confirmed bars now applies the same TradingView-parity rules as a + batch backtest over the same bars, so its trades can differ from 1.0.1's and + now follow the batch backtest's, apart from the look-ahead and + calendar-boundary limits the streaming guide's new *Backtest vs live* section + lists. Rules that streams had switched off are now chosen by the input: + historical semantics for batch and confirmed-bar input, observed-print + semantics only for genuine tick input. This fixes the v1.0.0 and v1.0.1 known + issue ([#323]): in a stream whose input and script timeframes are equal, + same-chart `request.security` values, Heikin-Ashi requests included, no + longer stop updating after the first realtime bar, because each newly + observed confirmed bar now reaches the requested-series evaluator. Two + stream-only fill differences also go: both-sided stop entries with default + sizing, and `process_orders_on_close` attribution. Batch results are + unchanged. A stream still refuses a missing confirmed bar and + `calc_on_order_fills`. + +- **Pine adapter parity ([#315], [#316]).** The adapter follows TradingView's + trade lists in more cases: same-bar entries under pyramiding; opening margin + checks on TradingView's opening schedule, gap-open checks kept; stop + reversals sized from their placed units; FIFO closes that split a lot, which + no longer leave a zero-quantity remainder; the trail extreme and the closing + stop carried through an opening fill's callback; all-in entries admitted + against the buying power at the order's source time; named percentage exit + targets sized from the live entry's ancestry; `request.security` calendar + history that no longer depends on auxiliary feeds, with full-day minute + requests published at the session close, early closes included; a stream + report's cumulative mark kept at a range end; a repeated short margin check + that reuses a resolved margin-call fill instead of applying slippage twice; + and exact fractional reversals under default and one-pyramid sizing, with a + short opening stop on a bar that opens at its high booked the way + TradingView's callbacks book it. The range-end change moves no fill: a + realtime stream that reaches its range end no longer re-marks its stored + terminal equity point or re-folds its equity extremes, and the report shows + the re-marked last point through a presentation hook instead, so that + stream's equity extremes and per-bar state hashes change while its trades + stay the same. A script that reaches one of these cases can get different + fills, sizes or trade counts than under 1.0.1. #315 moves 35 probes from + strong to excellent and #316 three more. + +- **Tick-built bar volume ([#319]).** In a stream fed with ticks, the forming + bar sums its prints' quantities exactly when the run's quantity grid is a + decimal step (1, 0.1, 0.01, …) and with compensated summation otherwise, so + it carries the volume that the same bar built offline from the same prints + has. Confirmed-bar input and batch runs are unchanged. Its hash change is + listed under *State hashes*. + +- **Report-only terminal quote ([#321]).** A magnified intraday batch run can be + given the chart's terminal quote: `scripts/run_strategy.py` takes the terminal + bar's time and close from the chart feed that + `PINEFORGE_RUN_REPORT_CHART_QUOTE` names (pinned by + `PINEFORGE_RUN_REPORT_CHART_QUOTE_SHA256`), a C host sets the + metadata keys `report_terminal_quote_time_ms` and + `report_terminal_quote_close` with `strategy_set_syminfo_metadata`, and a C++ + host calls `PineStrategyHost::set_report_terminal_quote`. The report then + prices a position still open at the range end, the synthetic `open_at_end` + row, at that quote: the row's exit fields, P&L and commission, the net + profit, the last equity point and the metrics derived from them change; + fills, the book, the hashes and the trace do not. Without the input nothing + changes, and `docker/run_json.py` does not read it. + [docs/report-terminal-quote.md](docs/report-terminal-quote.md) lists the + fields and the limits. + +- **Grader distinct-entry identity ([#313]).** `scripts/verify_corpus.py` + checks an engine entry against every TradingView entry key with the same time + and direction, not only the keys with several Signals: a price equal to one + key counts only there, and a price within tolerance of a multi-Signal key and + of another key refuses *excellent*. Trade matching and the thresholds are + unchanged; the README's *Distinct-entry identity* section states the rule. + +- **Harness symbol feeds ([#327]).** `docker/run_json.py --symbol-feeds` + (`PINEFORGE_SYMBOL_FEEDS` in the image entrypoint) installs other symbols' + bars for `request.security` on another symbol, which the harness did not do + before: a JSON index keyed by the exact symbol string the script passes and + by timeframe, each symbol with its catalog `syminfo` and one OHLCV CSV per + timeframe, installed through `strategy_set_symbol_facts` and + `strategy_set_symbol_feed` (C ABI calls since 1.0.0). Nothing aggregates + another symbol's bars, so a `1` feed serves neither a `240` nor a `D` + request; the run is historical only, with at most 256 symbols and 256 feeds + in one index. Unset, nothing changes. An index or feed the harness cannot + install fails the run (one `{"engine":"pineforge","error":...}` line whose + error begins `--symbol-feeds:`, harness exit 1, entrypoint exit 4), and what + it installed is recorded as `applied_runtime.symbol_feeds`, so such a run has + its own fingerprint digest. The change is in the harness alone; the release + hub's image passes `PINEFORGE_SYMBOL_FEEDS` to it as `--symbol-feeds` + (pineforge-release#23). [docker/README.md](docker/README.md) gives the index + format and the limits. + +- **Harness lot grid ([#322]).** `docker/run_json.py` applies `mincontract` + from the `--syminfo` (`PINEFORGE_SYMINFO`) file as the engine's lot grid, the + metadata key `qty_step` plus the `mincontract` key a script's + `syminfo.mincontract` reads, so order quantities are floored to the lot and a + percent-of-equity strategy no longer trades sub-lot quantities; v1.0.1's + harness ignored `mincontract`. Absent or `null` changes nothing: for the same + strategy library the report and its fingerprint are as before, apart from + `elapsed_seconds`. Instead of running without the grid, the run fails (one `{"engine":"pineforge","error":...}` line, harness exit 1, entrypoint exit 4) - instead of running without the grid. An applied grid is recorded as - `applied_runtime.syminfo`, so a gridded run has its own fingerprint digest. The - engine library is unchanged. - -- **Confirmed-bar streams compute what the batch computes:** a native stream fed - confirmed bars now applies the same TradingView-parity rules as a batch backtest over - the same bars. Rules that were switched off in any stream are now chosen by the input's - domain: historical semantics for batch and confirmed-bar input, observed-print semantics - only for genuine tick input. Fixes the v1.0.0/v1.0.1 known issue where same-chart - `request.security` stopped updating after the first realtime bar when the input and - script timeframes were equal, and two stream-only fill differences (both-sided stop - entries with default sizing; `process_orders_on_close` attribution). Batch results are - unchanged. The streaming guide gains a "Backtest vs live" section listing what a - backtest can see that a live run cannot. - -- **Harness symbol feeds:** `docker/run_json.py --symbol-feeds` (`PINEFORGE_SYMBOL_FEEDS`) - installs other symbols' bars for `request.security` on another symbol: a JSON - index keyed by the exact symbol string the script passes and by timeframe, each - feed an OHLCV CSV plus the symbol's catalog `syminfo`, through - `strategy_set_symbol_facts` / `strategy_set_symbol_feed` (engine and codegen - 1.0.0 and later). One feed per requested timeframe: nothing aggregates another - symbol's bars, so a `1` feed serves neither a `240` nor a `D` request. Unset - changes nothing; an index or feed it cannot install fails - the run (one `{"engine":"pineforge","error":...}` line, harness exit 1, - entrypoint exit 4). What was installed is recorded as - `applied_runtime.symbol_feeds`, so such a run has its own fingerprint digest. - The engine library is unchanged. - -- **Native runner routing and delivery:** webhooks are optional; `--webhook-routes` - adds first-match per-action targets and payload `pineforge-native-order-action/v2`. + when `mincontract` is not a positive finite number, with the message + `syminfo.mincontract must be a positive finite number, got `, or when `mincontract` is set and the strategy library has no + `strategy_set_syminfo_metadata`, with the message `the strategy library has + no strategy_set_syminfo_metadata, so syminfo.mincontract cannot be applied`. + An applied grid is recorded as `applied_runtime.syminfo`, so a gridded run has + its own fingerprint digest. The change is in the harness alone; the release + hub copies `docker/run_json.py` from the engine tag, so `pineforge-release` + 1.1.0 carries it. + +- **Native runner routing and delivery ([#320]).** Webhooks are optional; + `--webhook-routes` adds first-match per-action targets and payload + `pineforge-native-order-action/v2`. New `actions`, `status` and offline `redeliver` commands expose the journal and delivery audit. `redeliver` requires the ledger's `--deployment` identity. Existing `--webhook-url` deployments keep one default target, exact v1 payload @@ -57,11 +181,12 @@ version number follows semantic versioning over the surfaces the SIGINT/SIGTERM exit 130. Redelivery exits 2 for failed or pending selections. Schema-1 native ledgers migrate additively to an append-only delivery log without rewriting actions. This migration is one-way: older runner binaries cannot open - the migrated ledger. Back up the ledger before upgrading. The engine is unchanged. + the migrated ledger. Back up the ledger before upgrading. This runner change + leaves the engine library as it was. -- **Runner tooling removal:** the native live runner accepts only normalized - PineForge feed events from stdin, files, or a user's own HTTP/WebSocket feed - service. The installed `pineforge/live_parser.h` header, its +- **Runner tooling removal ([#320]).** The native live runner accepts only + normalized PineForge feed events from stdin, files, or a user's own + HTTP/WebSocket feed service. The installed `pineforge/live_parser.h` header, its `PF_LIVE_PARSER_*` types/constants and `pf_live_parser_abi_version` / `pf_live_parse_message` plugin exports, the `--parser` / `--parser-config` flags, and the example plugin are removed. This breaks callers that included @@ -71,12 +196,127 @@ version number follows semantic versioning over the surfaces the that adapter, not an exchange. The outbound order-action webhook remains. Strict native runner configurations now also require 1m input; higher script timeframes still aggregate those minutes. - No versioned engine `PF_API` export, native C++ surface, script ABI epoch or - engine behavior changes. Frozen historical ABI header manifests and archives - remain intact. Plugin-free ledger identity bytes remain unchanged; ledgers + This change itself alters no versioned engine `PF_API` export, native C++ + surface, script ABI epoch or engine behavior. Frozen historical ABI header + manifests and archives remain intact. For a strategy without the checked + settings calls, plugin-free ledger identity bytes remain unchanged; ledgers bound to removed plugins cannot be resumed by this runner and must not be silently rewritten. +- **Documentation ([#312], [#318], [#323], [#324]).** The README's new *How a + change is judged* section states the merge rule's zero-score outcome as it is + now: a score of exactly 0 passes only when nothing got worse (#312). The + parity figures of the README and the docs pages render from the release hub's + public facts tokens, kept in step by `lab facts render` and `lab facts check`, + and the README keeps a release's grades apart from main's scoreboard (#318); + the README's Parity and Trades badges render as images again (#324). The + streaming page gains a *Known issues* section (#323). + +- **Known issue fixed ([#323], [#325]).** The stream `request.security` known + issue that #323 documented for v1.0.0 and v1.0.1 is fixed in 1.1.0 by #325 + (above); the README keeps the note and links to the streaming page, which + keeps the workaround for those versions. + +### State hashes + +The script ABI epoch (`engine_script_run_v19`) and the domain tags +(`pineforge-broker-state/v19`, `pineforge-source-adapter/v4`) are unchanged. A +behaviour change above changes state-hash values for the runs it affects while +the recipe (which fields are hashed and how they are encoded) stays the same; +#315's range-end change, for example, changes a realtime stream's per-bar +hashes and leaves its trades as they were. Under the public contract's +state-hash rule, amended in this release, a minor release may also change a +recipe by adding a hashed field, with the domain tags unchanged, when the added +field changes no trade or report, and discloses it here. 1.1.0 adds hashed +fields in four places and removes, renames or re-encodes none, so state hashes +from 1.0.0 and 1.0.1 do not match 1.1.0's for the runs that reach them: + +- [#315] adds a record to the Pine adapter's part of the broker-state hash: the + original request, placement and submission context of a same-bar market entry + that joins a fixed market batch, folded only while such an entry is pending, + a state #315 introduces. +- [#316] adds an opening stop's next-waypoint flag + (`coof_open_stop_next_waypoint`) to the same adapter state, on each hashed + placement and on the adapter, each folded only when set; the witness rows + `Random44/0/0` and `Random44/0/1` were re-pinned with their trades hash + unchanged (13 trades each). +- [#319] adds to the native continuation hash, which the broker-state hash + folds, both tick-volume accumulators together with the partial bar and its + script-bar open, in an observed-tick stream and only where an accumulator is + not at its default or redundant with the bar's published volume; every + existing tick, bar and batch pin holds. +- [#325] adds stream-only state to the Pine scheduler's part of the + broker-state hash: whether the input is observed ticks, the confirmed-input + counters and the retained confirmed input bars. A batch run folds none of it. + The witness rows `Stream/0/0` and `Stream/0/1` were re-pinned with their + trades hash too (the trade count stays 5), because the same change makes the + stream compute what the batch computes. + +### Report keys + +The JSON report of `docker/run_json.py`, the release image's +[report schema](docs/pages/report-schema.md), from v1.0.1 to v1.1.0: + +- No key is removed or renamed. `EQUITY_REPORT_KEYS` is unchanged: + `metrics.equity.sharpe_tv` and `sortino_tv` stay. +- Added: `applied_runtime.syminfo`, `{"qty_step": , "mincontract": + }`, present only when the `--syminfo` (`PINEFORGE_SYMINFO`) file + carries a valid `mincontract` and absent otherwise. + `fingerprint.provenance.runtime` holds the same fields as `applied_runtime`, + so a gridded run's fingerprint differs from the gridless run's, and a gridless + report is the one v1.0.1's harness writes for the same strategy library, + apart from `elapsed_seconds`. +- Added: `applied_runtime.symbol_feeds`, `{"canonicalization": + "pf-symbol-feed-barc-close-le-v1", "symbols": {"": {"facts": + {...}, "feeds": {"": {"bars": , "first_ts": , "last_ts": + , "source_values_sha256": ""}}}}}`, present only when + `--symbol-feeds` (`PINEFORGE_SYMBOL_FEEDS`) installed at least one symbol and + absent otherwise; `first_ts` and `last_ts` appear only for a feed with bars. + `facts` holds the catalog facts that were set, `canonical`, `type`, + `timezone`, `session` and `currency` as strings and `mintick` as a number, + each only when the index gives it. `fingerprint.provenance.runtime` holds the + same fields, so a run with symbol feeds has its own fingerprint. +- Failure output: the existing one-line `{"engine":"pineforge","error":...}` on + stdout, harness exit 1 and image entrypoint exit 4 (the existing + backtest-failure code), with new messages: the lot grid's + `syminfo.mincontract must be a positive finite number, got ` and `the strategy library has no + strategy_set_syminfo_metadata, so syminfo.mincontract cannot be applied`, and + the symbol feeds' messages, each beginning `--symbol-feeds:` (an index or + feed it cannot read or refuses, a library without `strategy_set_symbol_facts` + / `strategy_set_symbol_feed`, or a fact or feed the engine refuses). + +### Migration + +- Regenerate strategy C++ with pineforge-codegen 1.1.0 and relink it against + v1.1.0's headers and `libpineforge.a`. Only a regenerated module has the + checked settings calls and stops C++ exceptions at its C entry points. +- Back up a native runner ledger before upgrading: its migration to the + delivery log is one-way, and older runner binaries cannot open the migrated + ledger. A ledger bound to a removed parser plugin cannot be resumed, and a + strategy regenerated with codegen 1.1.0 needs a new deployment. +- A confirmed-bar stream's trades can change from 1.0.1's ([#325]), and state + hashes from 1.0.0 and 1.0.1 do not match 1.1.0's for the runs *State hashes* + lists: re-baseline stored stream results and hashes. +- Code that included `pineforge/live_parser.h` or wrote a parser plugin moves + that translation into an external feed adapter that emits + [PineForge feed events](runner/README.md#feed-format). + +[#312]: https://github.com/pineforge-4pass/pineforge-engine/pull/312 +[#313]: https://github.com/pineforge-4pass/pineforge-engine/pull/313 +[#315]: https://github.com/pineforge-4pass/pineforge-engine/pull/315 +[#316]: https://github.com/pineforge-4pass/pineforge-engine/pull/316 +[#317]: https://github.com/pineforge-4pass/pineforge-engine/pull/317 +[#318]: https://github.com/pineforge-4pass/pineforge-engine/pull/318 +[#319]: https://github.com/pineforge-4pass/pineforge-engine/pull/319 +[#320]: https://github.com/pineforge-4pass/pineforge-engine/pull/320 +[#321]: https://github.com/pineforge-4pass/pineforge-engine/pull/321 +[#322]: https://github.com/pineforge-4pass/pineforge-engine/pull/322 +[#323]: https://github.com/pineforge-4pass/pineforge-engine/pull/323 +[#324]: https://github.com/pineforge-4pass/pineforge-engine/pull/324 +[#325]: https://github.com/pineforge-4pass/pineforge-engine/pull/325 +[#327]: https://github.com/pineforge-4pass/pineforge-engine/pull/327 + ## 1.0.1 — 2026-10-02 A documentation-only release that pairs with pineforge-codegen 1.0.1, the pair diff --git a/README.md b/README.md index 1f04025e..576be365 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ PineForge is a C++17 engine for backtesting and forward execution, with a C ABI 1. **A generic kernel** — a Pine-agnostic backtest and forward-execution state machine: order matching and fills, sizing, margin and settlement, the bar magnifier, indicator classes, `request.security()`, time and session math. Some TradingView-shaped names survive in its archive, each ruled in [ADR 0001](docs/adr/0001-kernel-adapter-boundary.md) and held there by `scripts/check_kernel_residuals.py`. 2. **A source-adapter parity runtime** (`src/source/` and `src/compat/pine/`, `PineExecutionAdapter` + `PineStrategyHost`) — maps Pine/TradingView execution semantics onto that kernel. This is where TradingView parity lives. -The separate PineForge compiler, [`pineforge-codegen`](https://github.com/pineforge-4pass/pineforge-codegen-oss), translates a PineScript v6 script into a C++ strategy that attaches the engine's Pine execution adapter (its releases 1.0.0 and 1.0.1 do; 0.10.4 predates the adapter); it owns translation, not execution semantics. TradingView comparisons measure this Pine path under the tested configurations. The [order model](docs/pages/fill-model.md) describes the current submodels and the remaining migration work; [Architecture](#architecture-kernel-vs-parity) states the boundary. +The separate PineForge compiler, [`pineforge-codegen`](https://github.com/pineforge-4pass/pineforge-codegen-oss), translates a PineScript v6 script into a C++ strategy that attaches the engine's Pine execution adapter (its releases 1.0.0, 1.0.1 and 1.1.0 do; 0.10.4 predates the adapter); it owns translation, not execution semantics. TradingView comparisons measure this Pine path under the tested configurations. The [order model](docs/pages/fill-model.md) describes the current submodels and the remaining migration work; [Architecture](#architecture-kernel-vs-parity) states the boundary. -- **Proven, not promised.** All 7,989 graded probes — 309 open reference strategies, 680 community-shared scripts and 61 probe scripts the maintainers wrote, on 18 market/timeframe lanes — grade against TradingView's own trade lists: **7,949 excellent, 40 strong, 0 below strong**. The graded probes' TradingView trade lists hold 4,776,328 trades; 17 probes with TradingView-side defects are excluded. +- **Proven, not promised.** All 7,989 graded probes — 309 open reference strategies, 680 community-shared scripts and 61 probe scripts the maintainers wrote, on 18 market/timeframe lanes — grade against TradingView's own trade lists: **7,951 excellent, 38 strong, 0 below strong**. The graded probes' TradingView trade lists hold 4,776,328 trades; 17 probes with TradingView-side defects are excluded. - **Open runtime.** The engine and native live runner are Apache-2.0. The separately distributed [PineForge compiler](https://github.com/pineforge-4pass/pineforge-codegen-oss/blob/main/LICENSE) uses PolyForm Noncommercial terms with additional personal-trading permission; commercial use requires a separate license. Public reference strategies, benchmarks and validation tooling are available in their respective repositories; the community-script test set is not redistributed. - **Fast.** In-process, no interpreter: median **36× faster than PyneCore** on the 200 strategies both engines time, measured at engine `35db01c8` on 2026-09-29 on an AWS c7a.8xlarge with PyneCore timed as a subprocess, its interpreter start-up included (PineForge runs a median 807k bars/s per strategy over its 201 slots with the bar magnifier on; [method](benchmarks/results/speed.md)). Parameter sweeps re-run a loaded `.so` with new inputs — no recompile, no fork. - **Deterministic to the bit.** Two runs with the same inputs produce identical trade lists. Same on Linux and macOS. @@ -88,7 +88,7 @@ Prerequisites: CMake ≥ 3.16 to build (the verifier and `ctest --test-dir` need ### Prebuilt library -The [v1.0.1 release](https://github.com/pineforge-4pass/pineforge-engine/releases/tag/v1.0.1) attaches the library prebuilt: `pineforge-v1.0.1-linux-x86_64.tar.gz`, `pineforge-v1.0.1-linux-aarch64.tar.gz` and `pineforge-v1.0.1-macos-universal.tar.gz`, each with a `.sha256`. Each unpacks to one directory holding what the install above writes (the two archives, `include/pineforge/` and the `find_package(PineForge)` config) plus `LICENSE`, `NOTICE` and `VERSION`; point `CMAKE_PREFIX_PATH` at it. The package asks for Eigen 3.3+: install it on Linux, while the macOS tarball carries Eigen 3.4.0 ([install guide](docs/pages/install.md)). +The [v1.1.0 release](https://github.com/pineforge-4pass/pineforge-engine/releases/tag/v1.1.0) attaches the library prebuilt: `pineforge-v1.1.0-linux-x86_64.tar.gz`, `pineforge-v1.1.0-linux-aarch64.tar.gz` and `pineforge-v1.1.0-macos-universal.tar.gz`, each with a `.sha256`. Each unpacks to one directory holding what the install above writes (the two archives, `include/pineforge/` and the `find_package(PineForge)` config) plus `LICENSE`, `NOTICE` and `VERSION`; point `CMAKE_PREFIX_PATH` at it. The package asks for Eigen 3.3+: install it on Linux, while the macOS tarball carries Eigen 3.4.0 ([install guide](docs/pages/install.md)). ### Embedded in your own harness @@ -131,14 +131,14 @@ TradingView's execution semantics on top of the kernel; this is the path the validation scoreboard below measures. ```bash -pip install "pineforge-codegen==1.0.1" +pip install "pineforge-codegen==1.1.0" python3 -c "from pathlib import Path; from pineforge_codegen import transpile; Path('generated.cpp').write_text(transpile(Path('strategy.pine').read_text(), filename='strategy.pine'))" c++ -std=c++17 -O2 -ffp-contract=off -fbracket-depth=1024 -shared -fPIC generated.cpp \ -Wl,-force_load,/usr/local/lib/libpineforge.a -o strategy.so python3 scripts/run_strategy.py . --ohlcv tutorial/data/btcusdt_15m_7d.csv --no-trim-output # or drive it over the C ABI ``` -Run it from the engine checkout, with `strategy.pine` there, after the `cmake --install` above (with a prebuilt tarball instead, add `-I/include` and link its `lib/libpineforge.a`). Engine v1.0.1 pairs with pineforge-codegen 1.0.1, as v1.0.0 does with 1.0.0; codegen 0.10.4 emits C++ for engine v0.13.1, which the headers of v1.0.0 and v1.0.1 no longer compile. No codegen release has a command-line entry point, so transpile through `transpile()`. The compile line is macOS/Clang's: on Linux link `-Wl,--whole-archive /usr/local/lib/libpineforge.a -Wl,--no-whole-archive`, and drop `-fbracket-depth` for GCC. Linking the whole archive is what puts the runtime's C exports (`pf_abi_version`, the `strategy_stream_*` family) in the module; a script that uses `matrix.*` also needs Eigen's include directory. +Run it from the engine checkout, with `strategy.pine` there, after the `cmake --install` above (with a prebuilt tarball instead, add `-I/include` and link its `lib/libpineforge.a`). Engine v1.1.0 pairs with pineforge-codegen 1.1.0, as v1.0.1 does with 1.0.1 and v1.0.0 with 1.0.0; codegen 0.10.4 emits C++ for engine v0.13.1, which the headers of v1.0.0, v1.0.1 and v1.1.0 no longer compile. No codegen release has a command-line entry point, so transpile through `transpile()`. The compile line is macOS/Clang's: on Linux link `-Wl,--whole-archive /usr/local/lib/libpineforge.a -Wl,--no-whole-archive`, and drop `-fbracket-depth` for GCC. Linking the whole archive is what puts the runtime's C exports (`pf_abi_version`, the `strategy_stream_*` family) in the module; a script that uses `matrix.*` also needs Eigen's include directory. ### 2. C++, against the kernel @@ -224,22 +224,22 @@ scoreboard below describes batch backtests; it does not certify new native live behavior or real broker fills. Known issue (v1.0.0, v1.0.1): a stream whose input and script timeframes are equal serves stale `request.security` values after the first realtime bar. -Fixed on main (#325); included in the next release. See +Fixed in 1.1.0 (#325). See [Streaming known issues](docs/pages/streaming.md#streaming_known_issues) for the workaround for those versions. ## Validation scoreboard -**Measured 2026-10-03** on main engine `700c5d24` with codegen-oss `13b9ccfd` (baseline `pineforge-parity-baseline-20261003-engine-700c5d24`, snapshot `3ee846c5`): **7,989 graded probes, 7,949 excellent + 40 strong**, 0 below strong and 0 engine errors across 18 market/timeframe lanes. The historical release 1.0.1 inventory holds 4,776,328 trades. +**Measured 2026-10-04** on main engine `7b596622` with codegen-oss `c5d97ee5` (baseline `pineforge-parity-baseline-20261004-engine-7b596622`, snapshot `af86f13e`): **7,989 graded probes, 7,951 excellent + 38 strong**, 0 below strong and 0 engine errors across 18 market/timeframe lanes. The historical release 1.0.1 inventory holds 4,776,328 trades. -Release **1.0.1 still grades 7,905 excellent / 84 strong until the next release**, on 7,989 probes (baseline `pineforge-parity-baseline-20261001-codegen-67892cda`, 2026-10-01). A main scoreboard advance does not change release results. +Release **1.1.0 grades 7,951 excellent / 38 strong until the next release**, on 7,989 probes (baseline `pineforge-parity-baseline-20261004-engine-7b596622`, 2026-10-04). 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 `; `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 release 1.0.1, independent of future main population rebinds, not to registry row or slug totals. | Board | Test set | Result | |---|---|---| -| **Public** — [open corpus](https://github.com/pineforge-4pass/pineforge-corpus) | 312 reference strategies on BINANCE:ETHUSDT.P 15m, Apache-2.0, reproducible by anyone | this repository's sweep: **311 excellent + 1 declared anomaly**; the 309 of them in the measured population: **309 excellent** | -| **Closed test** | 7,680 probes of 741 TradingView scripts across the 18 lanes: 680 community-shared scripts (7,179 probes), private under TradingView's Terms of Service, and 61 probe scripts the maintainers wrote (501 probes) | **7,640 excellent + 40 strong** | +| **Public** — [open corpus](https://github.com/pineforge-4pass/pineforge-corpus) | 312 reference strategies on BINANCE:ETHUSDT.P 15m, Apache-2.0, reproducible by anyone | this repository's sweep of the v1.0.1 library: **311 excellent + 1 declared anomaly**; the 309 of them in the measured population: **309 excellent** | +| **Closed test** | 7,680 probes of 741 TradingView scripts across the 18 lanes: 680 community-shared scripts (7,179 probes), private under TradingView's Terms of Service, and 61 probe scripts the maintainers wrote (501 probes) | **7,642 excellent + 38 strong** | ### Lane by lane @@ -253,7 +253,7 @@ The quantities above render from the public [facts tokens](https://github.com/pi | BINANCE:ETHUSDT.P · 1D | 540 | 539 | 1 | 0 | | CME_MINI:ES1! · 15m | 76 | 76 | 0 | 0 | | CME_MINI:ES1! · 1D | 35 | 35 | 0 | 0 | -| CME_MINI:NQ1! · 15m | 74 | 73 | 1 | 0 | +| CME_MINI:NQ1! · 15m | 74 | 74 | 0 | 0 | | CME_MINI:NQ1! · 1D | 37 | 37 | 0 | 0 | | NASDAQ:AAPL · 15m | 632 | 631 | 1 | 0 | | NASDAQ:AAPL · 1D | 464 | 464 | 0 | 0 | @@ -261,11 +261,11 @@ The quantities above render from the public [facts tokens](https://github.com/pi | NSE:NIFTY · 1D | 225 | 225 | 0 | 0 | | NYSE:F · 15m | 637 | 625 | 12 | 0 | | NYSE:F · 1D | 505 | 502 | 3 | 0 | -| OANDA:EURUSD · 15m | 653 | 648 | 5 | 0 | +| OANDA:EURUSD · 15m | 653 | 649 | 4 | 0 | | OANDA:EURUSD · 1D | 453 | 453 | 0 | 0 | | OANDA:XAUUSD · 15m | 695 | 692 | 3 | 0 | | OANDA:XAUUSD · 1D | 456 | 456 | 0 | 0 | -| **Total** | **7,989** | **7,949** | **40** | **0** | +| **Total** | **7,989** | **7,951** | **38** | **0** | @@ -373,7 +373,7 @@ Slot 192 has no PyneCore trade list: PyneSys rejects its source (`"Empty documen - **Tiers:** they now come from the canonical `scripts/verify_corpus.py::analyze_strategy` rubric. The old table graded a different 100-strategy population with `compare.py`'s own copy of the rubric, which had drifted from the canonical one and no longer parsed the current tape format. - **Speed:** that table was timed on the Apple M4 Max. The 2026-06-11 engine, rebuilt on the AWS host and timed in the same window, runs the three probes both populations share 4–8× faster than `35db01c8` ([provenance](benchmarks/results/speed.md#provenance)). -Last refresh **2026-09-29** (engine `35db01c8`, codegen `121b3e6a`, PyneCore 6.10.3, PineTS 0.9.34, vectorbt 0.28.2; timed on an AWS c7a.8xlarge running Ubuntu 24.04); v1.0.0 and v1.0.1 were released after it, and neither the tiers nor the timings were re-measured on them. Per-strategy table: [`benchmarks/results/summary.md`](benchmarks/results/summary.md). Population manifest: [`benchmarks/results/selection.md`](benchmarks/results/selection.md). Method, fairness and the reproduction recipe: [`benchmarks/README.md`](benchmarks/README.md). +Last refresh **2026-09-29** (engine `35db01c8`, codegen `121b3e6a`, PyneCore 6.10.3, PineTS 0.9.34, vectorbt 0.28.2; timed on an AWS c7a.8xlarge running Ubuntu 24.04); v1.0.0, v1.0.1 and v1.1.0 were released after it, and neither the tiers nor the timings were re-measured on them. Per-strategy table: [`benchmarks/results/summary.md`](benchmarks/results/summary.md). Population manifest: [`benchmarks/results/selection.md`](benchmarks/results/selection.md). Method, fairness and the reproduction recipe: [`benchmarks/README.md`](benchmarks/README.md). --- @@ -465,7 +465,7 @@ ground written for an agent that has been handed a brief in this repository. - `benchmarks/` — the cross-engine comparison harness (PineForge, PyneCore, PineTS, vectorbt) and the throughput package. - `scripts/` — `run_corpus.sh`, `verify_corpus.py`, `run_strategy.py` (load any `.so` via ctypes), `regen_corpus_cpp.sh`, `coverage.sh`. -**This is the runtime, not the compiler.** The PineScript → C++ transpiler is [`pineforge-codegen`](https://github.com/pineforge-4pass/pineforge-codegen-oss) (its release 1.0.1, `pip install "pineforge-codegen==1.0.1"`, pairs with engine v1.0.1), bundled with the runtime in the [`pineforge-release`](https://github.com/pineforge-4pass/pineforge-release) image that the MCP server builds on. **It is a backtest engine, not a chart:** `plot` and `bgcolor` compile and draw nothing; `line`, `box`, `label` and `linefill` objects are kept as data the script can read back, never rendered. **It is not a TradingView clone:** where TradingView's behaviour is undocumented or platform-specific (the bar magnifier's intrabar path, float ordering) PineForge chooses deterministic rules and documents them; where it converges, it converges exactly. +**This is the runtime, not the compiler.** The PineScript → C++ transpiler is [`pineforge-codegen`](https://github.com/pineforge-4pass/pineforge-codegen-oss) (its release 1.1.0, `pip install "pineforge-codegen==1.1.0"`, pairs with engine v1.1.0), bundled with the runtime in the [`pineforge-release`](https://github.com/pineforge-4pass/pineforge-release) image that the MCP server builds on. **It is a backtest engine, not a chart:** `plot` and `bgcolor` compile and draw nothing; `line`, `box`, `label` and `linefill` objects are kept as data the script can read back, never rendered. **It is not a TradingView clone:** where TradingView's behaviour is undocumented or platform-specific (the bar magnifier's intrabar path, float ordering) PineForge chooses deterministic rules and documents them; where it converges, it converges exactly. Full coverage map — every TA class, every order primitive, every `request.security()` semantic, and what is deliberately not implemented: [`docs/coverage.md`](docs/coverage.md). @@ -645,6 +645,7 @@ Documentation: [C ABI reference](https://cdocs.pineforge.dev) · [Getting starte ## Releases +- **v1.1.0** (2026-10-04) — a minor release: a strategy generated by pineforge-codegen 1.1.0 exports six checked-settings C functions and stops C++ exceptions at its C entry points, and codegen 1.1.0's `transpile_full()` lists the other symbols' feeds a script requests; confirmed-bar streams compute what the batch computes, which fixes the v1.0.0 and v1.0.1 stream `request.security` known issue; Pine adapter parity changes, exact tick-built bar volume, a report-only terminal quote, the Docker harness's lot grid from `syminfo.mincontract` and its multi-symbol `request.security` feeds, and native runner webhook routing, with `pineforge/live_parser.h` and the runner's parser plugins removed (the hub image `pineforge-release:1.1.0` carries the pair); regenerate and relink. See [CHANGELOG.md](CHANGELOG.md). - **v1.0.1** (2026-10-02) — documentation only: no library, C ABI, script ABI or report change since v1.0.0. It pairs with pineforge-codegen 1.0.1, which compiles history reads of objects, drawings, arrays and matrices where 1.0.0's C++ did not, and stores an int `na` given to a `float` field as `na` (the hub image `pineforge-release:1.0.1` carries the pair); regenerate and relink. See [CHANGELOG.md](CHANGELOG.md). - **v1.0.0** (2026-09-30) — the first stable release under semantic versioning; from it the engine and pineforge-codegen release one version (codegen 1.0.0; the hub image `pineforge-release:1.0.0` carries the pair). Every change since v0.13.1: C ABI version 4, the native kernel and its C host API, the script ABI epoch v19. What a 0.13.1 user must act on is in [CHANGELOG.md](CHANGELOG.md); what 1.x promises is the [public contract](docs/pages/public-contract.md). - **v0.13.1** (2026-09-06) — the parity campaign's rounds 7–11: TradingView's broker rules pinned with sensor exports and landed with replay tests — ten-significant-digit money, trailing-stop restarts, zero-offset trails, declined-reversal bracket legs, the surviving `strategy.close`, sparse `ta.atr`/`ta.tr`, same-bar market transactions, early-close higher-timeframe buckets; the corpus keeps every USDT-quoted book in USDT. Closed test 3,880/3,881; corpus 309/309. ABI v3, 32 symbols, 198 tests. diff --git a/docs/pages/contributing-llm.md b/docs/pages/contributing-llm.md index 322e6eec..c723966e 100644 --- a/docs/pages/contributing-llm.md +++ b/docs/pages/contributing-llm.md @@ -20,7 +20,7 @@ a **kernel** that matches triggers, prices fills, books lots and settles, and a it. A separate project transpiles PineScript into C++ that attaches the adapter. The engine's value is that its output is *byte-reproducible* and graded *trade for trade against TradingView* on a fixed population (8,006 probes at -the current baseline; 7,949 of the 7,989 graded are excellent, 40 strong), so +the current baseline; 7,951 of the 7,989 graded are excellent, 38 strong), so almost every rule below exists to keep a change from quietly moving a byte. ## Repo map diff --git a/docs/pages/install.md b/docs/pages/install.md index 5fa9988b..68f9753e 100644 --- a/docs/pages/install.md +++ b/docs/pages/install.md @@ -52,24 +52,24 @@ ${prefix}/ ## Prebuilt tarballs A release attaches the library prebuilt to its GitHub release. For -[v1.0.1](https://github.com/pineforge-4pass/pineforge-engine/releases/tag/v1.0.1) -they are `pineforge-v1.0.1-linux-x86_64.tar.gz`, -`pineforge-v1.0.1-linux-aarch64.tar.gz` and -`pineforge-v1.0.1-macos-universal.tar.gz` (one archive for arm64 and x86_64), +[v1.1.0](https://github.com/pineforge-4pass/pineforge-engine/releases/tag/v1.1.0) +they are `pineforge-v1.1.0-linux-x86_64.tar.gz`, +`pineforge-v1.1.0-linux-aarch64.tar.gz` and +`pineforge-v1.1.0-macos-universal.tar.gz` (one archive for arm64 and x86_64), each with a `.sha256`. A tarball unpacks to one directory, -`pineforge-v1.0.1-/`, laid out as the install above (both archives, +`pineforge-v1.1.0-/`, laid out as the install above (both archives, `include/pineforge/`, `lib/cmake/PineForge/`), with `LICENSE`, `NOTICE` and `VERSION` beside them: ```bash -curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.0.1/pineforge-v1.0.1-linux-x86_64.tar.gz -curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.0.1/pineforge-v1.0.1-linux-x86_64.tar.gz.sha256 -sha256sum -c pineforge-v1.0.1-linux-x86_64.tar.gz.sha256 # macOS: shasum -a 256 -c -tar -xzf pineforge-v1.0.1-linux-x86_64.tar.gz +curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.1.0/pineforge-v1.1.0-linux-x86_64.tar.gz +curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.1.0/pineforge-v1.1.0-linux-x86_64.tar.gz.sha256 +sha256sum -c pineforge-v1.1.0-linux-x86_64.tar.gz.sha256 # macOS: shasum -a 256 -c +tar -xzf pineforge-v1.1.0-linux-x86_64.tar.gz ``` A CMake consumer finds it with -`-DCMAKE_PREFIX_PATH=$PWD/pineforge-v1.0.1-linux-x86_64` (@ref integration_cmake). +`-DCMAKE_PREFIX_PATH=$PWD/pineforge-v1.1.0-linux-x86_64` (@ref integration_cmake). The package config asks for Eigen 3.3 or later (`find_dependency(Eigen3 3.3)`): install it on Linux (`libeigen3-dev` on Debian and Ubuntu); the macOS tarball carries Eigen 3.4.0's headers and CMake package, which the same prefix finds. @@ -89,7 +89,7 @@ with the hub's own version (`X.Y.Z`, `X.Y`, and `latest` for the newest stable one), with `engine-codegen` naming the pair it carries, and with `sha-`; a release candidate gets no `latest`. Pin the `engine-codegen` tag of the engine release you build against: for -v1.0.1, `engine1.0.1-codegen1.0.1`, the image the hub also tags `1.0.1`. +v1.1.0, `engine1.1.0-codegen1.1.0`, the image the hub also tags `1.1.0`. ```bash docker pull ghcr.io/pineforge-4pass/pineforge-release:latest diff --git a/docs/pages/public-contract.md b/docs/pages/public-contract.md index 5b52a1cd..bf35ae2a 100644 --- a/docs/pages/public-contract.md +++ b/docs/pages/public-contract.md @@ -4,7 +4,10 @@ 1.0.0 was released on 2026-09-30: engine v1.0.0 with pineforge-codegen 1.0.0. 1.0.1 followed on 2026-10-02: engine v1.0.1, which changes only documentation, -with pineforge-codegen 1.0.1. From 1.0.0 the engine's version number is a +with pineforge-codegen 1.0.1. 1.1.0 followed on 2026-10-04: engine v1.1.0, which +adds six functions to the C ABI (the checked settings calls of +``, which a strategy generated by codegen 1.1.0 exports), +with pineforge-codegen 1.1.0. From 1.0.0 the engine's version number is a semantic version over the surfaces this page lists, and over nothing else: a PATCH release fixes behaviour, a MINOR release adds to a surface, and only a MAJOR release removes or changes one. Each rule below names the checker or the CTest row that holds it on this @@ -126,24 +129,30 @@ and `` (@ref native_engine). mismatched pairs to fail on the epoch-qualified `BacktestEngine::broker_state_hash` symbol (`scripts/ci_verify.py` requires their prepared receipts, so none of them skips there). -- **State-hash values are stable within the epoch.** The recipe of each state - hash — the broker-state hash (`strategy_broker_state_hash`, the per-bar - `pf_report_t::broker_state_hash` rows), the stream fingerprint - (`strategy_stream_state_hash`) and the native continuation hash — belongs to - the epoch, so from 1.0.0 every 1.x engine folds one state to one value, and - a new recipe is a new epoch and a major release. Values from builds before - 1.0.0 are not comparable. `scripts/check_aggregate_cpp_versions.py` and - `scripts/check_broker_state_hash_coverage.py` pin the domain tags - `pineforge-broker-state/v19` and `pineforge-source-adapter/v4` and the - stream fingerprint's version 19; witness rows pin values — +- **State-hash recipes belong to the epoch.** The recipe of each state hash, + which fields it folds and how they are encoded, for the broker-state hash + (`strategy_broker_state_hash`, the per-bar `pf_report_t::broker_state_hash` + rows), the stream fingerprint (`strategy_stream_state_hash`) and the native + continuation hash, is the epoch's. A minor release may change a recipe only + by adding a hashed field, with the domain tags unchanged and only when the + added field changes no trade or report; its CHANGELOG discloses the addition + under *State hashes*, because state hashes from earlier releases of the epoch + will not match. A recipe change that removes, renames or re-encodes a hashed + field is a new epoch and a major release. Behaviour changes, fixes that + change values, trades or reports while the recipe stays the same, are not + recipe changes: they follow the normal release and parity rules. The first + uses of the addition rule are #315 and #316, in 1.1.0. Values from builds + before 1.0.0 are not comparable. `scripts/check_aggregate_cpp_versions.py` + and `scripts/check_broker_state_hash_coverage.py` pin the domain tags + `pineforge-broker-state/v19` and `pineforge-source-adapter/v4` and the stream + fingerprint's version 19; witness rows pin values — `test_native_host_hash_extension`, `test_native_lean_path`, `test_native_match_hash_witness`, `test_native_continuation_view`, - `test_adapter_quiet_bar`, `test_publication_witness` among them. Two - limits: the native continuation hash folds the resolved timezone's - resource digest, so a tzdata release that rewrites a zone moves the value of - a run in that zone (`test_native_report_truth` states why it pins no raw - continuation value), and no row pins a `strategy_stream_state_hash` value - directly. + `test_adapter_quiet_bar`, `test_publication_witness` among them. Two limits: + the native continuation hash folds the resolved timezone's resource digest, + so a tzdata release that rewrites a zone moves the value of a run in that + zone (`test_native_report_truth` states why it pins no raw continuation + value), and no row pins a `strategy_stream_state_hash` value directly. ## The 1.0 C-surface boundary @@ -158,22 +167,22 @@ COVERAGE block, a named `ENUM_TWINS` exclusion, or a `C_V1_EXCLUSIONS` row of neither twinned to its kernel enumeration nor declared C-only, when a `C_V1_EXCLUSIONS` row's C++ declaration goes or its C spelling appears, and when that table cites a `C_V1_EXCLUSIONS` row once too few or too many. -Four of its rows are planned for 1.1.0: a non-mutating execution preview, the -origin and label of an applied event, a closed-trade entry-comment accessor -and a replace-options word. Nothing in 1.0 promises C and C++ parity beyond -the fields and calls the C surface declares. +Four of its rows were planned for 1.1.0, which does not include them: a +non-mutating execution preview, the origin and label of an applied event, a +closed-trade entry-comment accessor and a replace-options word. Nothing in 1.0 +promises C and C++ parity beyond the fields and calls the C surface declares. ## Pairing with codegen - **From 1.0.0 the engine and the codegen share one version number, and the only supported pair is the same `X.Y.Z`, prerelease included:** engine `v1.0.0-rc.1` with codegen `1.0.0-rc.1` (PyPI spells it `1.0.0rc1`), engine - `v1.0.0` with codegen `1.0.0`, engine `v1.0.1` with codegen `1.0.1`. Any other - pair is unsupported: a release candidate with its final release, two minors, - or two builds that agree only on `PF_ABI_VERSION`. Generated strategy code - compiles against the engine's internal C++ headers, which the C ABI does not - cover and the script ABI checks above version (@ref abi_stability, "What's - *not* guaranteed"). + `v1.0.0` with codegen `1.0.0`, engine `v1.0.1` with codegen `1.0.1`, engine + `v1.1.0` with codegen `1.1.0`. Any other pair is unsupported: a release + candidate with its final release, two minors, or two builds that agree only + on `PF_ABI_VERSION`. Generated strategy code compiles against the engine's + internal C++ headers, which the C ABI does not cover and the script ABI + checks above version (@ref abi_stability, "What's *not* guaranteed"). Regenerate the C++ and relink the strategy library on every pair change. - **The release hub enforces it.** `release.yml` dispatches `engine-release` to pineforge-release with `client_payload` `{version: "vX.Y.Z[-rc.N]", diff --git a/docs/pages/streaming.md b/docs/pages/streaming.md index c2a858c1..8e7b1cf2 100644 --- a/docs/pages/streaming.md +++ b/docs/pages/streaming.md @@ -212,8 +212,8 @@ separate surfaces and are not implied by using this lifecycle. the first realtime bar, so its live results can differ from a backtest of the same bars. Batch backtests are not affected. Workaround: run the stream with a script timeframe larger than the input timeframe (for example input - `1`, script `5`), or use the batch backtest. **Fixed on main (#325); included in - the next release.** This change feeds each newly observed confirmed bar to the + `1`, script `5`), or use the batch backtest. **Fixed in 1.1.0 (#325).** This + change feeds each newly observed confirmed bar to the requested-series evaluator, including equal-timeframe and Heikin-Ashi requests. See [Lifecycle](@ref lifecycle) for handle ownership and