Skip to content

Repository files navigation

DataForge — know what your MetaTrader 5 data actually contains

DataForge logo

DataForge exports MT5 bars to CSV — and, more importantly, it tells you what is really inside them.

The mark is the product: two readings of the same instrument, and one column where they disagree — the declared value dashed, the measured one short.

Most machine-learning failures in trading are not model failures. They are data failures that nobody looked for: a field that silently reads zero, a contract spec that differs between the server you trained on and the server you trade on, a feature that your Python code and your MQL5 code compute almost the same way.

DataForge is two MQL5 scripts that make those failures visible before you train, not after you lose money.

It never trades. No orders, no positions, no account access. It reads history and writes a text file.


What it produces

1. An instrument passport, written into the CSV header

# server=FundedNext-Server 3
# symbol=XAUUSD
# digits=2
# point=0.01
# contrat=100
# tick_value=1
# lot_min=0.01
# lot_step=0.01
# lot_max=3

Export the same symbol from two servers and diff the two headers. That is the whole idea.

Why it matters — a real result. Exporting XAUUSD from three brokers on the same day gave:

field MetaQuotes-Demo Alpari-MT5-Demo FundedNext-Server 3
digits / point / contract 2 / 0.01 / 100 2 / 0.01 / 100 2 / 0.01 / 100
tick_value 0.1 0.1 1
lot_max 100 100 3

Same symbol, same contract size, same tick size — and a tenfold difference in what one tick is worth. (Contract 100 × tick 0.01 = $1, so the funded server is the one that is right and the two demo servers report a tick_value inconsistent with their own spec.) A backtest built on one and deployed on the other is off by a factor of ten in money, and nothing in the platform warns you.

2. A per-year volume table — read from the bars, not from the tester

VOLUME OF THE BARS, PER YEAR (read via CopyRates, NOT the tester)
  2019 :  23475 bars | tick_volume non-zero  23475 (100.0 %) | real_volume non-zero      0 (  0.0 %)
  2020 :  23611 bars | tick_volume non-zero  23611 (100.0 %) | real_volume non-zero      0 (  0.0 %)

Why it matters — the second real result. The Strategy Tester's "history quality" bar describes the generated tick stream. It says nothing about the real_volume stored in the bars. Those are two different things, and confusing them means opening the volume door too early — or closing it for nothing.

Measured across three brokers:

  • real_volume is zero on every source from 2019 to today;
  • where it does exist (2012–2018) the sources contradict each other — for 2015, one reports 100 % coverage and another 9.6 %; for 2017, 99.3 % against 0 %;
  • tick_volume is present at 100 % everywhere — but it is a tick count, entirely broker-dependent, usable only in relative terms.

If you were about to build volume features, that table is the difference between a model and a fiction.

3. A parity reference — MQL5 against your Python

ForgeExport also writes the feature columns as MQL5 computes them (f0…fN). ForgeParity writes them again after normalisation (z0…zN). Your training code recomputes both and compares.

Why it matters — the third real result, and the sharpest one. In one project, the same feature code was checked by transliterating the MQL5 into Python and diffing the two Python versions. It reported a maximum error of 2.1e-10. When the actual MQL5 output was finally compared:

P1  raw features        8.882e-16    machine precision   ✓
P2  after normalisation 1.339e+00    threshold 1e-5      ✗

Ten orders of magnitude apart. A check that never crosses the language boundary does not check the language boundary. Without it, an ONNX model would have gone live receiving inputs on a scale it had never seen — and it would have kept returning perfectly normal-looking probabilities.


Install

  1. Open MetaEditor from MetaTrader 5 (F4).
  2. Copy the folders into your terminal's MQL5 directory, keeping the layout:
    MQL5/Scripts/DataForge/ForgeExport.mq5
    MQL5/Scripts/DataForge/ForgeParity.mq5
    MQL5/Include/DataForge/ForgeFeatures.mqh
    
    Find that directory from the terminal: File → Open Data Folder.
  3. Compile each .mq5 with F7. Expect 0 errors, 0 warnings.

Getting the repository:

git clone https://github.com/Sjrazaviebra/DataForge.git

Use

Export

⚠️ Two settings first, or you will export less than you think — silently.

  1. Tools → Options → Charts → Max bars in chart → set it to Unlimited. CopyRates will never return more than this cap, and it raises no error when it truncates.
  2. Open the chart, click on it, and hold Home until it stops scrolling back. A script reads what the terminal has cached, not what the server holds.

Then: Navigator (Ctrl+N) → Scripts → DataForge → ForgeExport, drag it onto an M15 chart.

input default meaning
EX_Depuis 2004.01.01 start date; leave it wide — the script publishes the real bounds it found
EX_MaxBarres 600000 safety cap on the number of bars
EX_AvecFeatures true also write f0…fN, the parity reference

The volume table and the real bounds are printed to the Experts tab. The file lands in MQL5/Files/ and its name carries the server, so three sources give three files and nothing is overwritten.

Parity

ForgeParity does not recompute anything. It reads the raw features out of the export file and writes them back normalised, so the only thing under test is the one thing that should be: your scaler, applied by MQL5.

★ That is a deliberate design choice, and it came from a failure. An earlier version did recompute them — with its own warm-up depth, and two hours after the export ran. The result was that the normalisation test silently re-tested the feature computation instead, at a different depth and a different instant. Both sides now read the same lines.

  1. Your training code writes a scaler CSV whose header carries # etage= and # empreinte_cadre=.
  2. Drop it in the terminal's common folder — File → Open Data Folder, then up to Terminal/Common/Files.
  3. Run ForgeParity on the same chart.
input default meaning
PA_Export (empty) export CSV; empty → DataForge_<SYM>_<SERVER>_M15.csv
PA_Scaler (empty) scaler; empty → DataForge_scaler_<SYM>_e<STAGE>.csv
PA_Etage 1 expected stage — checked against the scaler's own header
PA_Empreinte (empty) expected frame fingerprint; empty → not checked
PA_DossierCommun true read the scaler from the common folder
PA_Barres 1000 parity window: the last N populated lines of the export

The stage and fingerprint are verified, not assumed. A scaler from the wrong stage is refused instead of silently testing the wrong normalisation — the filename is no longer the only safeguard.


The CSV format

# key=value            ← passport + per-year volume table, one line each
time,open,high,low,close,spread,tickvol,realvol,f0,f1,…,fN
2024-01-01 21:00:00,2062.99,2063.44,2062.85,2063.12,29,41,0,nan,nan,…
  • Timestamps are YYYY-MM-DD HH:MM:SSISO order, on purpose. MetaTrader's own TimeToString writes 2025.01.02 with dots, and a parser that guesses day/month would shift 03.04 by three months without raising anything.
  • The first bars come out nan: the recursive indicators need a warm-up, and the file says how many.
  • Comment lines are written in the terminal's ANSI code page. Read them tolerantly (encoding_errors="replace" in pandas) — the data rows themselves are pure ASCII.

Two real headers are in examples/, so you can see the diff before running anything.


Limits, stated plainly

  • M15 only. The feature set is calibrated for it; other periods are untested.
  • Order-book depth is empty on every CFD broker tested (MarketBookAdd is accepted, and nothing comes out). Verified on three.
  • No trade direction. No tick carries a buy/sell flag on any tested broker (BUY 0.000 %, SELL 0.000 %), so no order-flow delta is measurable. Any "signed volume" you build rests on the tick rule (Lee-Ready) — an inference, not a measurement, and its error rate belongs next to it.
  • ForgeParity needs a scaler produced by your own training code. It ships no model.

Licence

Source-available for reference, evaluation and demonstration. See LICENSE.

Built by Javad RazaviThe Solution Maker · javadrazavi.fr

See also HorizonProbe — the same discipline applied to time: at what holding period does your instrument stop being unprofitable by construction?

About

Export MetaTrader 5 bars to CSV — and see what is really inside them: instrument passport, per-year volume table, and an MQL5 to Python parity reference.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages