回测基本一致

This commit is contained in:
2026-06-26 20:50:07 +08:00
parent 49be922517
commit 0dcbfe0781
58 changed files with 4843 additions and 40 deletions
+34 -4
View File
@@ -193,6 +193,31 @@ For a brand-new symbol you must first **let MT5 cache its history** (open a char
`Tools → Options → Charts → Max bars: Unlimited`, scroll back) so the tester and the export have enough
bars. Confirm the exact broker symbol code (it varies: indices and metals especially) before exporting.
### 6a. Pull M1 even if your signal timeframe is higher — and pass it to the engine
A common mistake: download only the signal timeframe (e.g. M5/M15/H1) and assume that's enough. It is
not, **if your EA moves its SL during a trade** (break-even, trailing, basket trailing). The bar-level
engine produces a 40% to 50% net gap on those EAs (doc 03 §7 measured failure mode) because the BE
update and the SL trigger fall on the same bar's opposite extreme. The fix is tick-level exit
simulation, which needs the **M1 bars covering the same window as your signal bars**:
```python
# Download BOTH timeframes. Same symbol, same window, exclusive end (match MT5 tester).
m1_bars = load_bars(DATA / f"{SYMBOL}_M1_{start}_{end}.parquet")
m5_bars = load_bars(DATA / f"{SYMBOL}_M5_{start}_{end}.parquet") # the signal timeframe
# Slice both to the exact same window (exclusive end matches MT5 tester's ToDate).
m1_bars = m1_bars[(m1_bars["timestamp"] >= start) & (m1_bars["timestamp"] < end)]
m5_bars = m5_bars[(m5_bars["timestamp"] >= start) & (m5_bars["timestamp"] < end)]
# Pass m1_bars to the engine — it switches to tick-level exit simulation automatically.
result = engine.run(m5_bars, signals_long, signals_short, sl, tp,
instrument, sizing, deposit, m1_bars=m1_bars)
```
If your EA does **not** move its SL intra-trade (clean market entries with a fixed SL/TP), `m1_bars`
can be omitted — the bar-level engine is exact for that class and faster.
---
## 7. Parsing the report
@@ -223,10 +248,15 @@ For every finalist, write an `auto-verification.md` that puts the two tiers side
| Equity DD max | … | … | …% |
| Total trades | … | … | …% |
Then judge the delta **against the expected fidelity gap** (doc 03 §7): a clean-directional setup
should show only a modest negative gap (MT5 a little below Python); a trailing/grid setup in volatile
history can gap much wider, and that's *expected*, not a bug. The decision rule: if the **MT5** number still clears your bar after the gap,
the finalist is real; if the edge only existed in the optimistic Python figure, discard it.
Then judge the delta **against the expected fidelity gap** (doc 03 §7 + §8 target-gate table):
a clean-directional setup (bar-level engine, SL not moved intra-trade) should show ≤ ~2% net gap;
a trailing/BE setup on the **bar-level** engine is not trustworthy at all (40% to 50% gap,
doc 03 §7 measured failure mode) — **before** judging the gap "expected", confirm the Python run
used M1 tick-level exit simulation (`m1_bars=` passed to the engine), which brings the gap into the
≤ ~10% range. Only a gap inside the §8 target gate counts as "expected"; a wider gap is a
missing-M1 / wrong-engine-mode bug, not fidelity noise. The decision rule: if the **MT5** number
still clears your bar after the gap, the finalist is real; if the edge only existed in the
optimistic Python figure, discard it.
> A useful warm-up calibration: pick one known preset and run the full Python-vs-MT5 comparison on it
> first. It tells you *your* stack's actual gap for *your* EA, so later finalists are judged against a