3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个非常实用的市场监控需求。在 QMT 中,我们可以通过结合 get_full_tick(获取全市场实时快照)和 get_instrumentdetail(获取涨跌停价格)来实现这一功能。
init 中获取“沪深A股”板块的所有股票代码。get_full_tick 批量获取所有股票的最新价(lastPrice)。get_instrumentdetail 获取每只股票当天的涨停价(UpStopPrice)和跌停价(DownStopPrice)。
get_instrumentdetail 导致卡顿,我们应该将这些数据缓存起来,只在初始化或第一次运行时获取。最新价 >= 涨停价,涨停家数 +1。最新价 <= 跌停价,跌停家数 +1。(涨停家数 - 跌停家数) 或者 涨停占比。print 在日志输出数值,并使用 ContextInfo.paint 在副图上画出曲线,方便观察日内趋势。# -*- coding: gbk -*-
import time
def init(ContextInfo):
# 1. 设置股票池为全市场A股
# 注意:全市场股票数量较多,建议在性能较好的机器上运行
ContextInfo.stock_list = ContextInfo.get_stock_list_in_sector('沪深A股')
ContextInfo.set_universe(ContextInfo.stock_list)
# 2. 初始化全局变量
ContextInfo.limit_price_cache = {} # 用于缓存涨跌停价格,避免重复查询
ContextInfo.last_update_time = 0 # 上次更新时间
ContextInfo.update_interval = 3 # 设置更新间隔(秒),避免过于频繁刷新导致卡顿
# 设置副图显示的指标名称(可选)
ContextInfo.paint_names = ["涨停家数", "跌停家数", "市场情绪(净涨停)"]
def handlebar(ContextInfo):
# 仅在实时行情的最后一根K线(或Tick)运行,跳过历史回测阶段的逐根K线计算以节省时间
if not ContextInfo.is_last_bar():
return
# 控制运行频率,每隔 update_interval 秒运行一次
current_time = time.time()
if current_time - ContextInfo.last_update_time < ContextInfo.update_interval:
return
ContextInfo.last_update_time = current_time
# 1. 批量获取全市场实时Tick数据
# get_full_tick 返回字典: {code: {lastPrice: ..., ...}}
ticks = ContextInfo.get_full_tick(ContextInfo.stock_list)
up_limit_count = 0 # 涨停计数
down_limit_count = 0 # 跌停计数
valid_stock_count = 0 # 有效统计的股票数
# 2. 遍历所有股票进行统计
for code in ContextInfo.stock_list:
tick_data = ticks.get(code)
# 如果没有Tick数据或最新价为0(停牌或未开盘),跳过
if not tick_data or tick_data.get('lastPrice', 0) <= 0:
continue
last_price = tick_data['lastPrice']
# 3. 获取涨跌停价格(带缓存机制)
if code not in ContextInfo.limit_price_cache:
detail = ContextInfo.get_instrumentdetail(code)
# 如果获取不到详情或涨跌停价格异常,跳过
if not detail or detail['UpStopPrice'] <= 0:
continue
# 缓存该股票的涨跌停价格
ContextInfo.limit_price_cache[code] = {
'up': detail['UpStopPrice'],
'down': detail['DownStopPrice']
}
limits = ContextInfo.limit_price_cache[code]
# 4. 判断涨跌停
# 考虑到浮点数精度,虽然金融API通常处理过,但严格来说可以用极小误差范围,这里直接比较通常也没问题
if last_price >= limits['up']:
up_limit_count += 1
elif last_price <= limits['down']:
down_limit_count += 1
valid_stock_count += 1
# 5. 计算市场情绪
# 简单定义:净涨停数 = 涨停 - 跌停
market_sentiment = up_limit_count - down_limit_count
# 6. 打印日志信息
# 获取当前时间字符串
timetag = ContextInfo.get_tick_timetag()
time_str = timetag_to_datetime(timetag, '%H:%M:%S')
log_msg = f"【市场监控】{time_str} | 涨停: {up_limit_count} 家 | 跌停: {down_limit_count} 家 | 情绪(净涨停): {market_sentiment}"
print(log_msg)
# 7. 在界面画图 (需要在副图运行策略才能看到)
# 红色线画涨停
ContextInfo.paint("涨停家数", up_limit_count, -1, 0, "red", "noaxis")
# 绿色线画跌停
ContextInfo.paint("跌停家数", down_limit_count, -1, 0, "green", "noaxis")
# 黄色线画情绪
ContextInfo.paint("情绪指标", market_sentiment, -1, 0, "yellow", "noaxis")
缓存机制 (ContextInfo.limit_price_cache):
get_instrumentdetail 是一个相对耗时的操作,且一只股票当天的涨跌停价是固定的。handlebar 的循环速度,防止界面卡顿。批量获取数据 (get_full_tick):
get_market_data),那样效率极低。get_full_tick(list) 一次性拿回几千只股票的数据是最高效的方法。频率控制 (update_interval):
绘图 (paint):
ContextInfo.paint 可以将计算结果实时绘制在 K 线图的副图上。000001.SH 上证指数)。Q: 为什么有时候涨停家数比行情软件上看到的少?
A:
UpStopPrice。有些行情软件可能包含“触及涨停但未封死”的股票,或者对涨停的定义(如ST股的5%)处理略有不同。本代码逻辑是严格的 最新价 >= 涨停价。沪深A股 板块通常包含主板、创业板和科创板。如果需要包含或排除特定板块(如北交所),可以在 init 中调整 get_stock_list_in_sector 的参数。Q: 如何定义更复杂的情绪指标?
A: 你可以在代码第 5 步修改 market_sentiment 的计算公式。例如:
up_limit_count / (up_limit_count + down_limit_count)last_price > pre_close 的家数,计算 上涨家数 / 总家数。