Repository navigation
Pine adapter: limit reach, exit binding, carried trail, margin-call schedule - #341
Merged
Merged
Conversation
…-built bar Under calc_on_order_fills an on-grid exit limit used to rest at its raw level, so a 9.73 sell limit born in the opening fill's recalculation missed a bar whose high of 9.725 prints 9.73. TradingView fills it on that bar (tests/fixtures/callback_lifecycle newborn-limit-cancel, -owner-absent, -replace and -rounded, NYSE:F 15m, 4 identical exports each). exit_limit_trigger now rests such a limit at its tick-built threshold when it closes the position held when it is placed, on the chart path, and its placement point does not already reach it. Everywhere else the on-grid level stays raw, as before: - a leg placed for a parent not held on its side: its threshold would sit on the parent's side, and a settlement booked at the source level then lands outside the immutable trigger (MatchRejected InvalidTerms); - a leg its placement point already reaches: for a point that stands on the raw level, the matcher books the level at that point, while a passed threshold waits for the next point. A point that is a fill booked at the print of a half-tick-short open is not on the raw path: the raw level is then never reached, while TradingView fills at once (repeated-rounded, TradingView trades 18-19, recorded as a residual); - a magnifier's intrabars, as for the in-flight reach. These three exclusions are engine limits, not TradingView rules. The rule without them, every on-grid calc_on_order_fills limit at its threshold, moved closed-trade fills in the frozen witness tables below, so it was narrowed to the scope where no closed trade moves. The rule has its own test-only switch, RestingLimitTickReach (on). test_callback_lifecycle_tapes: 70 of 87 tapes equal TradingView row for row, 17 known divergences; clearing the switch moves exactly the four newborn-limit tapes and repeated-rounded's exit bar; the tapes the rule decides are replayed forward and a stream refuses each (calc_on_order_fills is unsupported). Four witness tables re-harvested with their own harvest switches, on the owner's approval of 2026-10-05, given on the premise that no closed trade moves (the same harvest against main reproduces every old value): publication 2 of 156 runs, quiet bar 14 of 276 rows, live state 9 of 108 transcripts, continuation view 2 of 10 k_coof reads. Every closed trade keeps every fill and money field in every run-pass; the moves are the hashed trigger price, and CalcOnFills' entry_incarnation renumbering. Doc citations re-anchored for the moved adapter lines. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…or to the pending entry id TradingView binds a strategy.exit(id, from_entry = X) when the script calls it: to X's open lots if X holds any, else to the id X while an order of X is working, else the call is ignored. An exit bound to the id survives a close, close_all, the flat and a cancel and re-entry of X, and binds to X's next fill (36 synthetic controls, two byte-identical exports each, and the ten pending-* tapes of tests/fixtures/global_exit_children). Each part has its own switch in ExitBindingRuleSwitches, all on: - pending_bound_exit_survives_flat: an exit called in position for an id with no lot but a limit or stop order working is bound to the id (PlacementSnapshot::pending_bound_exit, hashed while set, cleared by the id's fill). retire_in_position_exits_at_flat and cancel_exit_orders_for_full_close leave it; a strategy.cancel of the id's order keeps the call (id_bound_exits_, hashed while non-empty) and the id's next entry order re-arms it. - global_exit_binds_working_entries: a global exit called flat waits for the fill of the limit and stop entries working instead of ending on the flat book. - resting_stop_entry_survives_close: under process_orders_on_close an earlier bar's stop entry survives a close's flat, as a limit does. - priced_add_at_cap_not_placed: under process_orders_on_close a priced add of an id holding no lot, still at the pyramiding cap once its bar's closes are done, leaves the book at the next opening; each add is judged at that one opening. Every part acts only with margin requirements off (margin_long = margin_short = 0) and without calc_on_order_fills, the tapes' setting; the two exit parts on whole exits at absolute levels whose parent rests at a level, the stop-entry and cap parts under process_orders_on_close. Inside these gates the parts also change shapes no tape covers, as the pin's reference model predicts them: a parent on the other side of the position, a strategy.order parent, a market re-entry after the cancel, a cancel and re-entry on the exit's own bar, a short-side cap and a cap above 1. Open edges without a tape: a stop-limit entry, which the stop part keeps; a global exit called flat without process_orders_on_close, which also waits, and its taking by another id's first fill; an add at the cap marketable at its own close, which fills there before the cap part judges it, as before; an add whose own bar's close frees the slot, which stays, as before (the pin's model rejects it at the call). Every witness table keeps its pins. tests/test_exit_binding_tapes asserts all 36 controls, each part's tapes with the part off, the engine before the rule with every part off, and backtest == forward stream on every control both ways. The ten pending-* tapes are asserted. Doc anchors re-anchored. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…rder Two TradingView rules, each behind its own default-on, test-only switch. Carried trail tick reach (PineCallbackLifecycleRule::CarriedTrailTickReach). With calc_on_order_fills off, a trailing stop carried from an earlier bar is reached where the bar's tick-built print reaches it; the level stays the raw running best +/- the offset, as a static stop's does. The kernel's generic Trail compares the raw path with the raw level, so on_bar_open walks the bar as the kernel will and, only where the tick-built point comes before the raw compare's, re-prices the trail's distance for that bar (ride and handle kept); on_bar_close_before_script restores it. A raw reach whose tick-built print falls back inside the stop stays the kernel's, as before: no tape decides that direction. Tape: tests/fixtures/callback_lifecycle/ carried-trail-14 (NYSE:F, 14 ticks behind a 10.345 best, the 10.485 high prints 10.49 and exits at 17:45, not 18:15); it leaves known_divergences.json and pins the switch in rule_off_departures.json. test_callback_lifecycle_tapes also replays it as a bar-by-bar stream with 1 and 30 warm-up bars: the stream books the backtest's trades and TradingView's rows, and with the switch off both depart from TradingView the same way. The walk's copy of the kernel's trailing-stop level is compat::pine::kernel_trail_stop_level (include/pineforge/compat/pine/ trail_ticks.hpp, header-only). test_kernel_trail_stop_replica holds it, bit for bit, to native_matching::checked_trail_stop on every best a trail moves to on the tape's bars, ladder bests in both spellings on four price ticks, half-tick and off-grid bests, and whole-tick and fractional distances (45,057 levels). The unit includes a source-layer header, so a kernel-only build skips it. Trailing exits in the point order (MarginRuleSwitches::point_order_trailing_exits). A stop or limit leg of a strategy.exit that also carries trail_points, trail_offset or trail_price counts as a protective exit at the open, like any other: the gapped stop fills before the opening margin check. Tapes (lab tv --no-note, 3 byte-identical exports each, predictions written first): tests/fixtures/admission_rules/point_order_and_book/ gapstop-percent-trail-points and -trail-offset, c2's script with trail_points (and a trail_offset) on the exit; TradingView books c2's rows (112 call, 8744 at the 12.26 gap). No kernel, grader or codegen change; no stream gate. The new adapter state (the trails re-priced for the bar in flight) is hashed only while set. Docs: switch table and evidence counts, the callback-lifecycle README, the row on per-kind tick quantization; doc anchors re-anchored (digit-only). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…th, lagged follow-ups, pending vetoes, frozen reversal closes, adds at the signal close, long-call G + L money TradingView's margin-call schedule rules, each behind its own default-on, test-only switch (detail::MarginScheduleSwitches, appended at the header's end); adapter only, no kernel, grader or codegen change, no stream gate. - short_call_gate: a short's call of X units at mark p is taken only where X p' m > Q p' m - E(p), p' its slipped print (source_margin_units); the one-unit band is its one-unit case. An opening checkpoint at a fill keeps the earlier rules, and so does the repeat at one price: a process_orders_on_close short's open call repeated at its own fill (recheck_at_fill), a follow-up the pin calls ungated, is sized ungated (submit_margin_call_slice at an already-resolved price). - short_path_points: a carried process_orders_on_close short (commissioned or slipped, nothing resting) is checked at both extremes and the close before the script, not at its high alone (walk_short_path_points). It is ablated together with close_call_follow_up_at_open: each corrects its own bars, and with one off the other's equity error moves a later open call. - lagged_short_follow_up: after a short's call, the lot-by-lot check at its fill with the called units out and unbooked; the last still-short check's restore, four times, at the bar's next path point, ungated (fractional lot grids; outside process_orders_on_close only where margin_follow_up_units does not already follow the call, pinned there by lag/outside-pooc-close and lag/outside-pooc-extreme). - pending_veto_first: a deficit the open's check vetoed is checked at the first path point whose segment touches a resting whole exit, before it; after a call there the exit fills at that point's print. It stands down unless that exit, with the other leg of its strategy.exit, is the book's one resting order, the shape its tapes pin. - frozen_reversal_close: a reversal entry placed at a close where a margin call is booked after the script closes the quantity the script saw and opens the excess on the other side (resolve_terms). - add_signal_close: a same-side add's whole-book requirement at the tick-built signal close (validate_precommit), at margin 100 only. - whole_share_lagged_follow_up: a long's lagged follow-up on whole-share grids too (lagged_margin_follow_up_units). - long_call_gain_loss: a commission-free long's one-unit call reads initial + (G + L) inside gain_loss_regime(); fee-bearing books keep the closed-trade equity (no tape pins them). - close_call_follow_up_at_open: a process_orders_on_close short's call sized at the previous close and executed at the open is followed there once, at its own fill: four times the lot-floored shortfall, or one unit under one lot of it (margin_follow_up_units). New durable state (a follow-up owed at a path point, a close's after-script call) is folded into the adapter state hash only while set. Tapes: the 67 short-cutoff-gate tapes of tests/fixtures/margin_call_rules are asserted now (244/266 match; initial/short-s5-minus01, schedule-q9p1305-s5, -s6 and literals/literal-21 leave the known list), and tests/fixtures/margin_schedule_rules holds 39 synthetic controls (each exported twice, byte-identical): 35 match, 4 are listed; every tape also replays as a stream with identical closed trades, and three mechanism cases on synthetic or patched bars reach the branches no tape does (the walk's close call owing the next open, the pending veto on the open's segment and beside a resting entry). test_margin_open_print_tapes asserts its three tapes to their last bar (443, 445 and 667 trades). test_margin_rules_forward_replay samples four more tapes. Docs: switch table and evidence counts in docs/pine-adapter-kernel-notes.md; doc anchors re-anchored (digit-only). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
|
||
| class TapeStrategy(Strategy): | ||
| def __init__(self, lib, prefix): # noqa: super().__init__ loads a path | ||
| self.lib = TapeEntryPoints(lib, prefix) | ||
| _check_abi(self.lib) | ||
| self._setup_signatures() | ||
|
|
||
| class StreamStrategy(Strategy): |
This was referenced Oct 5, 2026
luisleo526
added a commit
that referenced
this pull request
Oct 6, 2026
* docs: release notes and version scoping for v1.3.0 CHANGELOG 1.3.0: confirmed-bar admission in pineforge-live (#342), the Pine adapter changes of #341, #345 and #347, tests and docs (#343, #344); no report key changes; the state-hash recipe additions of #341 and #347, domain tags and the v19 epoch unchanged; migration. Version scoping: README, install.md and public-contract.md name v1.3.0, its tarballs, the engine1.3.0-codegen1.3.0 image and the 1.3.0 pair. The confirmed-bar receipt and its admission, marked unreleased after 1.2.0 by #342, ship in 1.3.0 (README, strategy-capabilities.md, runner/README.md). Codegen license lines (README, LEGAL.md, docs/pages/index.md): the PineForge Source License 1.2 from codegen 1.3.0; 1.2.0 keeps 1.1, releases up to 1.1.0 the PolyForm Noncommercial terms. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * docs: release 1.3.0's grades in the README and the changelog, from the facts tokens The README's release sentence moves to the releases[1.3.0] tokens, and its main-scoreboard lines re-render the values defe41f (#343) rendered at pineforge-release 3e39d64, and the 1.3.0 changelog says which registry baseline grades the release and why that baseline is the release's code, all rendered from pineforge-release facts/facts.json at ff21de0 (#32). The changelog sentence extends the last line of the "What a script author sees" bullet that 0e1ced7 added. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Four Pine adapter rules, each pinned by synthetic TradingView controls with the predictions written before export and 0 counterexamples. Each sits behind its own internal test-only switch, default on. With every switch off, the engine is identical to main byte for byte over the whole suite.
A resting
calc_on_order_fillslimit reaches on its tick-built threshold. An on-grid COOF limit rests at its tick-built threshold only when three things hold:It fixes the four newborn-limit tapes. With the owner's approval (2026-10-05), four frozen witness tables were re-harvested on the premise that no closed trade moves. The unrestricted rule did move witness fills, so the rule was narrowed to the scope where none moves. The three exclusions are engine limits, not TradingView rules. In 21-field per-trade dumps, the re-harvested tables show 0 fill moves: hash-only changes, plus
entry_incarnationrenumbering in one calc-on-fills battery.strategy.exitbinds at its call. It binds to its entry's open lots if there are any; else to the entry id while that id has a working entry order. That binding survivesclose_all, the close of a sibling, flats and reversals. An add called at the pyramiding cap is not placed. Scope: whole exits at absolute levels with a limit/stop parent and no COOF, with margins off, as the TradingView evidence covers. The 36 controls and the 10 pending-entry tapes are asserted.The carried trail is reached on the tick-built print, and the level stays raw. This applies only where the tick-built print reaches first, the direction TradingView shows. Separately, the point order counts the stop/limit legs of exits that also trail.
The margin-call schedule. It has six parts:
units·p'·m > held·p'·m − equity, with p' the slipped print;It also prices an add at the signal's tick-built close against fee-charged equity, and books the whole-share-grid follow-up. In ablation,
short_path_pointsis meant to be switched together with the close-call follow-up.Effect on the population
One parity measurement of this exact tree, full population, paired with codegen main:
Evidence in the tree
Verification
🤖 Generated with Claude Code