Reference

Troubleshooting

Every known failure, grouped by where it happens. Start with the diagnostic command, then find your symptom.

Start here

One command answers most of these questions
run_studio.bat --check
# or
py FxMath_LR_Studio\run.py --check
# or for the frozen exe
"FxMath LR Studio.exe" --check
It prints the resolved repository, interpreter, bundled-runner probe, MetaEditor and terminal paths, every terminal found, whether compiling and downloading are possible, each stage's state, all staleness warnings, and every command a full run would execute.

Two lines in that output are worth checking first, always:

repo
Shows [ok] or [INVALID]. If invalid, nothing else matters — fix this first.
bundled ok
Only present on a standalone build. It proves the frozen runner started and imported numpy and pandas.

Startup and setup

The window opens but everything says "Repo: not set"

The app cannot find the pipeline repository. This is the most common setup failure and it disables every stage.

CauseFix
The repository folder is not on this machine or is misplaced. Settings → Repository → Browse and pick the folder containing scripts\ and data\.
You pointed at a folder of Python scripts that is not the pipeline repository. Detection requires both scripts/feature_search.py and scripts/gen_ea.py. Verify both exist.
A stale repo path in settings.json. It is auto-repaired on load if the path no longer exists. If the path does exist but is wrong, use Browse.
# verify the hard markers exist
dir LR-Studio-Repo-Windows\scripts\feature_search.py
dir LR-Studio-Repo-Windows\scripts\gen_ea.py

The app will not start at all

SymptomCauseFix
Dialog: "The 'customtkinter' package is missing" Source run without the GUI dependency. py -m pip install customtkinter, or use the built exe.
Dialog with a traceback The launcher caught a startup exception and showed it rather than letting the window vanish. Read the traceback in the dialog — it names the missing module or syntax error.
Nothing happens when double-clicking a .bat No Python on PATH. Install Python 3.10+ and tick "Add python.exe to PATH", or build the standalone exe.
Window flashes and disappears An unhandled error before the dialog could be shown. Run from a terminal so the traceback stays visible: py FxMath_LR_Studio\run.py.

Anti-virus or SmartScreen blocks the executables

A PyInstaller binary that spawns child processes and writes files is a textbook false positive. SmartScreen also flags unsigned executables downloaded from the internet.

Symptoms
The exe is quarantined; or it runs but the search never starts; or taskkill /T is silently blocked and workers survive cancellation.
Fix
Add an exclusion for the app folder and dist\, or run from source instead.

MetaTrader and compiling

"MetaEditor64.exe not found" — compiling is disabled

CauseFix
The selected mt5_dir is the wrong folder — for example the data directory rather than the install directory. It must contain metaeditor64.exe and terminal64.exe. Settings → Browse to correct it.
The terminal is not installed. Install MetaTrader 5 from your broker.
A stale POSIX or wine path persisted from another machine. Auto-repaired on load — --check will show what it resolved to.
# confirm the file exists
dir "C:\Program Files\AMarkets - MetaTrader 5\metaeditor64.exe"

The wrong terminal was auto-selected

Multiple installs are common — a main terminal plus a "Copy" left over from an update. The app scores candidates by whether they have a terminal, MetaEditor, a data directory and a known broker server, and picks deterministically.

A "Copy" folder can score well If the auto-pick chose the wrong one, choose explicitly on the Settings card. The selection is remembered, and changing it also refreshes the broker suffix if re-detect the broker suffix is enabled — because a different terminal usually means a different broker spelling.

A compiled EA does not appear in MT5

Two causes, in order of likelihood:

Deployed to a different terminal's data directory
Two installs keep separate %APPDATA% data folders. The Settings → MT5 card shows the exact MQL5\Experts path deployment targets. Compare it against the terminal you are actually looking at.
The MT5 Navigator is not refreshed
MetaTrader does not always notice new files. Right-click the Navigator tree and refresh, or restart the terminal.

Compile reports failure but the log says "0 errors"

This is MetaEditor's most misleading behaviour When a build fails outright, MetaEditor still writes a fresh 0 errors log next to the old .ex5. A log-only success check would report a green build for a build that never happened.

The app therefore requires three things: the .ex5 exists, it is newer than before, and the log reports 0 errors. If you are compiling by hand, check the .ex5 timestamp rather than trusting the log.

To force a genuinely clean test, delete both the .ex5 and the log before recompiling.

del strategies_lr_m5\all9\*.ex5
del strategies_lr_m5\all9\*.log

Compile fails with real errors

The EA page extracts diagnostics into a table of severity / code / file / line / message. Read that before the raw log. The usual candidates are a missing MQL5 include, or a generated file that references a feature the local feature_sets.py no longer defines — which happens if you edited the set definitions after generating.

Regenerate from a fresh search if the feature lists have changed.

Data and downloading

"Could not import MetaTrader5" when downloading

CauseFix
The module is not installed in the selected interpreter. py -m pip install MetaTrader5 — and note that the selected interpreter is what matters, not PATH.
The terminal is not running, or not logged in. Start MetaTrader 5 and log in first.
On Linux, the downloader needs a Windows Python inside the wine prefix. Enable the wine mode in Settings. The module talks to the terminal through a Windows DLL.
The export route avoids all of this Attaching ExportOHLC_MQL5.mq5 to a chart runs inside the terminal. No Python module, no wine, no DLL — and you get the broker's own spread column, which is strictly better input than an API download.

"symbol not found" / the downloader returns no bars

Almost always the broker suffix. An AMarkets account lists gold as XAUUSDb; requesting XAUUSD returns nothing.

Diagnose
Settings → Symbol & broker suffix → List instruments. It shows the closest matches in this terminal plus the detected suffix.
Fix
Press Detect from terminal to fill the suffix in automatically, then Save.

Remember the two names are used differently: the suffix goes to the terminal, the clean name is used for every file and folder.

A single timeframe downloaded nothing

The downloader prints [TF] FAILED: no data and continues — it does not exit non-zero. When downloading several timeframes at once, read the output list rather than the exit code.

Common reasons: the broker simply has no history at that timeframe, or fewer bars than requested. The exporter's sidecar summary flags this explicitly as SHORT-HISTORY.

The log shows boxes or question marks instead of · and —

An encoding mismatch, not a data problem The pipeline prints ·, and ->. Python's Windows console codec is cp1252, not UTF-8, so both ends of the pipe are pinned: the child gets PYTHONIOENCODING=utf-8 and PYTHONUTF8=1, and the parent reads with encoding="utf-8", errors="replace".

This was a real defect once: with text=True and no explicit encoding, the parent decoded with its own codec and the log showed replacement characters — or, in the worst case, raised inside the reader thread and stalled the log silently.

If you see this, something is overriding PYTHONIOENCODING in your shell environment. The app pins it explicitly and takes precedence over the launching shell, so a nested launcher is the usual culprit.

During a run

The search produces zero trades, or absurd results

CauseHow to confirm
Zero median spread in the CSV The Data page's median spread tile reads 0, or the validator reported the error. Every report then charges $0 cost per trade.
Not enough rows for the training window The validator warns below 1,559 rows.
Shifted clock — data in UTC rather than server time The hour histogram in the validator looks implausible for the instrument.
OHLC columns out of order or a wrong header The validator errors on the header — it byte-compares the exact expected string.
Bars at the wrong cadence The validator reports a 2× mismatch, meaning the file holds the double timeframe.

Fix the data and re-run. Do not tune the search around bad input.

The GUI freezes during a search

It should not — the child runs on a background thread and Tk polls its output queue every 80 ms. If the window genuinely stops responding:

CauseFix
Every core is saturated. Lower cores. The default is already cpu_count − 2; on a small machine that can still be too many.
A very large amount of log output. The history buffer is capped at 6,000 lines, so memory is bounded — but rendering a fast-moving log is still work.
The machine is swapping. The search is memory-hungry per worker. Reduce cores or close other applications.
A frozen window is not a crash The child process is independent. Even if the UI stalls completely, the search keeps running and its artefacts still land on disk. Check Task Manager, or just wait — the app re-reads state from disk on refresh.

Stop did not kill the workers

Killing only the parent leaves orphans holding every core The scripts use a process pool, so the immediate child has children of its own. On Windows the tree is killed with taskkill /T /PID; on POSIX the child runs in its own session and the process group is killed.

If workers survive, taskkill is being blocked — almost always anti-virus. Add an exclusion, then kill the survivors by hand:

taskkill /f /im FxMathLRStudioRunner.exe
taskkill /f /im python.exe

Watch Task Manager during a run to see the expected shape: one parent plus several pool workers. After Stop, all of them should vanish within a second or two.

Numbers changed after I re-ran something

This is usually correct behaviour, not a bug Several stages legitimately produce different numbers from the same inputs:
  • Portfolio versus Optimize page. The portfolio re-simulates at max_iter = 2000 while the search's reported metrics came from the same budget for survivors — but the combined curve is warmup-aligned and rebased, so the arithmetic differs from summing the table.
  • Reports versus the app. A report is a snapshot of whatever artefacts existed when it ran. If a stage re-ran afterwards, the report is stale.
  • Holdout versus in-sample. Different data by construction. This is the entire point of the holdout.

Before assuming a bug, check the freshness strip: a stage showing amber means an input is newer than an output, and everything downstream of it is describing a run that no longer exists.

Excel or the browser shows a stale report

Local files are cached aggressively. Hard-refresh with Ctrl+F5, or archive reports under dated names so the browser treats each as new.

Understanding the results

The holdout is negative — is something broken?

No. It is the most informative result the pipeline can give you A negative holdout means the in-sample performance was curve-fitting. That is a finding, not a failure — and it is exactly why this stage exists. Do not compile and do not deploy.

Before concluding anything, check the tail's trade count. A negative result from eleven trades is noise in the other direction. A negative result from hundreds of trades is a real absence of edge.

The holdout is suspiciously good

Be more suspicious of this than of a negative result. Check, in order:

Is the tail genuinely unseen?
Compare the report's recorded n_bars with the current CSV's row count. If they differ, the tail is not the tail you think it is.
Are the configurations frozen?
The holdout reads summary.json — it never re-optimises. If the summary was regenerated between runs, the "frozen" configs are new ones.
How many trades?
A handful of trades cannot establish anything. Check the per-slot table and the trade CSVs.
Is the tail one contiguous regime?
It always is. One trending month suits a momentum book; the next may not. A positive tail is one data point about one market condition.

Most hour windows show negative OOS

Expected more often than not. The search has 120 candidate windows; some look excellent by chance. Ship the 24-hour build instead — generate it with --no-hours --tag 24X so both variants coexist and the delivery report can quantify the difference.

Some sets reported fewer than 5 slots

The acceptance test (trades ≥ 30, profit_factor > 1.0) or the correlation filter rejected the rest. This is a legitimate outcome, not an error. It does mean the portfolio will be smaller than nine — check the slot count on the Portfolio page and note which sets dropped out.

All nine slots look identical

The correlation filter's fallback fills remaining slots by best score ignoring correlation. If the low-correlation pool was too small, several slots can be near-copies. Look at the per-slot equity curves on the Portfolio page — if they move together, the book is one position at nine times the size, and its drawdown will behave accordingly.

Quick reference

SymptomMost likely causeFirst action
Everything says "Repo: not set"Repository not foundSettings → Browse to the folder with scripts/feature_search.py
Compiling disabledWrong mt5_dirBrowse to the folder with metaeditor64.exe
EA compiled but invisible in MT5Different terminal's data directoryCheck the MQL5\Experts path in Settings, then refresh MT5
Compile "failed" with 0 errorsOld .ex5 plus a fresh logDelete both and recompile
Download returns nothingBroker symbol suffixSettings → Detect from terminal
Log shows Encoding override in the shellPYTHONIOENCODING is being overridden by a launcher
Zero trades / absurd numbersZero median spread, or a shifted clockRe-run the validator and read it
Window unresponsiveToo many coresLower cores; the search keeps running regardless
Workers survive Stoptaskkill blockedAdd an anti-virus exclusion, kill by hand
Numbers changedStale inputs, or comparing in-sample with holdoutCheck the freshness strip
Negative holdoutCurve-fittingNot a bug. Do not deploy.
Amber or red badge on a stageAn input is newer than an outputRe-run that stage

Reporting a problem

If you need to investigate further, capture these three things:

The --check report
It records the exact resolved paths, interpreter and stage states — the context everything else depends on.
The command and its full output
Every command is shown in the Output panel and is copy-pasteable. Run it in a shell to get the raw stream without GUI formatting.
The relevant artefact
The summary.json, best_hours.json or tail_report.json involved. These are small, self-describing, and describe the run precisely.
Reproduce it from a shell first Because the GUI never imports the pipeline, a command that fails in the app fails identically in a terminal. Running it there removes the GUI from the equation and shows the unformatted output — which is usually enough to identify the cause immediately.