Tags

Tags give the ability to mark specific points in history as being important
  • v4.15.0

    v4.15.0
    
    `POST /compile` and everything under it was contributed by @Marinski in #16.
    
    - `POST /compile` takes MQL5 source as JSON and returns the compiled `.ex5`, base64-encoded, with MetaEditor's log. Warnings do not fail a build, since MetaEditor exits non-zero on warnings too: success means a clean log and an actual binary. The log is decoded from MetaEditor's UTF-16LE. A compile error is a `422` carrying the diagnostics, the deadline is a `504`, and every response is JSON. See [Compiling MQL5](docs/compiling.md).
    
      The caller sends source text only. `filename` is reduced to a bare stem inside a per-request temp directory that is removed on every exit, and `/compile:`, `/log:` and `/inc:` are computed by the server. `#include`, `#resource` and `#property icon` paths that are absolute, UNC, contain a `..` segment or name a device are refused with a `400` before MetaEditor runs: measured on MetaEditor build 5836, `#include` otherwise reads any file the API process can, and quotes its tokens back in the log. The check splits lines the way the preprocessor does (`\r`, `\r\n`, backslash-newline continuations, form feed, vertical tab, and a comment between `#` and the directive name), and MetaEditor compiles the same line-normalized text the check read. `tests/real_compile/` checks this against a live deployment. `ea_version` is only logged, and must be 1 to 64 characters of `A-Z a-z 0-9 . _ + -`.
    - Compiles are serialized across processes, not just threads: MetaEditor is single-instance per installation directory and every API process on a VM serves `/compile`. The lock is an OS byte-range lock on `.compile-inflight.lock` in the local mirror, or beside `MetaEditor64.exe` without one, which the OS releases when its holder exits or is killed. The mirror is refreshed under the same lock. At most two compiles wait behind the running one; the rest get an immediate `429` with `Retry-After`, so compile traffic cannot occupy every server thread.
    - `compile_api_token`, a second bearer token accepted only on `/compile`, so a build pipeline or code generator can compile without holding the token that can trade. `api_token` keeps working everywhere, and leaving the new token empty changes nothing.
    - Compile settings: `compile_terminal_dir` (default `terminals/metaquotes/base`), `compile_include_dir`, `compile_work_dir`, `compile_timeout` (default `30s`, ceiling 60s; a bare number is seconds), `compile_max_source_bytes` (2 MB, `413` before anything is written), `compile_max_ex5_bytes` (16 MB, checked before the binary is read), `compile_local_cache` and `compile_include_digests`. An invalid timeout or byte cap falls back to its default with a warning in the API log.
    - A successful compile reports `include_hash`, a sha256 over the include tree MetaEditor was given, recomputed whenever a file in that tree changes. `compile_include_digests` names headers whose own digests are reported as `include_files`, so a caller can tell an edit of its own header from an upgrade of the stock library.
    - `compile_local_cache` mirrors MetaEditor, its `Config` and the `MQL5` tree onto local disk, for installs whose terminals sit on a network or host-shared mount. On a 9p share a compile MetaEditor timed at 4.1s took 29s wall-clock, all of it loading the 105 MB binary. The include tree is re-checked against the source at most once a minute. A mirror that cannot be built falls back to the shared copy.
    
    - **Every API process schedules a MetaEditor warm-up** when `compile_local_cache` is set: 180s after start, one throwaway compile, so the first real caller does not pay the 30 to 55s cold load. One process per VM per boot runs it, claimed by a file in the cache that records the boot. It skips itself if a compile is running and logs, never raises, on failure.
    - **nginx gives `/<broker>/<account>[/<instance>]/compile` a 180s read and send timeout.** The handler's worst case at the 60s ceiling is 150s. Every other route keeps nginx's 60s default.
  • v4.14.0

    v4.14.0
    
    The symbol-suffix, symbol-import, body-cap, journal-size and log-tail work below was contributed by @Marinski in #18.
    
    - `POST /symbols/import` fills a terminal's symbol cache from a JSON list without calling the MT5 SDK, so a `mode: backtest` terminal can be primed. Each import is merged into the existing cache. `"complete": true` says the list is the broker's full book and replaces the cache instead. A partial import keeps the cache's `updated` stamp, so only a full book restarts its trust window. The body is bounded by `symbol_import_max_body_bytes` (2 MiB, `413` before parsing, `411` without a `Content-Length`), `symbol_import_max_symbols` (20000) and `symbol_import_max_symbol_length` (64). See [Market data](docs/market-data.md).
    - Every request body is capped before it is parsed: `max_request_body_bytes` (4 MiB) for JSON, `max_upload_body_bytes` (25 MiB, matching nginx's `client_max_body_size`) for multipart `POST /backtest`. Over the cap is a `413`.
    
      For all five byte and count settings, zero, a negative or a non-integer falls back to the default with a warning in the API log. There is no value that turns a cap off.
    - `scripts/measure-broker-offsets.py` reads each terminal's latest tick and prints the `utc_offset` to set, for re-measuring after a DST change. It only works against `mode: live` terminals. See [Installation and configuration](docs/installation-and-configuration.md).
    - The rotator truncates a terminal journal over `MAX_LOG_BYTES` (default 2 GiB) once it has been idle for `IDLE_MINUTES` (default 30). One high-frequency backtest can fill the disk with today's journal long before the `RETAIN_DAYS` age pass reaches it. The file is truncated in place with its mtime kept, because the terminal holds it open. See [Operations](docs/operations.md).
    - `tests/integration/test_mcpunifier.py` calls the unifier's `endpoints` tool over MCP and compares the result with the API's Flask routes in both directions.
    
    - **`GET /symbols` returns `409` on a `mode: backtest` terminal.** It used to call `mt5.initialize()` there, which starts `terminal64.exe` and holds the tester's data-dir lock, so every later backtest on that terminal came back empty. Callers that listed symbols on a backtest terminal get a `409` now and should use `POST /symbols/import`. The refusal does not wait for the MT5 lock.
    - **Every other MT5 SDK route answers `503` on a `mode: backtest` terminal.** Account, orders, positions, history, market data and terminal info all went through the same reconnect path, which started `terminal64.exe` on a backtest terminal and left later backtests there with an empty report. They now refuse before any SDK call.
    - **`start.bat` launches only the terminals in its VM's group.** `config_helper.py terminals` now applies the same `config/vm-group.txt` filter that `check_health.py` and the container healthcheck already use. Before, every VM in a multi-VM install prepared and served every terminal, including another VM's live terminal on the same shared data dir. A single-VM install, or one with no group file, still gets every terminal.
    
    - `symbol_suffix` is no longer appended to a symbol the broker only carries bare. Brokers often suffix part of their book: Eightcap Global has `EURUSD.i` but a bare `XAUUSD`, so every non-FX backtest there asked for a symbol that does not exist. The suffix is skipped only when a complete symbol list, written by an unfiltered `GET /symbols` on a live terminal or by an import with `"complete": true`, has the bare name and not the suffixed one. With no cache, a partial one, or one older than `symbol_cache_max_age` (default `7d`; a bare number is seconds), the suffix is appended as before.
    - Log tails (`GET /backtest/<id>/tail`) read at most the last 256 KiB of the file. A multi-gigabyte Tester log used to be read whole on every poll, which held the process long enough to fail `/ping` and the healthcheck.
  • v4.13.2

    v4.13.2
    
    - Backtest tester processes are now recognised inside the Windows VM. There, `Desktop\Shared` is a link to `\\host.lan\Data`, and Windows reports a process's executable by the resolved path, so matching only the configured `C:\Users\Docker\Desktop\Shared\...` path found nothing. The self-relaunch wait never saw the replacement terminal, so those jobs failed as `Report not generated` while the run carried on, and the timeout and startup cleanups killed nothing, leaving `metatester64.exe` agents holding their ports. The resolved path now matches too, and a sibling directory still never does. Contributed by @Marinski in #22.
    
      After upgrading, the timeout and startup cleanups actually stop this terminal's `terminal64.exe` and `metatester64.exe` processes, which they silently skipped before.
    
    - The resolved terminal path is cached only once the link actually resolves. A lookup made while the share is still unreachable no longer hides the resolved path until the API restarts, and a failed lookup is logged instead of ignored.
  • v4.13.1

    v4.13.1
    
    Changed
    
    - Updated the Wickworks sidecar to v0.7.0. Technical-analysis requests now use
      its canonical OHLCV `volume` field. The existing `recentBars` request field
      remains accepted for compatibility and is not forwarded to Wickworks.
    
    Fixed
    
    - The log rotator now prunes dated MT5 terminal, Tester, and Tester Agent
      journals under `data/shared/terminals/`, using the same configurable
      `RETAIN_DAYS` window as shared API logs. It leaves expert logs, MetaEditor
      logs, reports, and backtest jobs alone.
  • v4.13.0

    b0825921 · release: v4.13.0 ·
    v4.13.0
    
    Added
    
    - A Compose-managed `vm-watchdog` sidecar now watches this project's Windows
      VM containers and recreates a VM only after it has remained unhealthy for the
      configured streak. Recovery uses the existing `recreate-vm.sh` path, so the
      VM and its shared-network sidecars are rebuilt together. The watchdog has
      scoped image and Compose-project filters, exponential backoff, a bounded
      attempt budget, dry-run mode, and documented configuration defaults.
    
    - Shared-network sidecars with their own healthchecks are supervised after
      their VM is continuously healthy. This repairs a sidecar stranded in an
      obsolete network namespace without unnecessarily recreating the VM. Set
      `WATCHDOG_WATCH_SIDECARS=0` to retain VM-only recovery.
    
    Changed
    
    - VM port checks now run concurrently. The healthcheck has a bounded wall-clock
      time independent of terminal count, deduplicates configured ports, and
      distinguishes a responsive terminal, a temporarily busy one, and a
      persistently hung one.
    
    - `run.sh` persists `MT5_PROJECT_DIR` for later Compose commands, and recovery
      explicitly stops VMs with the configured grace period before recreating them.
    
    Fixed
    
    - `make lint` no longer reports a false clean result when PSScriptAnalyzer is
      unavailable. The lint image treats module installation and import failures as
      fatal and validates the exact analyzer version before scanning scripts.
  • v4.12.2

    mt5-httpapi v4.12.2
    
    The binary gate now detects EX5 artifacts by header and filename, then requires a manifest entry. Includes the merged backtest cleanup, Wickworks lifecycle repair, and per-VM health filter fix.
  • v4.12.1

    mt5-httpapi v4.12.1 — document the binary-manifest gate
    
    make test already runs verify-binaries first, but the README never mentioned it,
    so the manifest gate was invisible to readers. Adds the target and a section on
    assets/binaries.lock.json. No code changed.
  • v4.12.0

    mt5-httpapi v4.12.0 — CI covers the stack, vendored binaries are gated
    
    make verify-binaries: every tracked executable must be declared in
    assets/binaries.lock.json with its sha256, upstream and signature state. An
    undeclared binary, a changed one, or a degraded signature fails the build, and
    it runs first in make test so CI enforces it on every PR.
    
    It immediately documents scripts/defender-remover/PowerRun.exe, which arrived
    repacked through the defender-remover toolkit: malformed certificate directory,
    hash matching no upstream Sordum release, signature unverifiable. Not known to
    be malicious, but no longer silent.
    
    The unit suite goes from 244 to 379. Everything that previously only ran
    against a live terminal now runs in CI through the real Flask app against a
    scripted SDK. mt5client, monitor and the Go client get their first coverage,
    and the healthcheck awk program is tested by executing it rather than grepping
    its source. Coverage for mt5api is gated at 62 percent, currently 75.
    
    Fixed: non-finite durations raised OverflowError and surfaced as a 500 instead
    of a 400; the backtest timeout was unbounded while holding the terminal's run
    lock; prune_old_jobs rmtree'd a path built from a jobId read out of a state
    file; check_health.py degraded silently when its per-VM filter import failed.
  • v4.11.4

    v4.11.4 - CI/infrastructure only, no code changes
  • v4.11.3

    v4.11.3 - track the shared reusable workflows at master
  • v4.11.2

    v4.11.2 - make the Quick Start actually start MT5
  • v4.11.1

    v4.11.1 - restore the psyb0t voice across the docs
  • v4.11.0

    v4.11.0 - complete MCP range parity and documentation
  • v4.10.1

    v4.10.1 - fix CI release deadlock and unify the test gate
  • v4.10.0

    v4.10.0 - multi-VM topology, handler contract tests, and CI that runs them
  • v4.9.4

    v4.9.4 - restore MCP SDK v1 compatibility for fresh installs
  • v4.9.3

    v4.9.3 - list make test-mcpunifier in the README
  • v4.9.2

    v4.9.2 - end-to-end test harness for the MCP unifier
  • v4.9.1

    v4.9.1 - a missing mcpunifier container no longer takes nginx down
  • v4.9.0

    v4.9.0 - unified MCP endpoint across every configured terminal