Repository navigation
Description
Summary
When the input bars are finer than an N-day script timeframe (input D or 240, script 2D, 3D or 5D), the engine builds the chart bars itself. Two things then differ from passing N-day bars directly:
last_bar_indexis 186 on every bar, while the last chart bar'sbar_indexis 61 (3D), 93 (2D) or 37 (5D); the run has 188 input days.barstate.islastis never true. The position still open at the end has no row in the trade list:net_profitis the sum of closed trades, while the last equity point includes the open position.- The N-day bars fall on a grid counted from 1970-01-01. Around the new year the 3D bars open on 2023-12-25, 12-28, 12-31, 2024-01-03 and 01-06, so one bar spans the year boundary. The engine's own
request.security(syminfo.tickerid, "3D", time)on a daily chart restarts on 1 January (2023-12-24, 12-27, 12-30, 2024-01-01, 01-04, 01-07; the 12-30 bar is two days long), whichsrc/source/multi_day_periods.hppdescribes as TradingView's rule, and TradingView's 3D chart of BINANCE:BTCUSDT does the same. So the same script gives different trades depending on whether the host passes 3D bars or finer bars.2Dand5Dshow the same 1970 grid (5D: 2023-12-24, 12-29, 2024-01-03).
Input D with script W, monthly from daily, and input = script = 3D behave as expected.
Versions
pineforge-engine v1.11.0 (a4472324) with pineforge-codegen 1.11.0, and v1.10.0 (59f98ba8) with Codegen 1.10.0: identical results on both. Apple clang 17.0.0, macOS 15.8 arm64. BTCUSDT daily bars from 2023-12-01 to 2024-06-05 (188 bars; the 4h run uses 1,123 4h bars over the same dates; the 3D / 3D run uses 63 3D bars of the same data that restart on 1 January, opening 2023-12-03 to 2024-06-05, the first bucket with only 12-01 and 12-02 left out), initial capital 10000, no commission or slippage, run_backtest_full_checked with bar_magnifier = 0. Values come from // @pf-trace and the run report.
TradingView: BINANCE:BTCUSDT, 3D, Deep Backtesting from 2023-12-01 to 2024-06-05, measured on 2026-11-10.
Reproduction
//@version=6
strategy("3D chart from daily bars", overlay = true, initial_capital = 10000, default_qty_type = strategy.percent_of_equity, default_qty_value = 10)
fast = ta.ema(close, 3)
slow = ta.ema(close, 8)
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.entry("Short", strategy.short)
last_index = last_bar_index
is_last = barstate.islast ? 1 : 0
bar_open = time
// @pf-trace last_index=last_index
// @pf-trace is_last=is_last
// @pf-trace bar_open=bar_open
input_tf / script_tf |
chart bars | last bar_index |
last_bar_index |
barstate.islast on the last bar |
trade list | net_profit / last equity |
|---|---|---|---|---|---|---|
D / 3D |
62 | 61 | 186 | false | 5 closed, no open row | 331.05 / 10387.63 |
240 / 3D |
62 | 61 | 186 | false | 5 closed, no open row | 331.05 / 10387.63 |
D / 2D |
94 | 93 | 186 | false | 9 closed, no open row | 95.17 / 10186.03 |
D / 5D |
38 | 37 | 186 | false | 3 closed, no open row | 283.14 / 10297.20 |
D / W |
27 | 26 | 26 | true | 2 closed + 1 open | 385.78 / 10385.78 |
3D / 3D |
63 | 62 | 62 | true | 4 closed + 1 open | 498.08 / 10498.08 |
Entries (date, side):
| run | 3D bar opens around the new year | entries |
|---|---|---|
PineForge D / 3D |
2023-12-25, 12-28, 12-31, 2024-01-03, 01-06 | 01-15 Short, 02-02 Long, 02-05 Short, 02-08 Long, 04-14 Short, 05-17 Long |
PineForge 3D / 3D |
2023-12-24, 12-27, 12-30, 2024-01-01, 01-04, 01-07 | 01-07 Long, 01-16 Short, 01-31 Long, 04-15 Short, 05-18 Long |
| TradingView, 3D chart | — | 01-07 Long, 01-16 Short, 01-31 Long, 04-15 Short, 05-18 Long (still open at the end) |
Each TradingView entry date is day 1 + 3k of 2024. In the D / 3D run, the Long opened on 2024-05-17 is still open on the last chart bar but has no row in the trade list; it counts only in equity (10387.63 − 10331.05 = 56.58).
The request.security grid, with input = script = D:
//@version=6
strategy("3D bars requested from a daily chart", overlay = true, initial_capital = 10000)
requested_open = request.security(syminfo.tickerid, "3D", time)
// @pf-trace requested_open=requested_open
From a read of the source, the count of expected script bars in PineScheduler::run_begin (src/source/pine_scheduler_native.cpp) comes out near the number of input days for these timeframes, so the run never reaches the bar it treats as last. The 2D run's last chart bar (2024-06-04, covering 06-04 and 06-05) is complete, so this is not the unfinished last bucket that is skipped on purpose.
Expected
last_bar_index equals the last chart bar's bar_index, barstate.islast is true on it, and the open position is in the trade list. N-day chart bars built from finer input restart on 1 January, like the engine's request.security N-day bars and TradingView's chart, so passing daily bars or 3D bars gives the same trades.
Workaround
Aggregate the input to N-day bars in the host, restarting on 1 January, and pass input = script timeframe. With the bar magnifier this loses the finer path.
Activity
luisleo526 commentedon Nov 10, 2026
Thank you for the detailed report and the reproduction script.
We are reproducing this on the released 1.11.0 and 1.10.0 builds. We are checking
last_bar_index/barstate.islastand the missing open-trade row when N-day bars are built from finer input bars. We are also checking the N-day bucket grid against TradingView's restart on 1 January. We will post what we find here, including which releases are affected.luisleo526 commentedon Nov 10, 2026
Confirmed: a silent wrong value in every release from 1.0.0 to 1.11.0, all four points. We measured it on the release builds and against TradingView's own 2D, 3D and 5D charts of BINANCE:BTCUSDT:
last_bar_indexandbarstate.islastfollow the input days, not the chart bars.Daily to weekly and daily to daily behave correctly. The causes are found (the timeframe-period lookup and the N-day bucket key). A fix is being prepared, and we will post here which release carries it.
Build an N-day chart on the year-restart N-day grid (#829)
Floor an explicit close quantity to the quantity step (#839)
Engine train 1: CI rounds under 15 minutes, and five fixes (#850)
luisleo526 commentedon Nov 13, 2026
Status 2026-11-13: the case of an N-day chart built from DAILY input bars is fixed on main (merged today) and ships in 1.13.0 (planned 2026-11-15). N-day charts built from intraday input bars are not fixed yet; their date is posted here by 2026-11-14.
🤖 Generated with Claude Code
luisleo526 commentedon Nov 14, 2026
Status 2026-11-14: a fix is in progress and targeted for PineForge 1.13.0 (merge cut-off 2026-11-15, release 2026-11-16). This issue closes when the fix merges. If it misses 1.13.0, we post a correction here the same day.
luisleo526 commentedon Nov 15, 2026
Correction 2026-11-15 (UTC+8): the fix for this issue will NOT be in PineForge 1.13.0.
The fix is in progress, but it has not passed verification yet, and we do not ship it before it does.
We do not have a new date yet; we will post one here when a verification run has measured it, and the merge commit when the fix lands.