中文 | English
A stable JSON interface in front of QMT / XtQuant, so any language and any agent can call it safely.
Current state: 60+ CLI subcommands; checked function-by-function against the official
xtdata doc, covering 43 functions (see
docs/xtdata-alignment.md); checked against the official
xttrader doc, covering 25 query/trading
method groups (see docs/xttrader-alignment.md); 267 automated tests,
all green, with xtquant fully faked so CI never needs a real QMT install; a weekly doc-drift CI
job re-checks both matrices against the live doc pages for drift.
Anyone who has automated QMT knows the friction: xtquant only lives inside the broker client's
install directory, so import-ing it directly ties your scripts, notebooks, and agents to that one
Python environment. Want to swap in a market-data engine written in Rust or Go? Want to wire up an
LLM agent to watch positions, flag anomalies, and write trade logs? Suddenly serializing DataFrames,
handling NaN, and guessing which field encoding to trust are your problem too.
qmtcli exists to do that work once: it starts a small local process, takes JSON in, hands JSON
back, and talks to the QMT client you already have logged in. Everything the official QMT/XtQuant
API exposes — diagnostics, market data, account queries, and guarded stock order placement (see the
official QMT beginner guide) — is reachable
through this one stable stdin/stdout JSON contract.
qmtcli does not install or launch the QMT trading client itself, store credentials, bypass
broker risk checks, or run a network service — but it does auto-discover and wire up the local
XtQuant SDK environment (preferring an already-installed venv/pip xtquant over the QMT-bundled
copy, see Install). QMT must already be installed and logged in locally.
- Anyone who wants an LLM agent (Claude, GPT, a local model) to check quotes, read positions, or
place guarded orders directly —
qmtcli mcpwires it into MCP in one command, with tools generated from the capability list instead of a hand-maintained second registry. - Teams building a quant system in Rust, Go, or Node.js who don't want to stand up a separate Python sidecar just to talk to QMT.
- Anyone who wants a stable JSON contract instead of re-guessing
xtquantparameter and field changes every time the broker ships a QMT update. - CI pipelines that need to run tests on a machine without QMT installed at all — the test suite
fakes
xtquant, so no broker install is required.
Discover the command surface:
qmtcli capabilities
qmtcli schema
qmtcli examplesRun one JSON request:
Get-Content examples\status.json | qmtcli rpcRun a JSONL loop for an agent or script:
qmtcli serverResponse shape:
{"ok":true,"data":{}}Error shape:
{"ok":false,"error":"message"}If a request includes id, the response echoes it.
QMT bundles xtquant inside the broker client install. That is fine for direct Python scripts on a
trading machine, but awkward for agents and process-based automation — you inherit whatever
numpy/pandas version QMT ships, and a silent broker-side upgrade can quietly change how a
DataFrame serializes or drop a field you were relying on. qmtcli keeps that instability local, in
a subprocess you can restart at will, and gives callers a simple, testable, version-stable JSON
contract instead:
capabilities,schema, andexamplesfor discovery;rpcfor one request over stdin/stdout;serverfor newline-delimited JSON requests;- explicit labels for read-only calls, escape hatches, order placement, and cancellation;
- tests that fake
xtquant, so CI does not need a broker install.
Any runtime that can start a local process and exchange JSON can use it — Python, Rust, Go, Node.js, shell scripts, or an LLM agent, no language-specific SDK or binding required.
- QMT SDK discovery from common Windows install paths, preferring an already-installed venv/pip
xtquantover the QMT-bundled copy (see Install). statusanddoctordiagnostics, including SDK source (environment/qmt_bundled/missing),xtquantversion, and xtdc availability.- Market data commands: calendar, trading dates, sectors, ticks, bars, local cached bars
(
local-data), full-push K-line (full-kline), L2 data, instrument/ETF/CB/IPO/index-weight metadata, and financials. sectorcommand family for creating, populating, and deleting local custom sectors (create-folder,create,add,remove-stocks,remove,reset).watch: CLI-only live quote streaming (JSONL to stdout) viasubscribe_quote/subscribe_whole_quote, blocking until Ctrl+C — see CLI Streaming.mcp: stdio MCP server exposing qmtcli commands as MCP tools, generated fromAGENT_CAPABILITIES— see MCP Server.fields: static xtdata field-name reference dictionaries (tick, kline, balance, ...) extracted from the doc appendix. Fully offline, no QMT install needed.- pandas-aware JSON output: DataFrames/Series returned by xtdata are serialized as records (a time
index is kept as a plain column), and NaN/NaT/
pd.NA/numpy scalars all become plain JSON values instead of invalidNaNtokens or unreadable object dumps. downloadcommand for populating the local QMT cache (history, financials, sectors, index weight, convertible bonds, ETF info, holidays, contracts).- Account queries: asset, positions, orders (with
--cancelable-only), trades. - Trader query commands: position statistics, credit/margin queries, IPO quota and data, account infos/status, and ordinary-account fund/position queries — see Trade Query Commands.
- Fixed-price A-share
buy,sell, andcancel. - Generic
data-callfor publicxtquant.xtdatamethods. - Generic
trade-callfor publicXtQuantTradermethods. - Optional standalone xtdatacenter (xtdc) data mode via
--xtdc-token(experimental) — see Standalone Data Mode. - Agent/script protocol commands:
capabilities,schema,examples,rpc,server. - A scheduled
doc-driftGitHub Action (weekly, plus manual dispatch) re-checks the alignment matrices below against the live doc pages and files an issue if a new doc function is not yet reflected in either matrix; seescripts/check_doc_drift.py.
See docs/xtdata-alignment.md and
docs/xttrader-alignment.md for the full function-to-command
coverage matrices against the official
xtdata and
xttrader docs.
Recommended: install with the sdk extra so xtquant/pandas/numpy come from this environment
instead of QMT's bundled site-packages; the broker QMT client then only needs to provide the
local trading/data service, not the Python SDK itself:
uv sync --extra dev --extra sdk
pip install -e ".[dev,sdk]"Bundled-SDK fallback (no sdk extra) still works — qmtcli falls back to the QMT install's own
xtquant/numpy/pandas when nothing is already importable — but the bundled copy can be older
than the current docs (for example, some bundled builds lack get_period_list) and its bundled
numpy should never be allowed to shadow a venv's own numpy. qmtcli doctor reports which
source won as sdk_source. See Runtime caveats for
details.
For local development:
uv sync --extra dev
uv run qmtcli statusEditable pip install:
pip install -e .[dev]
qmtcli statusDiscovery:
qmtcli capabilities
qmtcli schema
qmtcli examplesOne-shot RPC:
Get-Content examples\status.json | qmtcli rpc
Get-Content examples\data_call.json | qmtcli rpcJSONL loop:
.\examples\jsonl_server.ps1Generic integration notes are in examples/agent_tool.md. A short demo
recording script is in docs/demo_storyboard.md.
All named data commands (calendar, bars, sector-stocks, download, ...) are available over
rpc/server too, not just the CLI; send their CLI parameter names as JSON fields, for example
{"command":"bars","symbols":["600519.SH"],"period":"1d"}. The command name accepts either dashes
or underscores (sector-stocks or sector_stocks).
In server mode only, subscribe, subscribe_whole, and unsubscribe wrap the callback-based
xtdata.subscribe_quote, subscribe_whole_quote, and unsubscribe_quote:
{"command":"subscribe","symbol":"600519.SH","period":"1d"}
{"command":"subscribe_whole","symbols":["600519.SH","000001.SZ"]}
{"command":"unsubscribe","seq":1}Subscribing responds with {"ok":true,"data":{"seq":1}}, and every later quote push from xtquant
is printed as its own JSONL line carrying an event field instead of ok, interleaved with normal
responses on the same stdout stream:
{"ok":true,"data":{"seq":1}}
{"event":"quote","seq":1,"symbol":"600519.SH","data":{"600519.SH":{"lastPrice":1500.0}}}The one-shot rpc command and the CLI reject subscribe commands with {"ok":false,"error": "subscribe commands require server mode"}, since a subscription only makes sense while server
keeps the process alive.
watch is a CLI-only alternative to server-mode subscribe/subscribe_whole: it subscribes
directly, then blocks in xtdata.run(), printing one JSONL line per quote push until interrupted
(Ctrl+C exits cleanly with code 0). It is not available over rpc/server.
qmtcli watch 600519.SH
qmtcli watch 600519.SH 000001.SZ --period 1m
qmtcli watch 600519.SH 000001.SZ --whole{"event":"quote","symbol":"600519.SH","data":{"600519.SH":{"lastPrice":1500.0}}}qmtcli mcp runs a stdio MCP (Model Context Protocol) server exposing qmtcli commands as MCP
tools. Capabilities-driven, single source of truth: tools are generated from
AGENT_CAPABILITIES, and every tool call is dispatched through the same rpc machinery as
rpc/server — there is no second command registry.
Install the mcp extra:
uv sync --extra mcpRun it directly (talks JSON-RPC over stdio; nothing else prints to stdout):
qmtcli mcpRegister it with Claude Code:
claude mcp add qmt -- uv run --directory D:/projects/qmtcli --extra mcp qmtcli mcpTool names are qmt_<name> with dashes replaced by underscores, for example qmt_full_tick,
qmt_sector_stocks, qmt_account_infos. There is no persistent --account/--path like the
CLI has — every trade-query/account tool takes optional path/account/account_type
arguments per call instead.
Excluded by design: buy, sell, cancel (order placement/cancellation) and trade_call (an
unguarded escape hatch onto the full XtQuantTrader surface) — use the CLI directly for guarded
trading. watch and the subscribe/subscribe_whole/unsubscribe trio are also excluded (CLI-
only / server-only streaming, not a fit for one-shot tool calls). Everything else — status,
doctor, data_call, fields, download, every named data command, and every trade query
(asset, positions, orders, trades, ...) — is available.
Without the mcp extra installed, qmtcli mcp prints
{"ok":false,"error":"mcp extra is not installed; pip install 'qmtcli[mcp]'"} and exits 1.
Pass either a QMT install root or its userdata_mini directory:
qmtcli --path D:\DFZQxtqmt_client_real_win64 doctor
qmtcli --path D:\DFZQxtqmt_client_real_win64\userdata_mini --account ACCOUNT_ID assetWhen --path is omitted, these roots are checked:
D:\DFZQxtqmt_client_real_win64D:\DFZQxtqmt_client_test_win64C:\DFZQxtqmt_client_real_win64C:\DFZQxtqmt_client_test_win64
Expected SDK location:
<QMT root>\bin.x64\Lib\site-packages\xtquant
Diagnostics:
qmtcli status
qmtcli doctor
python -m qmtcli statusMarket data:
qmtcli calendar SH
qmtcli trading-dates SH --count 5
qmtcli sector-list
qmtcli sector-stocks 沪深A股
qmtcli full-tick 600519.SH 000001.SZ
qmtcli bars 600519.SH --period 1d --count 100
qmtcli local-data 600519.SH --period 1d --count 100
qmtcli full-kline 600519.SH --period 1m
qmtcli instrument-detail 600519.SH
qmtcli instrument-type 600519.SH
qmtcli divid-factors 600519.SH
qmtcli holidays
qmtcli period-list
qmtcli ipo-info
qmtcli cb-info 123001.SZ
qmtcli etf-info
qmtcli index-weight 000300.SH
qmtcli financials 600519.SH --tables BalanceStatic field-name reference dictionaries (fully offline, no QMT install needed):
qmtcli fields
qmtcli fields tick
qmtcli fields balanceL2 commands require Level-2 market data permission from the broker and are not covered by the public xtdata doc page:
qmtcli l2-quote 600519.SH
qmtcli l2-order 600519.SH
qmtcli l2-transaction 600519.SHDownload data into the local QMT cache; these calls return once the SDK download finishes and do not print market data themselves — use the read commands above for that:
qmtcli download history 600519.SH --period 1d
qmtcli download financials 600519.SH --tables Balance
qmtcli download sectors
qmtcli download index-weight
qmtcli download cb
qmtcli download etf
qmtcli download holidays
qmtcli download history-contractsManage local custom sectors (mutates local sector definitions only; danger: mutates_local_data):
qmtcli sector create-folder MyGroup --parent 我的自定义板块
qmtcli sector create MySector --parent 我的自定义板块
qmtcli sector add MySector 600519.SH 000001.SZ
qmtcli sector remove-stocks MySector 600519.SH
qmtcli sector reset MySector 600519.SH
qmtcli sector remove MySectorAccount and order commands require --account:
qmtcli --account ACCOUNT_ID asset
qmtcli --account ACCOUNT_ID positions
qmtcli --account ACCOUNT_ID orders
qmtcli --account ACCOUNT_ID orders --cancelable-only
qmtcli --account ACCOUNT_ID trades
qmtcli --account ACCOUNT_ID buy 600519.SH 100 1500.00
qmtcli --account ACCOUNT_ID sell 600519.SH 100 1500.00
qmtcli --account ACCOUNT_ID cancel ORDER_IDThese wrap named XtQuantTrader query methods; see
docs/xttrader-alignment.md for the full mapping. Most require
--account:
qmtcli --account ACCOUNT_ID position-statistics
qmtcli --account ACCOUNT_ID credit-detail
qmtcli --account ACCOUNT_ID stk-compacts
qmtcli --account ACCOUNT_ID credit-subjects
qmtcli --account ACCOUNT_ID credit-slo-code
qmtcli --account ACCOUNT_ID credit-assure
qmtcli --account ACCOUNT_ID ipo-limit
qmtcli --account ACCOUNT_ID com-fund
qmtcli --account ACCOUNT_ID com-positionipo-data, account-infos, and account-status wrap XtQuantTrader methods that take no account
argument at all, so --account is optional for these three — qmtcli still connects a QMT
session, it just skips subscribing an account:
qmtcli ipo-data
qmtcli account-infos
qmtcli account-statusdata-call calls any public method on xtquant.xtdata:
qmtcli data-call get_stock_list_in_sector --args "[\"沪深A股\"]"
qmtcli data-call get_cb_info --args "[\"123001.SZ\"]"trade-call calls any public method on XtQuantTrader after connecting the account. By default,
the StockAccount object is prepended to positional arguments:
qmtcli --account ACCOUNT_ID trade-call query_stock_orders
qmtcli --account ACCOUNT_ID trade-call some_method --args "[1,2]" --kwargs "{\"flag\":true}"
qmtcli --account ACCOUNT_ID trade-call method_without_account --no-accountPrivate method names beginning with _ are blocked.
--xtdc-token (or the QMTCLI_XTDC_TOKEN environment variable) enables standalone xtdatacenter
data mode: before running any command, qmtcli calls xtquant.xtdatacenter.set_token() and
.init(), so xtdata calls can route through the 迅投投研 standalone data service instead of a
local QMT client:
$env:QMTCLI_XTDC_TOKEN = "YOUR_TOKEN"
qmtcli calendar SH
qmtcli --xtdc-token YOUR_TOKEN --xtdc-port 58620 calendar SHThis requires a valid 迅投投研 data token and is experimental — verified only as far as init()
succeeding, not end-to-end against real data. --xtdc-port is accepted (default 58620) but not
yet wired to a specific xtdatacenter call. qmtcli doctor reports whether the
xtquant.xtdatacenter module itself is importable as xtdc_available. See
Runtime caveats for more.
{"command":"status"}
{"command":"data_call","method":"get_stock_list_in_sector","args":["沪深A股"]}
{"command":"buy","account":"ACCOUNT_ID","symbol":"600519.SH","volume":100,"price":1500.0}For JSONL server, one input line produces one output line. Request id is echoed.
- Local only:
serverreads stdin and writes stdout; it does not open a socket. - No broker software download or auto-install.
- No credential storage.
- No order retry loop.
capabilitiesmarks order placement and cancel actions as dangerous, marksdownloadasdownloads_datasince it writes into the local QMT cache, and markssectorasmutates_local_datasince it creates/modifies local custom sector definitions.- A-share order volume must be a positive multiple of 100.
- Order price must be positive.
- Private
xtdata/XtQuantTradermethod names are blocked. - QMT account permissions, risk checks, and final execution remain controlled by QMT and the broker.
qmtcli --help
qmtcli capabilities --help
qmtcli schema --help
qmtcli examples --help
qmtcli data-call --help
qmtcli download --help
qmtcli sector --help
qmtcli fields --help
qmtcli trade-call --help
qmtcli watch --help
qmtcli rpc --help
qmtcli server --help
qmtcli mcp --helpuv run --extra dev pytest -q
uv run --extra dev ruff check .
uv buildRegenerate the static fields catalog from the doc appendix, and check the alignment matrices for
drift against the live doc pages (also runs on a weekly schedule in CI, see
.github/workflows/doc-drift.yml):
python scripts/extract_doc_fields.py
python scripts/check_doc_drift.pyFor coding agents, see AGENTS.md.
PyPI packaging metadata is present so the name/build shape is reserved for future publishing, but this project is not published by this repository workflow.
If qmtcli saved you the trouble of integrating QMT yourself, a star is the most direct way to
help others find it. Hit a rough edge, missing command, or an agent framework it doesn't fit
smoothly — open an issue or send a PR.
