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.1
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.1.tar.gz | 27.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tickerall-0.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.3 kB
Release files / tickerall-0.4.1.tar.gz
| Download URL | tickerall-0.4.1.tar.gz |
|---|---|
| Size | 27.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ee9d3c98daaa10b72b2c85dcf4ccf4b349bcae015e46cc48b77d0756f8d4c11f
|
|
BLAKE2b-256 checksum How to use checksums |
de1c5d728f2a16e0a35563f7f04666f3205db88b38f81a2c40ce2e1b9eceb4a9
|
| 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.1-py3-none-any.whl
| Download URL | tickerall-0.4.1-py3-none-any.whl |
|---|---|
| Size | 35.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8899ca2d1b89185bc9776d544b13f8fc5d2710679239e3ee36ec9660815a9370
|
|
BLAKE2b-256 checksum How to use checksums |
8584385d6ec3f6beb8ce127ab776b2c8a86f745dac7f0d42a41a31e892200d79
|
| 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}
|