Skip to main content

Official Python client for the QJ Trader AI Trading APIs — Canadian market data and order entry.

Project description

qjtrader

Official Python client for the QJ Trader AI Trading APIs — stream real-time Canadian market data and send orders to Canadian venues (Montréal Exchange derivatives, and equities across every lit exchange and dark pool) over one authenticated connection.

pip install qjtrader
  • Free sandbox, no approval. Create an account at gateway.qjtrader.ai, click Create sandbox credential, and you get a client_id + client_secret that stream simulated data and return simulated fills — in the exact production wire format, 24/7.
  • Sandbox → production with one credential swap. Your code never changes; the credential decides sandbox vs. real, server-side.
  • Stdlib only. No dependencies — easy to install, easy to audit.

Quickstart

Get a sandbox key from the console, then:

export QJ_CLIENT_ID="your-client-id"
export QJ_CLIENT_SECRET="your-client-secret"

Send an order

import qjtrader

client = qjtrader.Client()  # reads QJ_CLIENT_ID / QJ_CLIENT_SECRET from the environment

with client.orders() as oe:
    fill = oe.order_and_wait(
        sym="MX:CRAU26", side="buy", qty=1, price=97.00, account="SIM", tif="ioc",
    )
    print(fill)   # {'type': 'exec', 'status': 'filled', 'last_px': 97.0, 'cum_qty': 1, ...}

Lower-level, if you want every message:

with client.orders() as oe:
    cid = oe.order(sym="MX:CRAU26", side="buy", qty=1, price=97.00, account="SIM")
    for msg in oe.updates(timeout=10):
        print(msg)          # accepted -> new -> (partial)* -> filled | canceled | replaced
    oe.cancel(cid)
    print(oe.status())      # open orders + session state

Stream market data

import qjtrader

client = qjtrader.Client()

with client.market_data() as md:
    md.subscribe(["CA:RY", "CA:RY.PT", "MX:CRAU26"], depth=5)
    for msg in md.messages(timeout=30):
        if msg["type"] == "quote":
            print(msg["symbol"], msg["data"]["bid"], msg["data"]["ask"])
  • CA:RY is the consolidated Canadian equity book (each level tagged with its venue); CA:RY.PT is PURE (CSE) only. Futures like MX:CRAU26 are venue-native. See the full symbology reference.

Command line

The package installs a qjtrader command:

qjtrader subscribe CA:RY MX:CRAU26 --watch 30
qjtrader order --sym MX:CRAU26 --side buy --qty 1 --price 97.00 --account SIM --tif ioc
qjtrader status
qjtrader cancel --orig qj-abc123

# strategies: the same file runs in backtest and live
qjtrader backtest examples/strategy_meanreversion.py --symbol MX:CRAU26 --bars 200
qjtrader run       examples/strategy_meanreversion.py --symbols MX:CRAU26 --tag mr1

Strategies — one contract, every venue

Subclass Strategy and the same file runs in the backtest engine, a paper run, or live (plan §10). Backtests are offline and deterministic (no network, no secrets); qjtrader run hosts it against a live/paper credential, tags every order with the strategy name (so the journal groups by strategy), and cancels everything on Ctrl-C.

from qjtrader import Strategy, run_backtest, synthetic_bars

class Buy2Percent(Strategy):
    def on_bar(self, ctx, bar):
        if ctx.position(bar["symbol"]) == 0 and bar["close"] < ctx.param("floor", 0):
            ctx.buy(bar["symbol"], 1, bar["close"], tif="ioc")
    def on_fill(self, ctx, fill):
        ctx.log("filled", fill.get("cid"), "@", fill.get("last_px") or fill.get("price"))

report = run_backtest(Buy2Percent(), synthetic_bars("MX:CRAU26", 200), params={"floor": 95})
print(report["total_pnl"], report["positions"])

The bar-level backtester is for logic; L2 event-replay with queue-model fills (microstructure truth) comes from the paper environment.

Configuration

Client() reads these (constructor args override environment):

Setting Env var Default
Client ID QJ_CLIENT_ID — (required)
Client secret QJ_CLIENT_SECRET — (required)
Token endpoint QJ_TOKEN_URL QJ Cognito token URL
Market-data host QJ_DATA_HOST data-feed.qjtrader.ai:7000
Order-entry host QJ_ORDERS_HOST orders.qjtrader.ai:7001
Pinned CA/cert QJ_CA_FILE none (standard public-CA validation)

Tokens are minted for you (OAuth2 client-credentials) and refreshed automatically before they expire — you never handle them directly. Need a raw token (e.g. for the WebSocket interface)? client.token(qjtrader.MARKET_DATA_SCOPE).

Pilot note: while order entry is in private pilot it may be reached by IP with a pinned certificate provided at onboarding — pass ca_file="pilot-server.pem" (or QJ_CA_FILE). Market data uses a standard public certificate.

How it works

Both APIs speak NDJSON over TLS — one JSON object per line, UTF-8, newline-terminated, authenticated with an OAuth2 JWT sent on the first line. The order lifecycle is a deterministic, journaled state machine (accepted → new → (partial)* → filled | canceled | replaced), commands are idempotent per client order id (cid), and the server enforces pre-trade risk checks + cancel-on-disconnect. Full protocol: Order Entry and Market Data.

Use it from an LLM (MCP)

Prefer to drive QJ from Claude or another AI assistant? The companion qjtrader-mcp server exposes these APIs as Model Context Protocol tools — subscribe to quotes and place simulated orders in plain language, no code. Order tools refuse a live credential by default (sandbox-only unless you opt in). Add it to Claude Code with:

claude mcp add qjtrader -e QJ_CLIENT_ID=... -e QJ_CLIENT_SECRET=... -e QJ_ENV=sandbox -- uvx qjtrader-mcp

The console's "Connect your AI" panel generates this for you, pre-filled.

Links

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qjtrader-0.4.0.tar.gz (57.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qjtrader-0.4.0-py3-none-any.whl (47.7 kB view details)

Uploaded Python 3

File details

Details for the file qjtrader-0.4.0.tar.gz.

File metadata

  • Download URL: qjtrader-0.4.0.tar.gz
  • Upload date:
  • Size: 57.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for qjtrader-0.4.0.tar.gz
Algorithm Hash digest
SHA256 65e2f92c517db66353b6748d092534db7b2c079d32525f8ce141919b11eec44c
MD5 fb23e6aafe325b4524a1e201588b572e
BLAKE2b-256 a4e2b14212650b779a34e8596c5f8dc7a358fe6a1540349274fc574bda4fa5a4

See more details on using hashes here.

File details

Details for the file qjtrader-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: qjtrader-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 47.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for qjtrader-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ea79480e5045cb12f647261d2057ea925a058926f86c68fb13d573b8cd20317
MD5 09d5c2a3a36f50ed808d1cda663d2007
BLAKE2b-256 8980921634b83c5918e5d977aaf10892ab9efca90cd9cf0e3677dc5f1903878f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page