Skip to content

fills: nearest-tick rounding of raw bar prices (TradingView fill rule) - #163

Merged
luisleo526 merged 1 commit into
mainfrom
fix/tv-fill-nearest-tick-ship
Aug 24, 2026
Merged

luisleo526 merged 1 commit into
mainfrom
fix/tv-fill-nearest-tick-ship

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

Fills taken at a raw bar price are rounded to the nearest tick the way TradingView does it: floor(price / mintick + 0.5) * mintick evaluated in double (lab finding 446/449). TradingView's price series carry sub-tick prints (NASDAQ:AAPL has x.xx5 and a few 4-dp values in ~5% of cells); only the fill is on the tick, and the rounding is a pure function of the double — 24,582/24,582 half-cent dump fills reproduce, including the 2,460 that round DOWN at binary midpoints (228.765/0.01 = 22876.4999…). The feed is left untouched because indicators consume the raw values.

round_to_mintick is now that function; a new bar_fill_price() applies it at fill resolution (before slippage ticks) at every raw-bar-price site — market fills at close/open, open-gap admits, margin-call slice prices, POOC exits, stop/limit fills that execute at the open or at a path point. round_to_mintick_directional is kept for computed stop/limit levels only. An earlier attempt that quantized the feed with a +1e-6 epsilon regressed 43 exact AAPL strategies (finding 444); this one does not.

Evidence: NASDAQ:AAPL population excellent 235 → 250, e+s 307 → 318 (lab finding 450); OANDA:EURUSD byte-identical (feed on-grid); ETH scraped 396/396 and corpus 309/2/1 unchanged (promote-fill-v1). tests/test_tv_fill_rounding.cpp embeds all 1,213 distinct midpoint-down census values; ctest 137/137.

@luisleo526
luisleo526 merged commit 7fc7347 into main Aug 24, 2026
7 checks passed
@luisleo526
luisleo526 deleted the fix/tv-fill-nearest-tick-ship branch August 24, 2026 19:17
luisleo526 added a commit that referenced this pull request Oct 12, 2026
… private fixtures (#375)

Squash of #375 (one commit on b802cee = v1.5.0; tree 18d3b6f). Its commit message follows verbatim.

tests: the ten test files that embed US-equity price data are private…

… rows (Form B)

Ten files leave the public tree for pineforge-private-fixtures (byte-exact
copies, commit 5abcf8a6): tests/test_ta_series_length_data.hpp,
test_ta_series_length_extremes.cpp, test_ta_series_length_supertrend.cpp,
test_ta_simple_length.cpp, test_ta_window_underapplied_data.hpp,
test_ta_window_underapplied.cpp, test_ta_window_round10_data.hpp,
test_ta_window_round10.cpp, test_tv_fill_rounding.cpp,
test_tv_fill_rounding_l4d.cpp. Their data headers and tables hold NYSE:F 15m
bars, NASDAQ:AAPL closes and TradingView indicator values on NYSE:F@15.

Six rows become private rows registered the #371 way (the real test when the
overlay supplies the source, a SKIP placeholder with the pinned literal
otherwise): test_ta_series_length_extremes, test_ta_series_length_supertrend,
test_ta_simple_length, test_ta_window_underapplied, test_ta_window_round10,
test_tv_fill_rounding_l4d. test_tv_fill_rounding (not the _l4d twin) was
already retired through L3A_LEGACY_OWNER_TEST_SOURCES and registers no row; its
source leaves and its name stays in that retirement list (REMOVE_ITEM of an
absent name is harmless).

The four source-bound rows are recorded in _pf_source_bound_private_rows so the
kernel profile, which has no source layer, stays correct without the files.
Pins: tests/private_fixture_rows.txt 368 -> 374 rows (and
PRIVATE_FIXTURE_ROW_COUNT), tests/private_fixture_paths.txt +10 F lines (10,206
files, 12,910 paths, 2,704 directories). Floors: release private count 300 ->
306 (absent floor 610 -> 604), kernel private count 28 -> 30 (only the
underapplied and round10 rows are source-free; absent floor 309 -> 307); full
totals 910 and 337 are unchanged.

Doc sentence reworded, named here for the doc-revert gate: "The full-run
release and kernel floors are the table's own numbers above (610 and 309 rows
absent, 910 and 337 with the overlay present); full runs do not exclude a
label." now says 604 and 307 for the absent floors; the two cells of the floor
table in docs/ci.md change the same way (610 -> 604, 309 -> 307).

None of our release-built assets contains these files: the prebuilt tarballs
are cmake --install with PINEFORGE_BUILD_TESTS=OFF plus LICENSE/NOTICE/VERSION
(release.yml, the build at line 399 and the pack step at 433); only GitHub's
automatic source archive carries tests/. Git history is not rewritten (owner
ruling 10-11). First added: test_tv_fill_rounding.cpp 7fc7347 (2026-08-25,
#163), test_tv_fill_rounding_l4d.cpp 73817c1 (2026-09-19, #254),
test_ta_window_underapplied* ade627e and test_ta_window_round10* c8993aa
(2026-09-06), test_ta_series_length_*, test_ta_simple_length.cpp 1e360bd
(2026-09-27).

Two existing gates carried the old numbers and move with the floors (found by
the Claude read of the first cut): scripts/test_ci_verify.py (the literal pins
(910,306)/(337,30) and absent floors 604/307, the kernel absent scenarios now
with 30 pinned rows, the explicit --min-tests 307 case, the one-row-ran case
337 - 29 = 308, the websocket allowance case 337 - 30 - 1 = 306; the shrunken
release registry 901/298 -> 603 still fails the 604 floor; dated measurements
stay as history) and tests/private_fixture_reads.evidence (the CMake line it
cites moved by -2: 3253 -> 3251, prose cites :3273 -> :3271, :3237 -> :3235,
:3249 -> :3247, :3279-3280 -> :3277-3278). A comment in tests/CMakeLists.txt
that cites the two gate suites follows (:2217/:2219 -> :2215/:2217).

Not run locally (no suites on the Mac); the two-world proof runs on lab remote.


Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant