Troubleshooting
Every known failure, grouped by where it happens. Start with the diagnostic command, then find your symptom.
Start here
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[ok] or [INVALID]. If invalid, nothing else matters — fix this first.bundled okStartup 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.
| Cause | Fix |
|---|---|
| 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
| Symptom | Cause | Fix |
|---|---|---|
| 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.
taskkill /T is silently blocked and workers survive cancellation.dist\, or run from source instead.MetaTrader and compiling
"MetaEditor64.exe not found" — compiling is disabled
| Cause | Fix |
|---|---|
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 compiled EA does not appear in MT5
Two causes, in order of likelihood:
%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.
Compile reports failure but the log says "0 errors"
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
| Cause | Fix |
|---|---|
| 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. |
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.
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 —
·, — 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
| Cause | How 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:
| Cause | Fix |
|---|---|
| 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. |
Stop did not kill the workers
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.exetaskkill /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
- Portfolio versus Optimize page. The portfolio re-simulates at
max_iter = 2000while 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?
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:
n_bars with the current CSV's row count. If they differ, the tail is not the tail you think it is.summary.json — it never re-optimises. If the summary was regenerated between runs, the "frozen" configs are new ones.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
| Symptom | Most likely cause | First action |
|---|---|---|
| Everything says "Repo: not set" | Repository not found | Settings → Browse to the folder with scripts/feature_search.py |
| Compiling disabled | Wrong mt5_dir | Browse to the folder with metaeditor64.exe |
| EA compiled but invisible in MT5 | Different terminal's data directory | Check the MQL5\Experts path in Settings, then refresh MT5 |
| Compile "failed" with 0 errors | Old .ex5 plus a fresh log | Delete both and recompile |
| Download returns nothing | Broker symbol suffix | Settings → Detect from terminal |
Log shows □ | Encoding override in the shell | PYTHONIOENCODING is being overridden by a launcher |
| Zero trades / absurd numbers | Zero median spread, or a shifted clock | Re-run the validator and read it |
| Window unresponsive | Too many cores | Lower cores; the search keeps running regardless |
| Workers survive Stop | taskkill blocked | Add an anti-virus exclusion, kill by hand |
| Numbers changed | Stale inputs, or comparing in-sample with holdout | Check the freshness strip |
| Negative holdout | Curve-fitting | Not a bug. Do not deploy. |
| Amber or red badge on a stage | An input is newer than an output | Re-run that stage |
Reporting a problem
If you need to investigate further, capture these three things:
--check reportsummary.json, best_hours.json or tail_report.json involved. These are small, self-describing, and describe the run precisely.