A package that uses Wine, RPyC and a Windows Python version to allow using MetaTrader5 on GNU/Linux.
The fastest way to get started on Ubuntu 24.04 (Desktop or Server):
git clone https://github.com/lucas-campagna/mt5linux.git
cd mt5linux
./scripts/install.sh fullThis installs everything needed: Wine Staging, Windows Python, MetaTrader 5 terminal, and the RPyC bridge. All files are stored locally in the project folder.
After installation:
# Start MT5 and RPyC server
./bin/start-system.sh
# In Python
from mt5linux import MetaTrader5
mt5 = MetaTrader5(port=18812)
mt5.initialize()
mt5.terminal_info()
# When done
./bin/stop-system.shThe scripts/ folder contains bash scripts that automate the entire installation process.
| Environment | Display | Installation |
|---|---|---|
| Ubuntu Desktop (X11) | Native X11 | Standard |
| Ubuntu Desktop (Wayland) | XWayland | Standard (auto-detected) |
| Ubuntu Server (headless) | ThinLinc | Auto-installs ThinLinc for remote GUI |
The installer sets up:
- Wine Staging - Windows compatibility layer (from WineHQ repository)
- Windows Python 3.12 - Runs inside Wine prefix
- MetaTrader 5 packages -
MetaTrader5andrpycPython packages (Windows side) - MT5 Terminal - Downloaded and installed automatically
- Development tools -
pipx,hatch,uvfor Python development - Chromium browser - Default browser on server installations
All files are stored locally in the project folder (fully isolated):
project/
├── .mt5/ # Wine prefix (contains MT5, Windows Python)
├── .mt5env # Configuration file
├── .mt5-install-state # Installation progress tracker
└── bin/ # Launcher scripts
├── start-system.sh # Start MT5 + RPyC server
├── stop-system.sh # Stop everything
├── start-mt5.sh # Start MT5 terminal only
├── start-rpyc-server.sh # Start RPyC server only
└── system-status.sh # Show system status
# Clone the repository
git clone https://github.com/lucas-campagna/mt5linux.git
cd mt5linux
# Run the installer
./scripts/install.sh fullThe installer will:
- Install base dependencies (wget, curl, Python, pipx, hatch, uv)
- Add WineHQ repository and install Wine Staging
- Create a Wine prefix with Windows Python
- Download and install MetaTrader 5
- Configure RPyC server and create launcher scripts
On headless servers, the installer automatically installs ThinLinc for remote GUI access:
# Clone the repository
git clone https://github.com/lucas-campagna/mt5linux.git
cd mt5linux
# Run the installer (ThinLinc auto-installed on headless)
./scripts/install.sh fullAfter ThinLinc installation completes:
- Download the ThinLinc client
- Connect to your server (port 22)
- Login with your Ubuntu credentials
- Resume installation:
cd mt5linux
./scripts/install.sh resumeIf you prefer X server without remote access:
./scripts/install.sh full --xserver./scripts/install.sh [OPTIONS] [COMMAND]
Commands:
full Full installation (default)
resume Resume from last incomplete phase
phase PHASE Run specific phase only (base, wine, mt5, rpyc, verify)
verify Verify installation
status Show current installation state
Options:
--prefix PATH Wine prefix path (default: ./.mt5)
--port PORT RPyC port (default: 18812)
--host HOST RPyC host (default: localhost)
--name NAME Instance name (default: directory name)
--xserver Install X server only (no ThinLinc)
--thinlinc Force ThinLinc installation
-y, --yes Non-interactive mode
For manual installation without the scripts:
- Install Wine
- Install Python for Windows via Wine
- Install MT5 packages on Windows Python:
wine python.exe -m pip install MetaTrader5 rpyc- Install this package on Linux:
pip install mt5linux# Start both MT5 terminal and RPyC server
./bin/start-system.sh
# Start MT5 terminal only (useful for initial broker login)
./bin/start-mt5.sh
# Start RPyC server only (if MT5 already running)
./bin/start-rpyc-server.shfrom mt5linux import MetaTrader5
# Connect to the RPyC server
mt5 = MetaTrader5(
host='localhost', # default
port=18812 # default, or your custom port
)
# Initialize connection to MT5 terminal
mt5.initialize()
# Check terminal info
print(mt5.terminal_info())
# Get market data
rates = mt5.copy_rates_from_pos('EURUSD', mt5.TIMEFRAME_M1, 0, 1000)
# Place orders, manage positions, etc.
# See: https://www.mql5.com/en/docs/integration/python_metatrader5/
# Shutdown when done
mt5.shutdown()# Stop everything (MT5 + RPyC server)
./bin/stop-system.sh
# Check status
./bin/system-status.shFor trading projects managed with git, add mt5linux as a submodule:
# Create your trading project
mkdir ~/trading/my-strategy
cd ~/trading/my-strategy
git init
# Add mt5linux as a submodule
git submodule add https://github.com/lucas-campagna/mt5linux.git
git submodule update --init --recursive
# Install to the project root (not inside the submodule)
./mt5linux/scripts/install.sh full --project .This creates the following structure:
my-strategy/
├── mt5linux/ # Git submodule (tracked by git)
│ ├── scripts/
│ ├── mt5linux/
│ └── README.md
├── .mt5/ # Wine prefix (gitignored)
├── .mt5env # Configuration (gitignored)
├── bin/ # Launcher scripts
│ ├── start-system.sh
│ └── stop-system.sh
├── .gitignore
└── my_strategy.py # Your trading code
Add to your .gitignore:
# MT5 Linux files
.mt5/
.mt5env
.mt5-install-stateAfter cloning your project on a new machine:
git clone --recurse-submodules https://github.com/you/my-strategy.git
cd my-strategy
./mt5linux/scripts/install.sh full --project .
git submodule update --init --recursiveEach project folder is a fully isolated instance with its own Wine prefix and port:
# Strategy A (port 18812)
cd ~/trading/strategy-a
./mt5linux/scripts/install.sh full --project . --port 18812
./bin/start-system.sh
# Strategy B (port 18813)
cd ~/trading/strategy-b
./mt5linux/scripts/install.sh full --project . --port 18813
./bin/start-system.shConnect to each instance:
mt5_a = MetaTrader5(port=18812)
mt5_b = MetaTrader5(port=18813)Each instance has:
- Separate Wine prefix (different MT5 installations, broker accounts)
- Separate RPyC port (no conflicts)
- Separate configuration (
.mt5env)
Run the diagnostic script to check your installation:
./scripts/diagnose.shThis reports:
- System information
- Display environment (X11/Wayland/headless)
- Wine installation status
- Wine prefix contents
- MT5 terminal location
- RPyC server status
- Network/port status
- Running processes
The scripts automatically handle Wayland by using XWayland. If you still have issues:
# Force X11 session (logout and select "Ubuntu on Xorg" at login)
# Or run with virtual desktop:
./bin/start-system.sh --virtual-desktop# Check what's using the port
ss -tuln | grep 18812
# Use a different port
./scripts/setup-rpyc.sh --port 18813 setup# Check Wine prefix is valid
ls -la .mt5/drive_c/
# Try starting MT5 manually
WINEPREFIX=$(pwd)/.mt5 wine .mt5/drive_c/Program\ Files/MetaTrader\ 5/terminal64.exe# Check if server is running
./bin/system-status.sh
# Start the server
./bin/start-rpyc-server.sh
# Test connection
./scripts/setup-rpyc.sh test# Full uninstall (removes Wine prefix, scripts, config)
./scripts/uninstall.sh all
# Keep Wine prefix (only remove scripts and config)
./scripts/uninstall.sh all --keep-wine
# Just kill running processes
./scripts/uninstall.sh processes
# Remove launcher scripts only
./scripts/uninstall.sh scriptsNote: System packages (Wine, Python) are not removed. To remove Wine:
sudo apt remove winehq-staging| Script | Purpose |
|---|---|
scripts/install.sh |
Main installation orchestrator |
scripts/install-base.sh |
Install base dependencies (Python, pipx, hatch, uv) |
scripts/install-wine.sh |
Install Wine Staging and Windows Python |
scripts/install-mt5.sh |
Install MetaTrader 5 terminal |
scripts/setup-rpyc.sh |
Configure RPyC and create launcher scripts |
scripts/start-system.sh |
Start MT5 and RPyC server |
scripts/stop-system.sh |
Stop MT5 and RPyC server |
scripts/diagnose.sh |
Run diagnostic checks |
scripts/uninstall.sh |
Uninstall components |
| Script | Purpose |
|---|---|
scripts/lib/common.sh |
Shared utilities (logging, sudo management, ports) |
scripts/lib/detect.sh |
Environment detection (display, Wine, MT5 paths) |
This package includes type stubs for full IDE support. When you use mt5linux, you get:
- Autocomplete for all methods and constants
- Type checking with mypy, pyright, or Pylance
- Inline documentation of parameters and return types
from mt5linux import MetaTrader5
mt5 = MetaTrader5()
mt5.initialize() # IDE shows: (path?, *, login?, password?, ...) -> bool
info = mt5.account_info() # IDE knows: AccountInfo | None
if info:
print(info.balance) # IDE knows: float
print(info.currency) # IDE knows: strThe type information is stored in mt5linux/__init__.pyi, a stub file that mirrors the official MetaTrader5 API. This file is:
- Auto-generated from the running MetaTrader5 instance via runtime introspection
- Committed to the repository so users get type support without extra setup
- Validated to ensure it matches the actual MetaTrader5 API
The package also includes a py.typed marker file (PEP 561) that tells type checkers this package provides type information.
When MetaQuotes releases a new version of the MetaTrader5 Python package, the type stubs may need updating. This section explains how to keep them in sync.
Update the stubs when:
- MetaTrader5 package updates - New fields added to
AccountInfo,SymbolInfo, etc. - New API methods added - MetaQuotes adds new functions
- Return type changes - Unlikely, but possible
The stub generator requires a running MT5 instance:
# Start MT5 and RPyC server
./bin/start-system.sh
# Verify the server is accessible
./scripts/setup-rpyc.sh testRun the stub generator script:
# Using hatch (recommended)
hatch run python scripts/generate_stubs.py
# Or directly with the venv
.venv/bin/python scripts/generate_stubs.py
# Specify custom host/port if needed
.venv/bin/python scripts/generate_stubs.py --host localhost --port 18812The script will:
- Connect to the MT5 terminal via rpyc
- Introspect
AccountInfoandTerminalInfofields from runtime - Extract all constants with their literal values
- Generate the complete
mt5linux/__init__.pyifile
| Component | Source | Notes |
|---|---|---|
AccountInfo fields |
Runtime introspection | Changes detected automatically |
TerminalInfo fields |
Runtime introspection | Changes detected automatically |
| Constants (202 values) | Runtime introspection | All TIMEFRAME_*, ORDER_*, etc. |
SymbolInfo, TradeOrder, etc. |
Official documentation | Require active trading to introspect |
| Method signatures | Official documentation | Stable API, rarely changes |
After regenerating, verify the stubs match the runtime:
.venv/bin/python scripts/generate_stubs.py --checkThis compares the generated output against the committed .pyi file. If they differ, it exits with an error.
After regeneration, review what changed:
git diff mt5linux/__init__.pyiLook for:
- New fields in
AccountInfoorTerminalInfo - New constants (usually new enum values)
- Changed values (rare, would indicate API change)
# Stage the updated stubs
git add mt5linux/__init__.pyi
# Commit with the MT5 version
git commit -m "chore(types): update stubs for MetaTrader5 v$(cat .mt5/drive_c/Python312/Lib/site-packages/metatrader5-*.dist-info/METADATA | grep ^Version | cut -d' ' -f2)"Add stub validation to the CI pipeline:
# .github/workflows/validate-stubs.yml
name: Validate Type Stubs
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dependencies
run: pip install rpyc numpy
- name: Start MT5 system
run: ./bin/start-system.sh
- name: Validate stubs match runtime
run: python scripts/generate_stubs.py --check
- name: Stop MT5 system
run: ./bin/stop-system.shscripts/generate_stubs.py [OPTIONS]
Options:
--check Validate existing stubs match runtime (exit 1 if mismatch)
--host HOST rpyc server host (default: localhost)
--port PORT rpyc server port (default: 18812)
--output PATH Output file path (default: mt5linux/__init__.pyi)
# Ensure MT5 and rpyc are running
./bin/system-status.sh
# Start if needed
./bin/start-system.shSome types (like SymbolInfo, TradeOrder) require market data or trading activity to introspect. These are defined manually in the script based on official documentation. If MetaQuotes adds fields to these types:
- Check the MQL5 Python documentation
- Update the
generate_manually_defined_types()function inscripts/generate_stubs.py
If --check fails but you haven't changed MT5:
- The MT5 version in CI may differ from your local version
- Regenerate stubs with the same MT5 version used in CI
- Or update CI to use the same MT5 version
mt5linux/
├── __init__.py # Runtime implementation
├── __init__.pyi # Type stubs (auto-generated)
└── py.typed # PEP 561 marker
scripts/
└── generate_stubs.py # Stub generator script
The .mt5env file stores instance configuration:
# MT5 Linux Configuration
MT5_WINE_PREFIX="/path/to/project/.mt5"
MT5_RPYC_PORT=18812
MT5_RPYC_HOST="localhost"
MT5_VENV="/path/to/project/.venv"
MT5_INSTANCE_NAME="mt5linux"- Ubuntu 24.04 LTS (Desktop or Server)
- 64-bit system
- ~2GB disk space for Wine prefix
- Internet connection for downloads
MIT License