TICKERALL!
← All posts
August 23, 20265 min read

Place Your First MetaTrader 5 Trade over a REST API

Go from zero to a live MetaTrader 5 order with a REST API — start a session on a demo account, place a market order with SL/TP in Python, read it back, and close it.

MetaTrader 5REST APIPythonTrading

Placing a MetaTrader 5 trade from your own code has traditionally meant one of two unpleasant paths: run the desktop terminal somewhere and script it, or wire up an Expert Advisor and talk to it over some fragile bridge. Either way there's a Windows box, a terminal process, and a VPS in your critical path — for what is, conceptually, a single POST request.

It doesn't have to be that. With a hosted MetaTrader API, your code talks HTTPS to an endpoint, the endpoint holds the broker session, and you place an order the same way you'd hit any other REST service. No terminal in the path.

Your code orders.place(...) Hosted API holds your session ticket Broker executes
A place-order call goes out over HTTPS; the ticket and status come back. That's the whole loop.

This walkthrough goes from an empty file to a live order and back — a market order with a stop-loss and take-profit, read back, then closed. We'll do the whole thing on a demo account, and I mean that as a hard rule, not a suggestion.

Do your first order on a demo account. Verify it's a demo before you send. The API will happily execute against a funded live account if that's what your session points at. A test order sized for play money becomes a real position with real money on the other side. Before your first orders.place, read the account back and confirm you're on the demo/trial account you intended — not a live one.

Get an API key and install the SDK

Grab a key from your TickerAll dashboard — it looks like cf_live_.... Then:

pip install tickerall

The Python SDK is a thin wrapper over the REST API. Everything below is a plain HTTP call underneath, so if you'd rather use requests or another language, the shapes are the same — see the REST API developer's guide for the raw endpoints.

Start a session for your demo account

A session is the hosted side holding a logged-in connection to your broker so you don't have to. You hand it your broker credentials once; you get back an account_id that identifies this connection in every later call.

from tickerall import Tickerall

client = Tickerall(api_key="cf_live_...")

session = client.sessions.start(
    broker="mt5",
    server="Exness-MT5Trial7",   # a DEMO/trial server
    account=12345678,            # your demo login
    password="...",
)

# This account_id is what every later call takes as its first argument.
account_id = session.account_id

Note the server: Exness-MT5Trial7 is a trial server, and that login is a trial login. This is the moment to be deliberate — the credentials you pass here decide whether the next call touches play money or real money.

Confirm you're on demo, then place the order

Before sending anything, read the account back and eyeball it. A demo balance is funny money; if the numbers look like your actual savings, stop.

detail = client.accounts.get(account_id)
print(f"balance={detail.balance}  equity={detail.equity}")
# Sanity-check: this should be your demo account's play-money balance.

Happy with it? Place a market order. We'll buy 0.10 lots of BTCUSDm with a stop-loss and take-profit attached, so risk is bounded the instant the position opens rather than in a follow-up call.

order = client.orders.place(
    account_id,
    type="market",
    symbol="BTCUSDm",
    side="BUY",
    volume=0.10,
    stop_loss=58000.0,
    take_profit=72000.0,
)

print(order.ticket, order.status)

Here's what each field means:

Field What it is
type "market" fills now at the current price. "limit" / "stop" are pending and also require a price=.
side "BUY" or "SELL".
volume Size in lots (0.10 = a tenth of a standard lot).
stop_loss Price at which the broker closes the position to cap a loss. Optional.
take_profit Price at which the broker closes the position to book a gain. Optional.

What comes back is an order with a ticket — the broker's identifier for this order, which you'll use to read or close the resulting position — and a status telling you how the broker handled it (accepted, filled, rejected). Always check the status; a call that returns without raising still tells you what the broker actually did.

Read the position back

Placing an order creates a position. Read the account again and you'll find it in detail.positions:

detail = client.accounts.get(account_id)

for p in detail.positions:
    print(p.ticket, p.symbol, p.side, p.volume, p.profit)

Each position carries its own ticket (not the same number as the order ticket — it's the position id), plus symbol, side, volume, and a live profit that moves with the market. If you want to tighten risk after the fact, modify the stop:

client.positions.modify(account_id, ticket=p.ticket, stop_loss=60000.0)

Close it

Closing is the mirror of opening — hand back the position ticket. Close the whole thing, or shave off part of it:

client.positions.close(account_id, ticket=p.ticket)                 # full close
client.positions.close(account_id, ticket=p.ticket, volume=0.05)    # partial

A partial close leaves the rest of the position open at the same entry; a full close flattens it. Either way you'll see the change reflected the next time you accounts.get.

When you're done, end the session so the hosted side can drop the broker connection:

client.sessions.end(account_id)

Retries won't double-execute

The one thing that makes people nervous about placing trades over HTTP: what if the request times out after the broker filled it, and my retry opens a second position? Every state-changing call here carries an Idempotency-Key, so a retried call is recognized as the same call and can't execute twice. That means you can retry safely on the errors that are safe to retry:

from tickerall import (
    TickerallServiceUnavailableError,
    TickerallBrokerError,
    TickerallValidationError,
    TickerallAuthError,
)

try:
    order = client.orders.place(
        account_id, type="market", symbol="BTCUSDm",
        side="BUY", volume=0.10, stop_loss=58000.0, take_profit=72000.0,
    )
except TickerallServiceUnavailableError as e:
    if e.transient:
        order = client.orders.place(   # same intent; idempotency guards it
            account_id, type="market", symbol="BTCUSDm",
            side="BUY", volume=0.10, stop_loss=58000.0, take_profit=72000.0,
        )
except TickerallValidationError:
    ...   # bad field — a wrong symbol, a size below the broker's minimum
except TickerallBrokerError:
    ...   # the broker rejected it (e.g. market closed, not enough margin)
except TickerallAuthError:
    ...   # key or session problem

The distinction worth internalizing: TickerallServiceUnavailableError with .transient set is the retry case. TickerallValidationError and TickerallBrokerError mean the request itself was wrong or refused — retrying sends the same bad request, so fix the input or handle the rejection instead.

Where to go next

You've now done the full round trip: session up, order placed with bounded risk, read back, closed, session down — no terminal, no Wine, no VPS in the path. From here the natural next step is feeding real-time prices to your strategy, which is a WebSocket, not a poll loop. And if you want the full endpoint reference behind this SDK, the REST API developer's guide lays it out.

Keep the demo-first discipline until your code is boring and predictable. When you do point it at a live account, the only thing that changes is the credentials in sessions.start — which is exactly why verifying them is the whole game.

Full API reference: tickerall.com/docs

Was this useful?

Comments

Leave a comment

Comments are public.
Place Your First MetaTrader 5 Trade over a REST API · Ticker All!