QMT
VerifiedQMT — programming languages tool with Python support.
$ Add to .claude/skills/ About This Skill
Content available in Chinese
# QMT(迅投量化交易终端)
QMT(Quant Market Trading)是迅投科技开发的专业量化交易平台。提供完整的桌面客户端,内置Python策略开发、回测引擎和实盘交易功能,支持中国证券市场全品种。
> ⚠️ 需要通过券商开通QMT权限。QMT仅在Windows上运行。可通过国金、华鑫、中泰、东方财富等券商获取。
两种运行模式
| 模式 | 说明 | |---|---| | QMT(完整版) | 完整桌面GUI,内置Python编辑器、图表和回测引擎 | | miniQMT | 极简模式 — 通过外部Python使用xtquant SDK(参见 `miniqmt` skill) |
内置Python策略框架
QMT提供事件驱动策略框架,内置Python运行时(类似聚宽/米筐)。
策略生命周期
```python def init(ContextInfo): """初始化函数 - 策略启动时调用一次,用于设置股票池和参数""" ContextInfo.set_universe(['000001.SZ', '600519.SH'])
def handlebar(ContextInfo): """K线处理函数 - 每根K线触发一次(tick/1m/5m/1d等),在此编写交易逻辑""" close = ContextInfo.get_market_data(['close'], stock_code='000001.SZ', period='1d', count=20) # 在此编写交易逻辑
def stop(ContextInfo): """停止函数 - 策略停止时调用""" pass ```
获取行情数据(内置)
```python def handlebar(ContextInfo): # 获取最近20根K线的收盘价 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') ```
下单(内置)
```python def handlebar(ContextInfo): # 限价买入100股,价格11.50 order_shares('000001.SZ', 100, 'fix', 11.50, ContextInfo)
# 限价卖出100股,价格12.00 order_shares('000001.SZ', -100, 'fix', 12.00, ContextInfo)
# 按目标金额买入(10万元) order_target_value('000001.SZ', 100000, 'fix', 11.50, ContextInfo)
# 撤单 cancel('order_id', ContextInfo) ```
查询持仓与账户
```python 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') ```
回测
QMT内置回测引擎:
- 在内置Python编辑器中编写策略
- 设置回测参数(日期范围、初始资金、手续费、滑点)
- 点击"运行回测"
- 查看结果:资金曲线、最大回撤、夏普比率、交易记录
回测参数设置
```python def init(ContextInfo): ContextInfo.capital = 1000000 # 初始资金 ContextInfo.set_commission(0.0003) # 手续费率 ContextInfo.set_slippage(0.01) # 滑点 ContextInfo.set_benchmark('000300.SH') # 基准指数 ```
完整示例:双均线策略
```python 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 # 获取最近slow+1根K线的收盘价 closes = ContextInfo.get_history_data(ContextInfo.slow + 1, '1d', 'close', stock_code=stock)
if len(closes) < ContextInfo.slow: return # 数据不足,跳过
# 计算当前和前一根K线的快慢均线值 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)
# 死叉信号:快速均线下穿慢速均线,卖出 elif prev_fast >= prev_slow and ma_fast < ma_slow and holding: order_shares(stock, -1000, 'fix', closes[-1], ContextInfo) ```
数据覆盖范围
| 类别 | 内容 | |---|---| | 股票 | A股(沪、深、北交所)、港股通 | | 指数 | 所有主要指数 | | 期货 | 中金所、上期所、大商所、郑商所、能源中心、广期所 | | 期权 | ETF期权、股票期权、商品期权 | | ETF | 所有交易所交易基金 | | 债券 | 可转债、国债 | | 周期 | Tick、1分钟、5分钟、15分钟、30分钟、1小时、日、周、月 | | Level 2 | 逐笔委托、逐笔成交(取决于券商权限) | | 财务 | 资产负债表、利润表、现金流量表、关键指标 |
QMT vs miniQMT vs Ptrade 对比
| 特性 | QMT | miniQMT | Ptrade | |---|---|---|---| | 厂商 | 迅投科技 | 迅投科技 | 恒生电子 | | Python | 内置(版本受限) | 外部(任意版本) | 内置(版本受限) | | 界面 | 完整GUI | 极简 | 完整(网页端) | | 回测 | 内置 | 需自行实现 | 内置 | | 部署 | 本地 | 本地 | 券商服务器(云端) | | 外网访问 | 支持 | 支持 | 不支持(仅内网) |
使用技巧
- QMT仅在Windows上运行。
- 内置Python版本由QMT固定,无法安装任意pip包。
- 如需不受限的Python环境,使用miniQMT模式配合`xtquant` SDK。
- 策略文件存储在QMT安装目录中。
- 文档:http://dict.thinktrader.net/freshman/rookie.html
- 也支持VBA接口用于Excel集成。
---
进阶示例
多股票轮动策略
```python 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 # 最多持有2只股票
def handlebar(ContextInfo): # 计算每只股票的20日收益率 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] # 20日收益率 momentum[stock] = ret
# 按动量排序,选择前N只股票 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}
# 卖出不在目标列表中的股票 for stock, vol in holding.items(): if stock not in target_stocks: closes = ContextInfo.get_history_data(1, '1d', 'close', stock_code=stock) if len(closes) > 0: order_shares(stock, -vol, 'fix', closes[-1], ContextInfo)
# 买入目标股票 account = get_trade_detail_data(ContextInfo.accID, 'stock', 'account') if account: cash = account[0].m_dAvailable per_stock_cash = cash / ContextInfo.hold_num # 等权分配 for stock in target_stocks: if stock not in holding: closes = ContextInfo.get_history_data(1, '1d', 'close', stock_code=stock) if len(closes) > 0 and closes[-1] > 0: vol = int(per_stock_cash / closes[-1] / 100) * 100 # 向下取整到整手 if vol >= 100: order_shares(stock, vol, 'fix', closes[-1], ContextInfo) ```
RSI策略
```python import numpy as np
def init(ContextInfo): ContextInfo.stock = '000001.SZ' ContextInfo.set_universe([ContextInfo.stock]) ContextInfo.rsi_period = 14 # RSI周期 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
# 计算RSI 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超卖 — 买入 if rsi < ContextInfo.oversold and not holding: order_shares(stock, 1000, 'fix', closes[-1], ContextInfo)
# RSI超买 — 卖出 elif rsi > ContextInfo.overbought and holding: order_shares(stock, -1000, 'fix', closes[-1], ContextInfo) ```
布林带策略
```python 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)
# 价格触及上轨 — 卖出 elif price >= upper and holding: order_shares(stock, -1000, 'fix', price, ContextInfo) ```
定时任务
```python def init(ContextInfo): ContextInfo.stock = '000001.SZ' ContextInfo.set_universe([ContextInfo.stock])
def handlebar(ContextInfo): import datetime now = ContextInfo.get_bar_timetag(ContextInfo.barpos) dt = datetime.datetime.fromtimestamp(now / 1000) # 仅在每変14:50执行调仓逻辑 if dt.hour == 14 and dt.minute == 50: pass # 执行调仓 ```
常见错误处理
| 错误 | 原因 | 解决方法 | |------|------|----------| | 账户未登录 | QMT未连接券商 | 检查QMT登录状态,确认券商账户已连接 | | 委托失败 | 资金不足或超出涨跌停 | 检查可用资金和委托价格 | | 数据为空 | 股票代码错误或停牌 | 校验代码格式(如`000001.SZ`),检查是否停牌 | | Python版本不兼容 | 内置Python版本受限 | 改用miniQMT模式 | | 策略运行缓慢 | 数据量过大 | 减少`get_history_data`的count参数 |
内置函数参考
行情数据函数
| 函数 | 说明 | 返回值 | |------|------|--------| | `ContextInfo.get_market_data(fields, stock_code, period, count)` | 获取K线数据 | dict/DataFrame | | `ContextInfo.get_history_data(count, period, field, stock_code)` | 获取历史数据序列 | list | | `ContextInfo.get_stock_list_in_sector(sector)` | 获取板块成分股 | list | | `ContextInfo.get_financial_data(stock_code)` | 获取财务数据 | dict | | `ContextInfo.get_instrument_detail(stock_code)` | 获取合约详情 | dict | | `ContextInfo.get_full_tick(stock_list)` | 获取全推行情快照 | dict |
交易函数
| 函数 | 说明 | |------|------| | `order_shares(code, volume, style, price, ContextInfo)` | 按股数下单(正买负卖) | | `order_target_value(code, value, style, price, ContextInfo)` | 按目标市值下单 | | `order_lots(code, lots, style, price, ContextInfo)` | 按手数下单 | | `order_percent(code, percent, style, price, ContextInfo)` | 按组合比例下单 | | `cancel(order_id, ContextInfo)` | 撤单 | | `get_trade_detail_data(account, market, data_type)` | 查询交易数据 |
交易数据类型
| data_type | 说明 | 常用字段 | |-----------|------|----------| | `'position'` | 持仓 | `m_strInstrumentID`(代码), `m_nVolume`(数量), `m_dMarketValue`(市值) | | `'order'` | 委托 | `m_strOrderSysID`(委托号), `m_nVolumeTraded`(成交量), `m_dLimitPrice`(委托价) | | `'deal'` | 成交 | `m_strTradeID`(成交号), `m_dPrice`(成交价), `m_nVolume`(成交量) | | `'account'` | 账户 | `m_dAvailable`(可用资金), `m_dBalance`(总资产), `m_dMarketValue`(持仓市值) |
进阶示例:MACD策略
```python import numpy as np
def init(ContextInfo): ContextInfo.stock = '600519.SH' ContextInfo.set_universe([ContextInfo.stock])
def handlebar(ContextInfo): stock = ContextInfo.stock closes = ContextInfo.get_history_data(60, '1d', 'close', stock_code=stock) if len(closes) < 35: return closes = np.array(closes, dtype=float)
def ema(data, period): result = np.zeros_like(data) result[0] = data[0] k = 2 / (period + 1) for i in range(1, len(data)): result[i] = data[i] * k + result[i-1] * (1 - k) return result
ema12 = ema(closes, 12) ema26 = ema(closes, 26) dif = ema12 - ema26 dea = ema(dif, 9)
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position') holding = any(p.m_strInstrumentID == stock and p.m_nVolume > 0 for p in positions)
# 金叉:DIF上穿DEA if dif[-2] <= dea[-2] and dif[-1] > dea[-1] and not holding: order_shares(stock, 1000, 'fix', closes[-1], ContextInfo) # 死叉:DIF下穿DEA elif dif[-2] >= dea[-2] and dif[-1] < dea[-1] and holding: order_shares(stock, -1000, 'fix', closes[-1], ContextInfo) ```
进阶示例:止盈止损策略
```python import numpy as np
def init(ContextInfo): ContextInfo.stock = '000001.SZ' ContextInfo.set_universe([ContextInfo.stock]) ContextInfo.entry_price = 0 ContextInfo.stop_loss = 0.05 # 止损5% ContextInfo.take_profit = 0.10 # 止盈10%
def handlebar(ContextInfo): stock = ContextInfo.stock closes = ContextInfo.get_history_data(21, '1d', 'close', stock_code=stock) if len(closes) < 21: return price = closes[-1] ma20 = np.mean(closes[-20:])
positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position') pos = None for p in positions: if p.m_strInstrumentID == stock and p.m_nVolume > 0: pos = p break
if pos is None: if price > ma20: order_shares(stock, 1000, 'fix', price, ContextInfo) ContextInfo.entry_price = price else: if ContextInfo.entry_price > 0: pnl = (price - ContextInfo.entry_price) / ContextInfo.entry_price if pnl <= -ContextInfo.stop_loss: order_shares(stock, -pos.m_nVolume, 'fix', price, ContextInfo) ContextInfo.entry_price = 0 elif pnl >= ContextInfo.take_profit: order_shares(stock, -pos.m_nVolume, 'fix', price, ContextInfo) ContextInfo.entry_price = 0 ```
---
社区与支持
由 大佬量化 (BossQuant) 维护 — 量化交易教学与策略研发团队。
微信客服: bossquant1 · Bilibili · 搜索 大佬量化 — 微信公众号 / Bilibili / 抖音
Use Cases
- Generate professional written content tailored to specific requirements
- Interact with external APIs for data retrieval and service integration
- Fetch and analyze pricing data from markets and exchanges
- Analyze market data and trading opportunities
- Manage and configure Raspberry Pi devices remotely
Pros & Cons
Pros
- +Well-structured approach ensures consistent and reliable results
- +Integrates smoothly into existing workflows
- +Clear documentation makes it easy to get started and integrate
Cons
- -Focused scope means it may not cover edge cases outside its primary use case
- -May require adaptation for non-standard project configurations
FAQ
What does QMT do?
What platforms support QMT?
What are the use cases for QMT?
100+ free AI tools
Writing, PDF, image, and developer tools — all in your browser.