tickerall
Official Python client for the TickerAll REST + WebSocket API.
Place trades, stream live market data, and manage broker sessions programmatically — without an MT4/MT5 terminal in the path. No Windows VM, no Wine, no MetaTrader5 terminal to babysit, no thread-safety workarounds.
pip install tickerall
Requires Python 3.9+. Depends only on httpx and websocket-client.
Why
The official MetaTrader5 Python package only runs on Windows, drives a local terminal over a single-threaded IPC channel, and falls over under concurrency. TickerAll hosts the broker connection for you and exposes it as a clean HTTP + WebSocket API, so your bot can run anywhere — Linux, macOS, a container, a Raspberry Pi — and stream ticks instead of polling.
MetaTrader5 (local terminal) |
tickerall |
|
|---|---|---|
| OS | Windows only | anywhere Python runs |
| Live ticks | poll symbol_info_tick() per symbol |
push over WebSocket |
| Concurrency | single-threaded IPC, not thread-safe | stateless HTTP, thread-safe |
| Deploy | a terminal per account to babysit | pip install |
Quickstart
from tickerall import Tickerall
client = Tickerall(api_key="cf_live_...")
# Connect a broker account → get a TickerAll account_id
session = client.sessions.start(
broker="mt5",
server="Exness-MT5Trial7",
account=12345678,
password="...",
)
# Place a market order
order = client.orders.place(
session.account_id,
type="market",
symbol="BTCUSDm",
side="BUY",
volume=0.10,
stop_loss=58000.0,
take_profit=72000.0,
)
print(order.ticket, order.status)
client.sessions.end(session.account_id)
The client is a context manager too:
with Tickerall(api_key="cf_live_...") as client:
...
Terminal type (MOBILE / WEB / CLIENT)
terminal_type picks which client the connection presents AS — "MOBILE" (the
default), "WEB", or "CLIENT" (a desktop terminal). All expose the full surface
(account, quotes, positions, history). The type sets the broker-assigned order
origin (ENUM_DEAL_REASON): "MOBILE" → DEAL_REASON_MOBILE, "WEB" →
DEAL_REASON_WEB, "CLIENT" → DEAL_REASON_CLIENT — useful where a venue
distinguishes desktop-placed orders (e.g. some prop firms).
"WEB" requires the broker's web-terminal URL (web_terminal_url) — web
terminals are per-broker-domain, so the URL must be supplied. "MOBILE" and
"CLIENT" take neither web field:
session = client.sessions.start(
broker="mt5",
server="YourBroker-Server",
account=12345678,
password="...",
terminal_type="WEB",
web_terminal_url="https://mt5.yourbroker.com", # required for WEB
# web_endpoint="wss://host/path", # optional WS override (rare)
)
For a desktop-origin (DEAL_REASON_CLIENT) connection — no web URL needed:
session = client.sessions.start(
broker="mt5",
server="YourBroker-Server",
account=12345678,
password="...",
terminal_type="CLIENT",
)
Streaming — push, not poll
The stream runs on its own background thread. Register callbacks and go; it heartbeats, reconnects with backoff, and re-subscribes automatically.
client = Tickerall(api_key="cf_live_...")
session = client.sessions.start(broker="mt5", server="Exness-MT5Trial7",
account=12345678, password="...")
stream = client.stream.connect()
stream.on("tick", lambda e: print(e.symbol, e.bid, e.ask, e.timestamp))
stream.on("position", lambda e: print(e.event, e.position.ticket, e.position.profit))
stream.subscribe_ticks(session.account_id, ["BTCUSDm", "ETHUSDm"])
stream.subscribe_positions(session.account_id)
# ... your app runs ...
stream.close()
Keep an in-memory tick cache fresh (zero polling)
A common pattern: let the WebSocket fill a dict so price reads are O(1) with no network call — strictly better than polling a terminal per symbol.
latest: dict[str, "TickEvent"] = {}
stream = client.stream.connect()
stream.on("tick", lambda e: latest.__setitem__(e.symbol, e))
stream.subscribe_ticks(session.account_id, ["BTCUSDm", "ETHUSDm", "XAUUSDm"])
# Anywhere in your app — instant, no IPC, no thread-safety dance:
tick = latest.get("BTCUSDm")
Market data & history
# Historical OHLC candles (coarser timeframes reach further back)
bars = client.candles.get(session.account_id, symbol="BTCUSDm", hours=24, timeframe="M5")
for c in bars:
print(c.timestamp, c.open, c.high, c.low, c.close)
# Closed-trade history (recent broker window)
trades = client.history.get(session.account_id, symbol="BTCUSDm", limit=100)
# Tradeable symbols and their volume specs
symbols = client.accounts.symbols(session.account_id)
specs = client.accounts.symbol_specs(session.account_id) # min / max / step per symbol
# Remove an account from your roster (disconnects it + drops it from your list
# and billing; broker account and open positions are untouched). Reversible —
# reconnect the same login with sessions.start to re-add it.
client.accounts.remove(session.account_id)
Positions
detail = client.accounts.get(session.account_id)
for p in detail.positions:
print(p.ticket, p.symbol, p.side, p.volume, p.profit)
client.positions.modify(session.account_id, ticket=p.ticket, stop_loss=60000.0)
client.positions.close(session.account_id, ticket=p.ticket) # full close
client.positions.close(session.account_id, ticket=p.ticket, volume=0.05) # partial
Always-hot sessions & transparent re-arm
For connections that must stay up across restarts, use keep_alive. The
credentials live in this process's memory only (never persisted); if the
account goes cold (e.g. TickerAll restarted), the next call transparently
re-supplies them and retries once.
session = client.sessions.keep_alive(broker="mt5", server="Exness-MT5Trial7",
account=12345678, password="...")
# ... later, after an outage, this just works — the client re-arms under the hood:
client.accounts.get(session.account_id)
# Stop keeping it alive (drops the cached credentials):
client.sessions.stop_keep_alive(session.account_id)
Reliability — idempotency & queue-and-replay
State-changing calls (sessions.start, orders.place, positions.close,
positions.modify) carry a stable Idempotency-Key, so a retried call can't
double-execute. By default a transient connectivity failure
(TickerallServiceUnavailableError, .transient == True) fails fast so you
can re-decide with fresh prices:
from tickerall import TickerallServiceUnavailableError
try:
client.orders.place(account_id, type="market", symbol="BTCUSDm", side="BUY", volume=0.1)
except TickerallServiceUnavailableError:
... # momentary blip — safe to retry
For price-insensitive orders (pending orders, SL/TP edits) you can instead queue-and-replay until connectivity returns:
client.orders.place(
account_id, type="limit", symbol="BTCUSDm", side="BUY", volume=0.1, price=60000.0,
queue_if_reconnecting=True, queue_max_s=60.0,
)
Errors
All errors derive from TickerallApiError and carry .status, .code,
.request_id, .details, and .transient:
| Class | When |
|---|---|
TickerallAuthError |
401 — bad/missing API key |
TickerallForbiddenError |
403 — plan limit / reserved resource |
TickerallValidationError |
400 / 422 — malformed request |
TickerallNotFoundError |
404 — account / position not found |
TickerallBrokerError |
broker rejected or could not satisfy the request |
TickerallServiceUnavailableError |
transient — TickerAll momentarily unreachable (safe to retry) |
Using it from an async app
REST methods are synchronous and thread-safe, so call them from an event loop
via asyncio.to_thread:
detail = await asyncio.to_thread(client.accounts.get, account_id)
The stream is already non-blocking (its own thread) — callbacks fire as events arrive.
License
MIT © Miguel Santos
Release files for tickerall 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tickerall-0.4.0.tar.gz | 27.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tickerall-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.0 kB
Release files / tickerall-0.4.0.tar.gz
| Download URL | tickerall-0.4.0.tar.gz |
|---|---|
| Size | 27.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eb8bddb3a69995fe679496044cfad44717a6e7972b7bf3eb176c8610f1574c5f
|
|
BLAKE2b-256 checksum How to use checksums |
240093446f0c7e108a9a14202164eaf9ac84dc2d2d97bbd7a5958f69f6dd5ae7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / tickerall-0.4.0-py3-none-any.whl
| Download URL | tickerall-0.4.0-py3-none-any.whl |
|---|---|
| Size | 35.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1fcdc6df93ead71ef03f9c184b9605a9f6839263ee6570f03e4e05eaa2c44580
|
|
BLAKE2b-256 checksum How to use checksums |
9d8be4043227928bc32ba2425c60e0dbf5eacd81c2cf22c435cdbb1a71154e8f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|