Skip to content

playbackrun: drive the Playback connection end to end (Market Replay … - #7

Open
Quantrosoft wants to merge 1 commit into
eman007:mainfrom
Quantrosoft:playbackrun
Open

playbackrun: drive the Playback connection end to end (Market Replay …#7
Quantrosoft wants to merge 1 commit into
eman007:mainfrom
Quantrosoft:playbackrun

Conversation

@Quantrosoft

Copy link
Copy Markdown

I have extended your bridge with NinjaTrader's Playback engine, in both of its run modes — Market Replay and Historical — plus a way to run the Strategy Analyzer from one of NinjaTrader's own strategy templates. Everything stays in the style of the project: in-process, JSON in and out, no UI automation.

What this adds

  • playbackrun — one Playback measurement, end to end, with no click anywhere: every connection off, clean start, connect, source (--source marketreplay|historical), dates, range, speed, attach the strategy, play to the data end, restore the baseline. Every value it writes is read back, and it exits 0 only when the data end was reached and the teardown restored the baseline, so a run that stopped for any other reason cannot be mistaken for a result. Each run is archived (request, result, transcript, screenshots).
  • Both Playback sources, kept apart because they do not read the same store. Market Replay is served from db\replay (.nrd), Historical from db\tick (.ncd), and the coverage pre-flight scans the one the run will read. The source itself is settled on PlaybackAdapter.IsSourceHistoricalData; the panel's radio buttons are display only, because writing them while connected makes NinjaTrader re-parse the panel's date fields and throw.
  • satemplate — put one of NinjaTrader's own strategy template files on the Strategy Analyzer tab (the complete parameter set plus instrument and window). backtest --config becomes optional, and the run cannot drift from what the GUI would run.
  • A second AddOn file, addon/NT8BridgeServerPlayback.cs, carrying the Playback stages.

What the existing commands gained on the way

All of it is what a long unattended run turned out to need; every entry in CHANGELOG.md carries the measurement behind it.

  • Every request carries a TTL; connections says whether a row came from the configuration or only from the live list.
  • playbackrun: a connect budget of its own (CONNECT_WAIT, min. 600 s), a preflight that waits out a busy NinjaTrader (PREFLIGHT_WAIT, min. 1800 s) but refuses at once when no NinjaTrader.exe is running, and --from/--to validated as YYYY-MM-DD before anything is sent.
  • During a run the bridge confirms NinjaTrader's order-rejection boxes for the playback account (the ones carrying affected Order:) and counts them; every other modal still stands and is still the finding.
  • playback: the .nrd coverage scan is opt-in (--coverage / --instrument), responses carry coverageScanned.
  • ntstatus decides "stale" by comparing the newest .cs under bin\Custom with the build time of the assembly NinjaTrader actually executes — after a reload that is a temp assembly, so the old rule (DLL newer than the process) called reloaded code stale.
  • Subprocess output decoded with errors="replace", for a non-English Windows.

Verification

  • pytest: 307 passed, 8 skipped (the skips need matplotlib, an offline compiler, or .nrd fixtures that are not in the repository).
  • Both AddOn files compile against NinjaTrader 8.1's own reference set with 0 errors, and the same code compiles and hot-reloads inside NinjaTrader (compile + reload).
  • Measured on NinjaTrader 8.1.8.2 between 2026-08-19 and 2026-09-03; the dates and numbers in CHANGELOG.md are those measurements. Live runs on the final build: Strategy Analyzer 298/298 runs byte-identical to their stored references, Playback/Market Replay 8/8 byte-identical, Playback/Historical 3 runs to the data end (2 byte-identical, 1 differing in fill prices of a stop race inside the strategy under test, not in the bridge).

Happy to split this up or adjust anything to your taste.

@Quantrosoft
Quantrosoft force-pushed the playbackrun branch 3 times, most recently from 22c34fd to 30642e4 Compare September 7, 2026 14:25
…and Historical), satemplate, and the parameter search

This extends the bridge with NinjaTrader's Playback engine, in both of its
run modes, plus a way to run the Strategy Analyzer from one of NinjaTrader's
own strategy templates.

playbackrun performs one measurement from end to end and never needs a click:
every connection off, clean start, connect, open NinjaTrader's Playback
window if it is not up, source (--source marketreplay|historical), dates,
range, speed, attach the strategy, play to the data end, restore the
baseline. Every value it writes is read back, and
it exits 0 only when the data end was reached and the teardown restored the
baseline, so a run that stopped for any other reason cannot be mistaken for
a result. Each run is archived (request, result, transcript, screenshots).
A second AddOn file, NT8BridgeServerPlayback.cs, carries the stages.

The two Playback sources do not read the same store, and the bridge treats
them apart: Market Replay is served from db\replay (.nrd), Historical from
db\tick (.ncd), and the coverage pre-flight scans the one the run will read.
The source itself is settled on PlaybackAdapter.IsSourceHistoricalData; the
panel's radio buttons are display only, because writing them while connected
makes NinjaTrader re-parse the panel's date fields and throw.

satemplate puts one of NinjaTrader's own strategy template files on the
Strategy Analyzer tab - the complete parameter set plus instrument and
window - which makes backtest --config optional and cannot drift from what
the GUI would run.

optimize, walkforward and multiobjective drive NinjaTrader's own parameter
search on the Strategy Analyzer tab, with one option syntax shared with the
headless runner Nt8Cli (--template, --opt=Name:min:max:step[,...],
--optimizer, --fitness, --out, --Name=value property overrides, --anchored).
The AddOn puts the template on the tab, writes the ranges as NinjaTrader's
own Parameter objects - the Run button refuses a run without one - sets the
run type and executes RunCommand, then reads the results grid once its
progress control has gone: one row per window and per combination with the
optimized values and the performance, and the CSV files the strategy wrote
under a per-host prefix. Measured against the headless runner on the same
template and Custom.dll (NinjaTrader 8.1.8.2, 2026-09-08/09): walk-forward
windows, in-sample ranking and every CSV present on both sides
byte-identical; optimize identical in every combination.

Along the way, the commands that were already here gained what a long
unattended run needs: a TTL on every request, connection rows that say
whether they came from the configuration or only from the live list, a
connect budget of its own, a driver lease that runs from the answered
request rather than from its receipt (so no stage can outlive it), a preflight that waits out a busy NinjaTrader but
refuses at once when NinjaTrader is not running, argument validation for the
run window, an opt-in .nrd coverage scan, an ntstatus verdict that compares
the sources on disk with the code NinjaTrader actually executes, and
subprocess output that survives a non-English Windows.

Every number in CHANGELOG.md and README.md was measured on NinjaTrader
8.1.8.2 between 2026-08-19 and 2026-09-09. Tests: 326 passed, 6 skipped
(the skips need matplotlib, an offline compiler, or private .nrd fixtures).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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