fix(engine): margin-call intrabar chronology + percentrank length denominator - #149
Merged
Conversation
…ced exits TradingView places the forced-liquidation event chronologically on the synthesized intrabar path. When a priced exit of the live position fills on a bar whose adverse extreme comes strictly earlier on that path (the engine's own bar_path_uses_high_first proximity rule) than the exit's fill, and the pre-fill position is already in margin deficit at that extreme, TV slices FIRST (the ordinary floor-before-4x nibble, filled at the extreme, tagged "Margin call") and the exit then closes the reduced remainder. The engine ran process_margin_call once AFTER all order processing, so a same-bar full exit hid the deficit (FLAT early-return) and the event was lost. The fix hooks the process_pending_orders fill loop immediately before a path-resolved priced exit is applied: (a) no margin call booked on this bar yet, (b) adverse extreme strictly earlier on the path than the exit fill (a tie keeps the exit first), (c) pre-fill deficit at the extreme via the existing fee-net eq/req arithmetic. The slice mirrors the adverse-cascade trigger/slice arithmetic byte-for-byte, re-freezes default-sized market orders, and marks the bar so the end-of-bar process_margin_call does not double-liquidate the survivor (TV's one-nibble-per-bar cascade). Confirmed trigger/slice rules are untouched; trail fills, the magnifier, and the COOF scheduler stay outside the hook. Derivation (Lab finding 308, rhyme17 whole-tape per-position replay): 3/3 TP-exit adverse-first deficit bars produce TV's slices bit-exact (0.0084 / 0.0044 / 0.0384); both LOW-first large-deficit bars and 157/158 SL-stop deficit bars stay quiet under the chronology condition. Tape validation: the 2025-10-11 20:45 slice books 0.0084@3721.62 with the remainder 2.5021@3664.69 (TV rows 1586-1588 aligned), the 2025-10-12 03:30 sizing flips back to TV's exact 2.5073, and the canonical rubric's PnL p90 collapses 4.9634% -> 0.0060% (matched 2056 -> 2079, unmatched 46 -> 24) with the pre-divergence tail bit-identical. Full corpus tiers unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PercentRank::compute and ::recompute ranked the current bar against the
non-na values in the lookback but divided by that non-na count (the
PineTS ta.percentrank model). TradingView divides by LENGTH always, even
in the partial (na-lead) warmup window, so any window containing na
priors with count > 0 came out inflated.
Evidence (Lab finding 315): trendmatrix pair verified byte-exact against
TV tapes with the length denominator — 100.0/0/0. The na gates, the
valid==0 corner (still na), the 1e-10 fixed comparison band, and the
na-skip numerator are all unchanged; only the denominator moves.
Tests: na-history expectation updated 100 -> 50 (2 of 4 slots <= current,
denominator 4), plus a new pin asserting the partial-window denominator
stays LENGTH (lookback {na,na,na,10}, current 20 -> 25, never 100).
Verification: full build (cmake -j4), ctest 125/125 passed, corpus sweep
ran 312 strategies ok=312 fail=0, all 312 engine tapes byte-identical to
the checked-in corpus baseline (b5d53d2), tiers excellent=307 strong=4
anomaly=1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
luisleo526
added a commit
that referenced
this pull request
Aug 12, 2026
…lined reversals + 1x-long entry-fill margin chronology (#150) * factorial: extrema-positional-stoch-zerorange [engine] * fix(engine): exit-bracket lifecycle across declined in-position reversals A declined in-position opposite MARKET reversal (the KI-54/KI-72 fill re-check declines — the tradeless reversal) cancels the live position's standing PRICED strategy.exit brackets on TradingView. The engine kept the original bracket live and stop-filled early, forking position state for days on every tradeless opposite signal. - KILL: the decline marks the position's standing priced brackets dormant — never the "__close__" close/close_all family, never stale exits bound to a not-yet-filled entry id (the #147 stale-exit family). - DORMANT: a dormant bracket stays in the book but never matches a fill (classify_order_eligibility Skip in the ordinary kernel; an apply-time mirror in the KI-60 COOF kernel, whose candidate set is pre-classified before any candidate is applied, so a mid-segment kill is invisible to classify there). - REVIVE-A: a fresh same-(id,from_entry) strategy.exit re-issue replaces the dormant bracket wholesale and arms the new call's prices (the ordinary replacement path — no new code). - REVIVE-B: a margin-call partial re-registers the surviving position's dormant brackets at their last-armed prices. - MC-CASCADE: when the margin-call event price already makes a revived full-percent default stop marketable, the entire remainder closes at that event price through the bracket's id on the slice bar. Derivation: 162/162 alive-at-breach episodes, 118/118 TV stop-skips, 19/19 revive-B exact-stop fills, 18/18 cascade fills at the event extreme; tape validation collapses the count mismatch to 0 with the whole suite green and the corpus byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(engine): 1x-long opening-affordability check runs at the entry fill, before same-bar intrabar exits TradingView evaluates the margin_long=100 opening-affordability check AT THE ENTRY FILL, chronologically before the same bar's intrabar exits. The #149 chronology hook (margin_call_slice_before_priced_exit) deliberately excluded 1x longs — compute_liquidation_price() is na there — so a same-bar priced exit filled the FULL position first and the end-of-bar one-shot opening event found the position already reduced or gone: the "Margin call" trim row (ordinary floor-before-4x restore, including the sub-lot one-contract fallback, filled at the RAW matched entry base — a pnl-0 row) was lost, and the equity fork cascaded through every later default-sized fill. The hook now routes the 1x-long class to an opening-slice helper that books the trim with process_margin_call's opening-affordability LONG branch arithmetic verbatim, then lets the triggering exit close the reduced remainder. The one-shot event is consumed only when a slice is actually booked. Unchanged byte-for-byte: bars where no same-bar priced exit fills (end-of-bar placement), POOC close fills, the scoped SHORT opening event (end-of-bar plus adverse-retry), the leveraged adverse-extreme chronology class, and every no-deficit evaluation. The deficit class: a lot-floored percent=100 reversal admitted on an uptick inside its floor remainder overshoots post-close equity by tick*(qty+closed) - remainder (sub-lot -> one-contract fallback); a commissioned explicit open reaches the same discontinuity through its entry fee. Tape validation collapses the count mismatch (the pure cascade family) to 0 with the whole suite green and the corpus byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: PineForge Factorial <factorial@pineforge.invalid> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Gate
pr-gatePASS — engine corpus zero regressions, scraped entering excellent+strong >= leaving.Verdict:
/Users/haoliangwen/code/pineforge-lab/pr-gate-verdict.json🤖 Generated with Claude Code