Skip to content

calc_on_order_fills: the script runs again after the bar points with fills - #433

Merged
alexgrover merged 1 commit into
devfrom
feature/calc-on-order-fills
Oct 14, 2026
Merged

alexgrover merged 1 commit into
devfrom
feature/calc-on-order-fills

Conversation

@alexgrover

@alexgrover alexgrover commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

strategy(calc_on_order_fills = true) was accepted and ignored. This implements it for historical bars, from seven TradingView probes that log every execution (BINANCE:BTCUSDT 1h, Pine v6) plus controlled case 25.

What TradingView does

  • Fill points: the broker walks the bar point by point: open → nearer extreme → farther extreme → close. A fill between two points belongs to the later one.
  • Extra runs: after each point with fills (other than the close), the script runs again. The run after a fill at the close is the bar's normal run.
  • What a run sees: the complete bar (final OHLC, barstate.isconfirmed true), with the broker state at that point.
  • Orders placed in an extra run: a market order fills at that point's price; limit / stop / exit orders work on the rest of the path, and stay pending if not reached.
  • Variables and outputs: var is rolled back between the runs of a bar; plots come from the last run.
  • No extra run: fills at the close (process_orders_on_close) and margin calls.

Changes

  • Bar loop (PineTS._processBarWithOrderFills): for such strategies, each path segment is given to the broker as a bar of its own, opening at the segment's start. After a segment with fills, the script runs again. Its orders are kept and work from that point on. Its plots, drawings and variable changes are discarded. Strategies without the setting take the unchanged path (the broker phases moved into processBarOrders).
  • strategy.order: an order with the id of one still pending from an earlier bar modifies it instead of adding another. Limit / stop levels snap to the tick grid away from the market, as strategy.entry does. In a run after a fill, "the market" is the fill point's price.
  • Repeated runs of one bar:
    • strategy.exit's persistent-call detection compares with the previous bar;
    • the ta.cross* call-id tracking (barState) no longer treats a second run of a bar as a call id shared by two call sites.

Known limit: varip is still treated as var, so it is rolled back too. Arrays, maps and matrices mutated in an extra run are not rolled back.

Tests

tests/namespaces/strategy/calc-on-order-fills.test.ts (6 tests):

  • a market order after a fill at the open fills at that open;
  • after a mid-segment limit fill, a close fills at the segment's end point;
  • a limit placed after a fill and not reached stays pending;
  • var is rolled back and plots are not duplicated;
  • strategy.order modifies a pending order with the same id;
  • strategy.order limit levels are tick-rounded.

4 fail on dev; the other two guard existing behavior.

Results against TradingView (compared with dev)

Set dev This PR
Case 25 trade 4 identical
Probes cof01–cof07 1 / 7 identical 7 / 7 identical
Controlled + probes 157 / 201 identical 164 / 201 identical
Public strategies 24 identical 25 identical (ict-10am-first-fvg)
  • vwap-reversal now has TradingView's trade count (108; dev 103). Its first difference is an unrelated commission rounding.
  • Premium backtesters: no change.
  • No run gets worse.
  • Unit suite: all committed tests pass. Oracle suite: 0 regressions.

Note

High Risk
Touches core strategy bar execution, order filling, var/plot rollback, and TA state across multiple re-runs per bar; incorrect ordering could change backtest results broadly.

Overview
Implements strategy(calc_on_order_fills = true) for historical bars so the broker walks each bar along TradingView’s open → nearer extreme → farther extreme → close path, and re-runs the script after intra-bar fills (except at the close). Mid-bar runs see full OHLC with broker state at the fill point; market orders fill at that price, limit/stop work on the remaining path, and plots, drawings, and var changes from those runs are discarded (final bar run wins).

The bar loop adds _processBarWithOrderFills; default strategies still use the same broker phases via new processBarOrders. riskAfterFill increments _fillCount to detect fill points; barPath is exported for segment simulation.

strategy.entry / strategy.order snap limit/stop using _fillPointPrice during COF runs. strategy.order also replaces same-id pending orders from earlier bars and applies mintick rounding like entry. strategy.exit persistent-call detection ignores same-bar re-executions. ta na-aware state keys off _execTick so a second COF run on one bar is not treated as a duplicate call site.

Adds calc-on-order-fills.test.ts covering same-bar fills after entries, segment closes, pending limits, var/plot rollback, and order id replacement.

Reviewed by Cursor Bugbot for commit 1dcf470. Bugbot is set up for automated code reviews on this repo. Configure here.

…fills

strategy(calc_on_order_fills = true) was accepted and ignored. On
TradingView's historical bars the broker walks the bar point by point
(open, nearer extreme, farther extreme, close; a fill between two points
belongs to the later one) and the script runs again after each point
with fills, other than the close (whose run is the bar's normal run):
- that run sees the complete bar, with the broker state at that point;
- its market orders fill at that point's price, its limit / stop / exit
  orders work on the rest of the path;
- var is rolled back between the runs of a bar; plots come from the last.
Fills at the close (process_orders_on_close) and margin calls do not
trigger a run.

For such strategies each path segment is given to the broker as a bar of
its own. Strategies without the setting take the unchanged path.

Also:
- strategy.order with the id of an order pending from an earlier bar
  modifies it instead of adding another, and snaps its limit / stop to
  the tick grid away from the market (as strategy.entry does); in a run
  after a fill the market is the fill point's price;
- strategy.exit's persistent-call detection and the ta.cross* call-id
  tracking compare with the previous bar, not an earlier run of the same
  bar.

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Oct 14, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 397aa898-1346-4036-b5a9-5a530c79dd5a)

@alexgrover
alexgrover merged commit 97a7ae6 into dev Oct 14, 2026
2 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant