Skip to main content

REST and WebSocket API project for MetaTrader 5

Project description

open-api-mt5

MetaTrader 5 API service with FastAPI.

Important limitation

This API controls a single MT5 terminal/session instance per running service process.

  • A single API instance can be connected to only one account at a time.
  • /account/connect switches that single active session.
  • If you run multiple API services, use separate MT5 terminal instances/data folders for reliable isolation.

Setup

  1. Create a virtual environment:
    • Windows PowerShell: python -m venv .venv
  2. Activate it:
    • .\.venv\Scripts\Activate.ps1
  3. Install dependencies:
    • python -m pip install -U pip
    • pip install -e .

MT5 startup config

The API initializes MetaTrader 5 when FastAPI starts and closes it when FastAPI stops. It also checks MT5 connection every 5 seconds and tries to reconnect automatically if disconnected.

You can configure startup with a server_config.json file in the project directory:

{
  "path": "C:\\Program Files\\MetaTrader 5\\terminal64.exe",
  "username": "12345678",
  "password": "your-password",
  "server": "YourBroker-Server",
  "port": 8000,
  "apiKey": "optional-api-key"
}

port and apiKey are optional. If the JSON file does not exist, the app uses the environment variables and command-line parameters by default.

You can also set these environment variables in PowerShell before running:

$env:MT5_PATH = "C:\Program Files\MetaTrader 5\terminal64.exe"
$env:MT5_LOGIN = "12345678"
$env:MT5_PASSWORD = "your-password"
$env:MT5_SERVER = "YourBroker-Server"

MT5_PATH is optional if MT5 is already discoverable, but setting it is recommended. Mode, apiKey, apiSecret, and registryUrl are startup settings and are not stored by /account/connect.

Run

open-api-mt5

Optional flags:

open-api-mt5 --port 9000
open-api-mt5 --host 0.0.0.0 --port 8000
open-api-mt5 --mode standalone
open-api-mt5 --mode secure --api-key your-api-key
open-api-mt5 --mode secure-client --api-key your-api-key --api-secret your-api-secret
open-api-mt5 --registry-url https://example.com/registry
open-api-mt5 --reload
open-api-mt5 --config C:\path\to\server_config.json

Default port is 8000.

Run unit tests with coverage:

pip install -e ".[test]"
pytest

The calendar, bars, and trade services require 100% statement coverage.

Run only the mocked news-close integration scenarios:

pytest -m integration --no-cov

API docs:

  • Swagger UI: http://127.0.0.1:8000/docs
  • WebSocket docs in Swagger:
    • GET /ws/positions/open/docs

Health endpoint:

  • GET http://127.0.0.1:8000/health

Bars endpoints:

  • GET http://127.0.0.1:8000/bars/{symbol}?timeframe=M1&n=100
  • GET http://127.0.0.1:8000/bars/{symbol}/range?timeframe=M1&fromDate=2026-03-20T08:00:00Z&toDate=2026-03-20T12:00:00Z
  • GET http://127.0.0.1:8000/quotes/{symbol}
  • GET http://127.0.0.1:8000/ticks/{symbol}?count=100
  • GET http://127.0.0.1:8000/market-depth/{symbol}
  • GET http://127.0.0.1:8000/exposure
  • GET http://127.0.0.1:8000/exposure/{symbol}

Account connection endpoints:

  • POST http://127.0.0.1:8000/account/connect
    • Body: username, password, server, optional path
    • Example body:
      {
        "username": "12345678",
        "password": "your-password",
        "server": "YourBroker-Server",
        "path": "C:\\Program Files\\MetaTrader 5\\terminal64.exe"
      }
      
  • POST http://127.0.0.1:8000/account/disconnect
  • If --registry-url is set at startup, the API sends a POST call to that URL with JSON body fields address, port, apiKey, and accountId

Security modes:

  • Set the mode when starting the app with --mode standalone, --mode secure, or --mode secure-client
  • Set the headers credentials when starting the app with --api-key and, for secure-client, --api-secret
  • Set the registry target when starting the app with --registry-url
  • standalone: default mode, no X-apiKey or X-apiSecret header checks
  • secure: every HTTP endpoint and the open positions WebSocket require X-apiKey to match the locally stored apiKey
  • secure-client: every HTTP endpoint and the open positions WebSocket require both X-apiKey and X-apiSecret to match the locally stored values

