atjte — ATJ trading engines
Cross-venue arbitrage market making: a crypto leg on an exchange (Kraken spot, Kraken Futures, Coinbase, Binance, Hyperliquid, Lighter) quoted against a CFD leg on MetaTrader 5, with the CFD hedged fill by fill.
Every platform connection goes through a GATEWAY (atjte.gateways): a
per-account / per-machine / per-terminal daemon that owns the keys, the
sockets, the order transport and a per-bot dead man's switch, and leases them
to the bots over loopback. A bot holds no venue key and no terminal login and
opens no venue connection of its own.
atjte is the open-source engine and its gateways (MIT). ATJ's strategy
control panel is a separate application built on it.
Install
pip install atjte[mt5] # from PyPI
pip install -e ".[mt5]" # from a checkout of this repository (editable)
mt5 pulls the MetaTrader 5 terminal API (Windows only; the MT5 GATEWAY is
the one process that needs it). ctrader adds the cTrader Open API
connector. The Lighter gateway signs through Lighter's own signer library
(lighter_library_path, from github.com/elliottech/lighter-python). ccxt and
simplefix (the Kraken FIX gateway's codec) are always installed.
The gateways
| gateway | serves | one per | bot connector (VENUE_CLIENT) |
|---|---|---|---|
atjte.gateways.ccxt |
Coinbase, Binance, Kraken spot, Kraken Futures — any venue without its own | exchange (several accounts) | CcxtGatewayClient (default for those venues) |
atjte.gateways.fix |
Kraken spot / Kraken Futures orders over FIX 4.4; reads, prices, fills over its CCXT side | SenderCompID | KrakenFixClient / KrakenFuturesFixClient (ORDER_TRANSPORT = 'fix') |
atjte.gateways.hyperliquid |
Hyperliquid (10 websockets per IP) | machine | HyperliquidGatewayClient (default) |
atjte.gateways.lighter |
Lighter (one signer and nonce per API key) | machine | LighterGatewayClient (default) |
atjte.gateways.mt5 |
the MT5 terminal: ticks, hedges, the deal history | terminal | MT5GatewayClient (MT5_CLIENT, default) |
atjte-gateway --new coinbase_main --venue ccxt --exchange coinbase
atjte-gateway --new kraken_live --venue kraken # Kraken FIX (krakenfutures: -DRV)
atjte-gateway --new hl_main --venue hyperliquid
atjte-gateway --new mt5_main --venue mt5
atjte-gateway --list
atjte-gateway coinbase_main # run it (or: the panel's Gateways page)
A gateway is a folder, <workspace>/gateways/<kind>/<name>/: gateway.json
(what it connects to, its accounts, its listen port) and its own
gateway.env (the keys — read from that file only). The folders are never
tracked; the templates ship in atjte/gateways/templates/. A bot names its
gateway's port and account in VENUE_CLIENT_OPTIONS ({'gateway_port': 5650,
'account': 'main'}) and reads the loopback token by NAME from env/.env.
The bot's connectors (atjte.clients.gateway) keep a CCXT instance for the
market MATH only, loaded with the markets the gateway hands over; its HTTP
entry point refuses, so no call can reach a venue directly. The engine
refuses any VENUE_CLIENT / MT5_CLIENT that does not go through a gateway.
What is in the box
| package | what |
|---|---|
atjte.clients |
one unified connector per venue (KrakenClient, KrakenFuturesClient, CoinbaseClient, MT5Client, CTraderClient, generic CCXTClient) over shared dataclasses (Account, Margin, Position, Order, Trade, Ticker) and the UniversalClient ABC — what the GATEWAYS build their venue side on. atjte.clients.gateway holds the bot-side connectors (see above). Imports are lazy: one venue's SDK is never required to use another. |
atjte.gateways / atjte.fix |
the gateways (see above), and the Kraken FIX 4.4 protocol layer the Kraken FIX gateway runs (codec, kraken for the spot and derivatives dialects, session; atjte fixcheck <gateway> proves a session). |
atjte.engines.perp / atjte.engines.spot |
the two ENGINE LITERALS of a Kraken project — aliases of the one engine since 2026-09-13 (perp_bot / spot_bot are atjte.engines.ccxt.arb_bot; their project templates make a Kraken Futures / Kraken spot project that never states its exchange, which the engine fills in). |
atjte.engines.ccxt |
THE engine (the only one since 2026-09-13): the crypto leg on ANY supported exchange — Kraken Futures, Kraken spot, Coinbase, Binance spot / USDⓈ-M, Hyperliquid, Lighter — SPOT or PERPETUAL, vs an MT5 CFD. venue.py resolves every spot/perp difference (position, sizing, reduce-only, funding, liquidation, contracts ↔ base units, spot margin leverage, the excluded base position) over the GATEWAY connector, venue_feed.py is the CCXT Pro feed with venue-aware liveness and socket order operations that the CCXT gateway runs per (account, symbol), arb_bot.py the engine with all sizes in base units (*_UNITS); the re-price is an amend where the gateway can, cancel + place where it cannot. Its identity names the exchange: EXCHANGE_ID, SYMBOL_VENUE, MARKET_KIND (an assertion, not a switch). base_settings.py = the defaults of every engine literal. |
atjte.engines.common |
the pure, unit-tested modules the engine is built on: order math (grid_model, incl. fixed_levels and fixed_entry_exit_levels), risk limits (risk), trading blackouts (blackout), and aliases — the retired Kraken engines' setting names (SYMBOL_KRAKEN, GRID_UNIT_OZ, MIN_KF_AVAILABLE_MARGIN_USD …) read as the canonical ones, so every existing project file stays valid. |
atjte.strategy_types |
the strategies that plug into the engine — grid_bot, bollinger_bot, fixed_bot, fixed_entry_exit (one entry and one exit level per direction, one direction at a time) under ccxt/; the perp/ and spot/ folders alias them (with the Kraken-flavoured settings templates a perp / spot project is generated from). |
atjte.backfill |
python -m atjte backfill <strategy_dir> [--since YYYY-MM-DD] [--dry-run] [--mt5-offset-h H]: rebuild a strategy's report/ history from the venues — the exchange's own trades (paged the way each venue pages, paced, retried on a rate limit) and the MT5 deal history — merged by trade id into trades.jsonl; the seed is rewritten flat at the earliest fill only after a complete fetch. Reads through the strategy's gateways on a READ-ONLY lease, so it runs beside the live bot. |
atjte.runtime / atjte.cli |
how a strategy project on disk is bound and run: python -m atjte bot <strategy_dir>. |
atjte.workspace / atjte.credentials |
where projects, state, gateways and the loopback tokens live, and the key NAMES a gateway's gateway.env uses (key_names: Kraken's historical spellings, <id>_key / <id>_secret otherwise, _<account> appended for a named account). |
atjte.templates / atjte.projects |
building a project from the shipped templates; migrating an older layout. |
atjte.settings_io |
the AST-surgical editor for settings files (values only, comments kept). |
atjte.reporting / atjte.accounting |
reporting (since 2026-09-12): every engine owns a Reporter that keeps <strategy>/report/ current — snapshot.json (the venue account: margin or balances, position, resting orders, top of book, funding; the MT5 account, tick and every open ticket on the hedge symbol; rewritten every REPORT_SNAPSHOT_S = 5 s, atomically), trades.jsonl (append-only: every venue fill the bot booked and every MT5 deal on the hedge symbol, close-by legs included, de-duplicated by venue id across restarts), bars.jsonl (1-minute closes of both legs, 14 days) and seed.json (the basis when recording began). Report reads a folder back (snapshot + age, trades, bars, seed) and computes the position and the realized PnL by day locally with atjte.accounting (avg-cost, MT5 close-by attribution). A dashboard reads these files and needs NO venue key: python -m atjte report <strategy_dir> [--days N] [--json]. |
Supported exchanges
Five, by their CCXT ids (atjte.venues is the one list; the connectors refuse
any other id and the control panel offers only these):
| exchange | CCXT ids |
|---|---|
| Kraken | kraken (spot), krakenfutures (perpetuals) |
| Coinbase | coinbase (Advanced Trade) |
| Binance | binance (spot), binanceusdm (USDⓈ-M perpetuals) |
| Hyperliquid | hyperliquid |
| Lighter | lighter |
Every exchange trades through its gateway (the table above): the venue's own
(Hyperliquid, Lighter) or the exchange's CCXT gateway, and Kraken spot / Kraken
Futures may take the Kraken FIX gateway instead. The keys are the gateway's:
<ccxt id>_key / <ccxt id>_secret (+ <ccxt id>_password where the exchange
needs one) in a CCXT gateway's gateway.env — Kraken's historical
kraken_apikey / kraken_secret and kraken_fut_key / kraken_fut_secret.
Lighter's key is its API key, not the L1 wallet key: an existing API key
(80 hex chars) signs through Lighter's own signing library
(lighter_library_path); the Lighter gateway refuses an L1 key rather than let
CCXT register a new API key with it. How a CCXT gateway sends orders is its
order_transport: auto (the private websocket where CCXT Pro places there,
else REST), ws or rest — one path per gateway, never a fallback.
A workspace and its projects
Everything runs inside a workspace: a folder marked by atjte_workspace.json
holding strategies/ (the projects), gateways/ (the gateway instances, with
their keys), env/.env (the loopback tokens the bots present), data/ and
archive/. It is found through ATJTE_HOME, or by walking up from
the strategy folder / the current directory to the marker.
<workspace>/strategies/<project>/
project_settings.py EXCHANGE_ID, SYMBOL_VENUE, SYMBOL_MT5, MT5_MAGIC, the gateway connectors, overrides
strategies/<type>/<type>.py a ~10-line shim: run_strategy(this folder)
strategies/<type>/strategy_settings_template.py
strategies/<type>/strategy_settings.py the live file — LIVE_TRADING + tunables (created on first start)
strategies/<type>/bot_state.json position_state.json spread_1s.json fill_marks.csv stop.signal logs/
Settings resolve in three layers, the later winning: the engine defaults,
project_settings.py (identity — the symbols and the hedge magic, which have
no engine default — plus project-wide overrides), the strategy file.
Make a project by hand:
from pathlib import Path
import shutil
from atjte import templates
proj = Path("~/atjte/strategies/my_xaut").expanduser()
proj.mkdir(parents=True)
shutil.copyfile(templates.project_settings_template("perp"), proj / "project_settings.py") # then edit the identity
templates.copy_strategy_type("perp", "grid_bot", proj / "strategies" / "grid_bot")
Run it (dry run until LIVE_TRADING = True in its strategy_settings.py):
python -m atjte bot <workspace>/strategies/my_xaut/strategies/grid_bot
python -m atjte bot <...>/grid_bot --check # bind and print what resolved, no connection
python -m atjte migrate <project> # convert a project of the older, copied-engine layout
python -m atjte workspace # how the workspace resolves
One strategy per process. A start needs its gateways running — the venue's and
the MT5 gateway (a bot started first waits for them) — and the loopback tokens
in env/.env (ccxt_gateway_token, hl_gateway_token, lt_gateway_token,
kraken_fix_gateway_token, mt5_gateway_token; the control panel writes them
when it sets a gateway up). No venue key and no MT5 login is ever read by a bot.
Setting names
One spelling since 2026-09-13: the crypto leg is SYMBOL_VENUE on EXCHANGE_ID, sizes are *_UNITS (the base asset's unit — UNIT_LABEL says how to print it), the crypto venue's gates are VENUE_*. A project written for the retired Kraken engines (SYMBOL_KRAKEN, GRID_UNIT_OZ, MIN_KF_AVAILABLE_MARGIN_USD …) still runs — the engine reads the old names through atjte.engines.common.aliases — and python -m atjte migrate <project> renames them in place (--dry-run lists the changes first).
Tests
python tests/run_all.py # core, the engine bound to a ccxt / perp / spot project, the gateways — one interpreter each
python tests/ccxt/test_arb_bot.py # one file (stdlib unittest, no pytest needed)
License
MIT — see LICENSE.
Release files for atjte 0.1.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 | |
|---|---|---|---|
| atjte-0.1.0.tar.gz | 458.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| atjte-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 968.7 kB
Release files / atjte-0.1.0.tar.gz
| Download URL | atjte-0.1.0.tar.gz |
|---|---|
| Size | 458.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e1b6d7f5a3dbe5370a69adee2cec783199771dd6fd2f6a7b774c4d37af24bc9
|
|
BLAKE2b-256 checksum How to use checksums |
92cd5e0ab49a1c7004eb7fe69ac01ecc4a2de701c41977bc4e3e2a1a67c95121
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / atjte-0.1.0-py3-none-any.whl
| Download URL | atjte-0.1.0-py3-none-any.whl |
|---|---|
| Size | 510.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
713d8c7f8d1c628b1f67f2f8266c22af0b09e7ce985bc04baf41b5066f208e16
|
|
BLAKE2b-256 checksum How to use checksums |
c1afcac024fa80d494d32ccd469822353eaca2d961a0b59075acfcdf0211e7cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|