| name | qmt |
| description | QMT Xuntou Quantitative Trading Terminal — Built-in Python strategy development, backtesting engine, and live trading, supporting all instruments in the Chinese securities market. |
| homepage | http://dict.thinktrader.net/freshman/rookie.html |
QMT (Xuntou Quantitative Trading Terminal)
QMT (Quant Market Trading) is a professional quantitative trading platform developed by Xuntou Technology. It provides a full desktop client with built-in Python strategy development, backtesting engine, and live trading capabilities, supporting all instruments in the Chinese securities market.
⚠️ Requires QMT access from a broker. QMT runs only on Windows. Available through brokers such as Guojin, Huaxin, Zhongtai, East Money, etc.
Two Operating Modes
| Mode | Description |
|---|
| QMT (Full Version) | Full desktop GUI with built-in Python editor, charts, and backtesting engine |
| miniQMT | Minimal mode — uses the xtquant SDK via external Python (see the miniqmt skill) |
Built-in Python Strategy Framework
QMT provides an event-driven strategy framework with a built-in Python runtime (similar to JoinQuant/RiceQuant).
Strategy Lifecycle
def init(ContextInfo):
"""Initialization function — called once when the strategy starts, used to set up the stock pool and parameters"""
ContextInfo.set_universe(['000001.SZ', '600519.SH'])
def handlebar(ContextInfo):
"""Bar handler function — triggered once per bar (tick/1m/5m/1d, etc.), write trading logic here"""
close = ContextInfo.get_market_data(['close'], stock_code='000001.SZ', period='1d', count=20)
def stop(ContextInfo):
"""Stop function — called when the strategy stops"""
pass
Fetching Market Data (Built-in)
def handlebar(ContextInfo):
data = ContextInfo.get_market_data(
['open', 'high', 'low', 'close', 'volume'],
stock_code='000001.SZ',
period='1d',
count=20
)
history = ContextInfo.get_history_data(
20, '1d', 'close', stock_code='000001.SZ'
)
stocks = ContextInfo.get_stock_list_in_sector('沪深A股')
fin = ContextInfo.get_financial_data('000001.SZ')
Placing Orders (Built-in)
def handlebar(ContextInfo):
order_shares('000001.SZ', 100, 'fix', 11.50, ContextInfo)
order_shares('000001.SZ', -100, 'fix', 12.00, ContextInfo)
order_target_value('000001.SZ', 100000, 'fix', 11.50, ContextInfo)
cancel('order_id', ContextInfo)
Querying Positions and Account
def handlebar(ContextInfo):
positions = get_trade_detail_data('your_account', 'stock', 'position')
for pos in positions:
print(pos.m_strInstrumentID, pos.m_nVolume, pos.m_dMarketValue)
orders = get_trade_detail_data('your_account', 'stock', 'order')
account = get_trade_detail_data('your_account', 'stock', 'account')
Backtesting
QMT has a built-in backtesting engine:
- Write a strategy in the built-in Python editor
- Set backtesting parameters (date range, initial capital, commission, slippage)
- Click "Run Backtest"
- View results: equity curve, max drawdown, Sharpe ratio, trade log
Backtesting Parameter Setup
def init(ContextInfo):
ContextInfo.capital = 1000000
ContextInfo.set_commission(0.0003)
ContextInfo.set_slippage(0.01)
ContextInfo.set_benchmark('000300.SH')
Full Example: Dual Moving Average Strategy
import numpy as np
def init(ContextInfo):
ContextInfo.stock = '000001.SZ'
ContextInfo.set_universe([ContextInfo.stock])
ContextInfo.fast = 5
ContextInfo.slow = 20
def handlebar(ContextInfo):
stock = ContextInfo.stock
closes = ContextInfo.get_history_data(ContextInfo.slow + 1, '1d', 'close', stock_code=stock)
if len(closes) < ContextInfo.slow:
return
ma_fast = np.mean(closes[-ContextInfo.fast:])
ma_slow = np.mean(closes[-ContextInfo.slow:])
prev_fast = np.mean(closes[-ContextInfo.fast-1:-1])
prev_slow = np.mean(closes[-ContextInfo.slow-1:-1])
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
holding = any(p.m_strInstrumentID == stock and p.m_nVolume > 0 for p in positions)
if prev_fast <= prev_slow and ma_fast > ma_slow and not holding:
order_shares(stock, 1000, 'fix', closes[-1], ContextInfo)
prev_fast >= prev_slow ma_fast < ma_slow holding:
order_shares(stock, -, , closes[-], ContextInfo)
Data Coverage
| Category | Content |
|---|
| Stocks | A-shares (Shanghai, Shenzhen, Beijing), Hong Kong Stock Connect |
| Indices | All major indices |
| Futures | CFFEX, SHFE, DCE, CZCE, INE, GFEX |
| Options | ETF options, stock options, commodity options |
| ETFs | All exchange-traded funds |
| Bonds | Convertible bonds, government bonds |
| Periods | Tick, 1m, 5m, 15m, 30m, 1h, 1d, 1w, 1mon |
| Level 2 | Order-by-order, trade-by-trade (depends on broker permissions) |
| Financials | Balance sheet, income statement, cash flow statement, key metrics |
QMT vs miniQMT vs Ptrade Comparison
| Feature | QMT | miniQMT | Ptrade |
|---|
| Vendor | Xuntou Technology | Xuntou Technology | Hundsun Electronics |
| Python | Built-in (version restricted) | External (any version) | Built-in (version restricted) |
| Interface | Full GUI | Minimal | Full (web-based) |
| Backtesting | Built-in | Must implement yourself | Built-in |
| Deployment | Local | Local | Broker server (cloud) |
| Internet Access | Yes | Yes | No (intranet only) |
Usage Tips
- QMT runs only on Windows.
- The built-in Python version is fixed by QMT — you cannot install arbitrary pip packages.
- If you need an unrestricted Python environment, use miniQMT mode with the
xtquant SDK.
- Strategy files are stored in the QMT installation directory.
- Documentation: http://dict.thinktrader.net/freshman/rookie.html
- A VBA interface is also supported for Excel integration.
Advanced Examples
Multi-Stock Rotation Strategy
import numpy as np
def init(ContextInfo):
ContextInfo.stock_pool = ['601398.SH', '601939.SH', '601288.SH', '600036.SH', '601166.SH']
ContextInfo.set_universe(ContextInfo.stock_pool)
ContextInfo.hold_num = 2
def handlebar(ContextInfo):
momentum = {}
for stock in ContextInfo.stock_pool:
closes = ContextInfo.get_history_data(21, '1d', 'close', stock_code=stock)
if len(closes) >= 21:
ret = (closes[-1] - closes[0]) / closes[0]
momentum[stock] = ret
sorted_stocks = sorted(momentum.items(), key=lambda x: x[1], reverse=True)
target_stocks = [s[0] for s in sorted_stocks[:ContextInfo.hold_num]]
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
holding = {p.m_strInstrumentID: p.m_nVolume for p in positions if p.m_nVolume > 0}
stock, vol holding.items():
stock target_stocks:
closes = ContextInfo.get_history_data(, , , stock_code=stock)
(closes) > :
order_shares(stock, -vol, , closes[-], ContextInfo)
account = get_trade_detail_data(ContextInfo.accID, , )
account:
cash = account[].m_dAvailable
per_stock_cash = cash / ContextInfo.hold_num
stock target_stocks:
stock holding:
closes = ContextInfo.get_history_data(, , , stock_code=stock)
(closes) > closes[-] > :
vol = (per_stock_cash / closes[-] / ) *
vol >= :
order_shares(stock, vol, , closes[-], ContextInfo)
RSI Strategy
import numpy as np
def init(ContextInfo):
ContextInfo.stock = '000001.SZ'
ContextInfo.set_universe([ContextInfo.stock])
ContextInfo.rsi_period = 14
ContextInfo.oversold = 30
ContextInfo.overbought = 70
def handlebar(ContextInfo):
stock = ContextInfo.stock
closes = ContextInfo.get_history_data(ContextInfo.rsi_period + 2, '1d', 'close', stock_code=stock)
if len(closes) < ContextInfo.rsi_period + 1:
return
deltas = np.diff(closes)
gains = np.where(deltas > 0, deltas, 0)
losses = np.where(deltas < 0, -deltas, 0)
avg_gain = np.mean(gains[-ContextInfo.rsi_period:])
avg_loss = np.mean(losses[-ContextInfo.rsi_period:])
if avg_loss == 0:
rsi = 100
else:
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
holding = any(p.m_strInstrumentID == stock and p.m_nVolume > 0 for p in positions)
rsi < ContextInfo.oversold holding:
order_shares(stock, , , closes[-], ContextInfo)
rsi > ContextInfo.overbought holding:
order_shares(stock, -, , closes[-], ContextInfo)
Bollinger Bands Strategy
import numpy as np
def init(ContextInfo):
ContextInfo.stock = '600519.SH'
ContextInfo.set_universe([ContextInfo.stock])
ContextInfo.boll_period = 20
ContextInfo.boll_std = 2
def handlebar(ContextInfo):
stock = ContextInfo.stock
closes = ContextInfo.get_history_data(ContextInfo.boll_period + 1, '1d', 'close', stock_code=stock)
if len(closes) < ContextInfo.boll_period:
return
recent = closes[-ContextInfo.boll_period:]
mid = np.mean(recent)
std = np.std(recent)
upper = mid + ContextInfo.boll_std * std
lower = mid - ContextInfo.boll_std * std
price = closes[-1]
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
holding = any(p.m_strInstrumentID == stock and p.m_nVolume > 0 for p in positions)
if price <= lower and not holding:
order_shares(stock, 1000, 'fix', price, ContextInfo)
price >= upper holding:
order_shares(stock, -, , price, ContextInfo)
社区与支持
由 大佬量化 (Boss Quant) 维护 — 量化交易教学与策略研发团队。
微信客服: bossquant1 · Bilibili · 搜索 大佬量化 on 微信公众号 / Bilibili / 抖音