Server info endpoint:

  • GET http://127.0.0.1:8000/api/server/info
  • Returns JSON with the locally stored apiKey and the detected machine ipAddress

Trade history endpoint:

  • GET http://127.0.0.1:8000/trades/history
  • Optional query params: fromDate, toDate (ISO datetime, UTC recommended)
  • If omitted, it returns the last 7 days by default

Modify an open position's stop loss / take profit:

  • POST http://127.0.0.1:8000/positions/modify
    • Body: ticket, optional sl, optional tp, optional comment
    • At least one of sl or tp is required. If one is omitted, its current MT5 value is kept.
    • Example body:
      {
        "ticket": 123456789,
        "sl": 1.0825,
        "tp": 1.095
      }
      

Open position details:

  • GET http://127.0.0.1:8000/positions/{ticket}/details
  • Returns entryPrice, stopLossPrice, takeProfitPrice, volume, contractSize, stopLossValue, and takeProfitValue
  • Value formula:
    • Buy stop loss: (entryPrice - stopLossPrice) * volume * contractSize
    • Buy take profit: (takeProfitPrice - entryPrice) * volume * contractSize
    • Sell stop loss: (stopLossPrice - entryPrice) * volume * contractSize
    • Sell take profit: (entryPrice - takeProfitPrice) * volume * contractSize

Adjust an open position's stop loss / take profit by money values:

  • POST http://127.0.0.1:8000/positions/adjust-by-money
    • Body: ticket, optional stopLossValueInMoney, optional takeProfitValueInMoney, optional comment
    • Defaults: stopLossValueInMoney = 10, takeProfitValueInMoney = 30
    • The API converts money values to SL/TP price distances using the position entry price, volume, and symbol contract size.
    • If the exact value cannot be represented by the symbol price step, the API uses the nearest lower value.
    • Example body:
      {
        "ticket": 123456789,
        "stopLossValueInMoney": 10,
        "takeProfitValueInMoney": 30
      }
      
    • Response includes stopLossPrice, takeProfitPrice, stopLossValueInMoney, and takeProfitValueInMoney after rounding.

Close orders before economic news:

  • POST /orders accepts optional closeOnNews, for example M15_High, M10_Medium, or M5_Low
  • New orders with closeOnNews are rejected with HTTP 409 when a matching event is already inside the configured close window
  • GET /orders/news-close/jobs lists the current tagged pending orders and open positions watched by the news-close checker
  • The policy is stored in a durable SQLite file at .db/news_close_jobs.sqlite3 under the folder where the API process was started
  • Restart the API from the same folder to reuse the existing news-close jobs; set NEWS_CLOSE_DB_PATH only if you need a custom database path
  • High closes only for high-impact events; Medium closes for medium/high; Low closes for low/medium/high
  • Events are matched against the symbol's base, profit, or margin currency
  • Tagged open positions are closed and tagged pending orders are cancelled when an event enters the configured time window
  • Modifying SL/TP values, including money-based adjustments, keeps the stored news policy unchanged
  • The check runs once at startup and every 60 seconds; orders without closeOnNews are unchanged
  • Fair Economy events include an explicit timezone and are compared in UTC. If you test with timezone-less event timestamps, the API also considers the local computer timezone; set LOCAL_TIMEZONE (for example Europe/Paris) only if you need to override the OS timezone.

Calendar events endpoint:

  • GET http://127.0.0.1:8000/calendar/events
  • The default source is the Fair Economy current-week feed, cached in calendar_cache.json
  • The cache is loaded at startup, retried once on startup failure, refreshed every Monday at 00:00 UTC, and loaded lazily when missing or stale
  • Optional query params: source (fairEconomy or mt5), fromDate, toDate (ISO datetime), country/currency (example: USD), and impact (Low, Medium, High, or Holiday)
  • Fair Economy defaults to the current Monday-through-Sunday UTC week
  • Use source=mt5 for the previous MT5 calendar behavior (default range: last 7 days to next 7 days)
  • Optional environment variables: FAIR_ECONOMY_CALENDAR_URL and FAIR_ECONOMY_CALENDAR_CACHE_PATH

