TICKERALL!
← All posts
August 23, 20265 min read

Deploying a MetaTrader 5 Trading Bot to the Cloud

Ship an MT5 trading bot as a plain Python process on any Linux box, container, or Raspberry Pi — no terminal, no Wine, no Windows VPS. Docker + systemd included.

MetaTrader 5PythonDevOpsCloud

The traditional way to run a MetaTrader 5 bot in production is a Windows VPS with the terminal open around the clock. You RDP in to check it's still alive, you babysit the terminal through updates and reboots, and your whole strategy is pinned to one Windows box that has to keep a GUI application running forever. If that VPS hiccups, your bot goes dark and you find out later.

There's a simpler shape. When the broker connection is hosted, your bot stops being a Windows appliance and becomes what it always should have been: a normal Python process. It reads ticks, makes decisions, and places orders over HTTP and WebSocket. That process doesn't care what operating system it's on. It runs on a Linux VM, inside a container, or on a Raspberry Pi in the corner of your desk — because nothing on that machine needs a MetaTrader terminal.

Laptop bot Cloud VM bot Raspberry Pi bot Hosted API TickerAll
Same bot, three machines, zero terminals — the broker connection lives behind the hosted API, not on your host.

If you're new to driving MT5 from Python this way, start with running MetaTrader 5 from Python on Linux for the basics. This post is about taking that bot to production.

A minimal but real bot

Here's the whole thing: connect an account, stream ticks, and act on one. It's deliberately small so the deployment concerns stand out, but every call is a real one you'd ship.

import os
from tickerall import Tickerall, TickerallServiceUnavailableError, TickerallBrokerError

client = Tickerall(api_key=os.environ["TICKERALL_API_KEY"])

# keep_alive: a connection that survives restarts and outages. Credentials live
# in this process's memory only; they are never persisted anywhere.
session = client.sessions.keep_alive(
    broker="mt5",
    server=os.environ["MT5_SERVER"],
    account=int(os.environ["MT5_ACCOUNT"]),
    password=os.environ["MT5_PASSWORD"],
)

def on_tick(e):
    # Trivial illustrative rule — replace with your real strategy.
    if e.symbol == "BTCUSDm" and e.ask and e.ask < 100_000:
        try:
            order = client.orders.place(
                session.account_id,
                type="market",
                symbol="BTCUSDm",
                side="BUY",
                volume=0.10,
            )
            print("placed", order)
        except TickerallServiceUnavailableError as err:
            # Transient — the retry is safe (see the note on idempotency below).
            print("temporary outage, will retry next tick:", err.transient)
        except TickerallBrokerError as err:
            # The broker rejected it (margin, market closed, bad volume) — don't retry blindly.
            print("broker rejected order:", err)

stream = client.stream.connect()
stream.on("tick", on_tick)            # on(event, callback) — not a decorator
stream.subscribe_ticks(session.account_id, ["BTCUSDm"])

Two things to notice. First, stream.on(...) takes a callback — the stream runs on its own background thread, handling heartbeats, reconnects, and re-subscribing after a drop for you. Second, there's no run_forever(). In a standalone process you keep it alive yourself:

import time

try:
    while True:
        time.sleep(60)
except KeyboardInterrupt:
    stream.close()
    client.sessions.stop_keep_alive(session.account_id)

For a deeper look at the tick stream — event shapes, subscribing to many symbols, back-pressure — see streaming live MT5 tick data over WebSocket in Python.

Make it survive restarts

Production processes restart. The host reboots, you deploy a new version, the orchestrator moves the container. The question that matters is: what happens to your broker connection when your process comes back?

That's what sessions.keep_alive is for. You hand it the credentials once, and it keeps the broker session warm. If the account goes cold — a broker-side drop, a network blip, an outage on either end — the next call transparently re-supplies the credentials and retries once, so your code doesn't have to hand-roll a reconnect loop. The credentials themselves stay in your process's memory for the lifetime of the run and are never written to disk.

When your process shuts down cleanly, tell the service to stop keeping the connection warm:

client.sessions.stop_keep_alive(session.account_id)

State-changing calls like orders.place carry an idempotency key under the hood, so a retry after a transient failure can't accidentally place the order twice. That's why the except TickerallServiceUnavailableError branch above can safely retry: err.transient tells you it's worth another attempt, and the idempotency key guarantees you won't double-fill.

Never hardcode credentials. Everything the bot needs — the API key, the broker server, the account number, the password — comes from environment variables. They never appear in your source, your image, or your git history. The hosted session holds them in memory only and persists nothing, so a leaked repo or a snapshotted disk gives up no secrets.

Package it in a container

Because the bot is a plain Python process with no terminal, no Wine layer, and no GUI, the container is boring in the best way — a slim Python base, your code, and the SDK:

FROM python:3.12-slim

WORKDIR /app

# Install deps first so this layer caches across code changes.
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY bot.py .

# Run as a non-root user.
RUN useradd --create-home bot
USER bot

CMD ["python", "-u", "bot.py"]

Your requirements.txt is a single line:

tickerall

Pass the secrets in at run time — never bake them into the image:

docker build -t mt5-bot .
docker run -d --name mt5-bot --restart unless-stopped \
  -e TICKERALL_API_KEY \
  -e MT5_SERVER \
  -e MT5_ACCOUNT \
  -e MT5_PASSWORD \
  mt5-bot

The -e VAR form (no =value) forwards the value from your shell or your orchestrator's secret store, so nothing sensitive lands on the command line. With --restart unless-stopped, Docker brings the bot back after a crash or a host reboot, and keep_alive re-warms the broker session on the way up.

Or run it under systemd on a plain VM

Not everything needs a container. On a bare Linux VM, a systemd unit gives you the same restart resilience with journal logging for free. Drop your secrets in a root-only env file:

# /etc/mt5-bot.env  (chmod 600, owned by root)
TICKERALL_API_KEY=ta_live_xxx
MT5_SERVER=Exness-MT5Trial
MT5_ACCOUNT=12345678
MT5_PASSWORD=your-broker-password
# /etc/systemd/system/mt5-bot.service
[Unit]
Description=MT5 trading bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=bot
EnvironmentFile=/etc/mt5-bot.env
WorkingDirectory=/opt/mt5-bot
ExecStart=/opt/mt5-bot/venv/bin/python -u bot.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mt5-bot
journalctl -u mt5-bot -f      # follow the logs

EnvironmentFile keeps the credentials out of the unit file and out of process listings, Restart=on-failure handles crashes, and After=network-online.target makes sure the box has networking before your bot tries its first connect. That's the entire ops surface — no terminal to keep open, no GUI session, no RDP.

The ops win, stated plainly. A Windows-VPS-with-terminal setup means a GUI app that must stay logged in, a heavier and pricier instance, manual terminal updates, and a single-OS lock-in. Here the deployable unit is a stateless Linux process. It fits your existing container platform or systemd, scales by running more copies, and moves between hosts without carrying a terminal along.

Wrap-up

Once the broker connection is hosted, deploying an MT5 bot stops being a MetaTrader problem and becomes an ordinary devops problem — one you already know how to solve. Stream ticks, place orders, keep the session warm across restarts, feed secrets through the environment, and run it wherever your other services run: a container, a VM, or a Pi. No Wine, no Windows, no terminal babysitting.

The full API reference — sessions, streaming, orders, candles, and history — is at tickerall.com/docs.

Was this useful?

Comments

Leave a comment

Comments are public.
Deploying a MetaTrader 5 Trading Bot to the Cloud · Ticker All!