WebSocket streams

Open positions stream:

  • ws://127.0.0.1:8000/ws/positions/open
  • Optional query param: intervalSeconds (poll interval, bounded to 0.2..60)
  • Events:
    • subscribed
    • positionsSnapshot
    • error
  • positionsSnapshot includes:
    • positions[].pnl (position PnL, sourced from MT5 profit)
    • totalPnl (sum of all open positions PnL)

Example JavaScript client:

const ws = new WebSocket("ws://127.0.0.1:8000/ws/positions/open?intervalSeconds=1");
ws.onmessage = (event) => {
  const payload = JSON.parse(event.data);
  console.log(payload.event, payload);
};

Build and publish package

Build distribution files locally:

python -m pip install --upgrade build
python -m build

Install from the local build to smoke-test it:

python -m pip install --force-reinstall dist/*.whl
open-api-mt5 --help

Install from PyPI and run:

pip install open-api-mt5
open-api-mt5 --port 8000

Release to PyPI

The repository includes .github/workflows/publish.yml, which runs tests, builds the package, and publishes to PyPI with a PyPI API token. It only runs from release branches named like release/0.5.

One-time PyPI token setup:

  1. Create or open your PyPI account.
  2. Create a PyPI API token. If the project already exists on PyPI, prefer a project-scoped token for open-api-mt5; otherwise create an account-scoped token for the first upload.
  3. In GitHub, open repository Settings -> Secrets and variables -> Actions.
  4. Add a repository secret named PYPI_API_TOKEN with the token value from PyPI. The workflow uses PyPI username __token__ and this secret as the password.
  5. Optional: create a GitHub environment named pypi and add required reviewers if you want manual approval before publishing.

Prepare a release:

  1. Update version in pyproject.toml.
  2. Run tests:
    python -m pip install -e ".[test]"
    python -m pytest
    
  3. Build locally:
    python -m pip install --upgrade build
    python -m build
    
  4. Commit the version change:
    git add pyproject.toml
    git commit -m "Release 0.6.1"
    
  5. Create and push a release branch:
    git checkout -b release/0.6.1
    git push origin release/0.6.1
    
  6. The Publish to PyPI workflow runs on pushes to release/**. You can also run it manually from GitHub Actions, but select a release/** branch such as release/0.6.1.

PyPI rejects reused versions, so every release must have a new pyproject.toml version.

Manual upload with a token, if needed:

python -m pip install --upgrade twine
python -m twine upload dist/* -u __token__ -p "<your-pypi-token>"

Optional: standalone executable (no Python required on target machine)

If you want users to run it without installing Python, build an executable:

python -m pip install pyinstaller
pyinstaller --onefile --name open-api-mt5 app/cli.py

The executable will be in dist/open-api-mt5.exe.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

open_api_mt5-0.7.1.tar.gz (51.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

open_api_mt5-0.7.1-py3-none-any.whl (35.9 kB view details)

Uploaded Python 3

File details

Details for the file open_api_mt5-0.7.1.tar.gz.

File metadata

  • Download URL: open_api_mt5-0.7.1.tar.gz
  • Upload date:
  • Size: 51.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for open_api_mt5-0.7.1.tar.gz
Algorithm Hash digest
SHA256 57f0ff367b2f663b2d05f4b9cafeb26d6991fd8f6a4123468e447347ef30f03c
MD5 ddc6a4d299457219bfe609b5ef9381cd
BLAKE2b-256 d0d63a38f829703f1e746ee4172eb43e833578eba1fd36b88e7e6653e412b1d2

See more details on using hashes here.

File details

Details for the file open_api_mt5-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: open_api_mt5-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 35.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for open_api_mt5-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7159adb0695fc8fc0282554cac8b13b86620d784c87ddeb62236b33407a61afb
MD5 0c5fba3eadd07f4ef3a80b5b786834ad
BLAKE2b-256 82ea4c4213bb7079299c9f69d3922306f2439627314b710ad717a2dcbc516c3d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page