Vibe-Trading 全市场选股工具 screen_market:基于东财 clist 接口的 A 股/美股/港股行情排行榜实战指南
【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading
Vibe-Trading 内置的screen_market工具(MarketScreenerTool)封装了东方财富免费免鉴权的全市场行情列表接口(push2clist),可以一次性获取 A 股、美股、港股全市场的涨跌幅、成交量、成交额、换手率排行榜 Top N,无需逐 symbol 抓取。读完本文你将掌握该工具的端点寻址、市场全集选择器(fs)与排序字段(fid)映射、工具入参与返回字段约定、限速保护机制,以及如何在 Vibe-Trading 中直接调用它回答"今天哪些标的涨得最猛、成交最活跃"这类问题。
一、工具定位:一次请求获取整张市场排行榜
在交易研究中,"今天全市场涨跌幅榜""成交量最大的个股"这类问题是最高频的需求之一。常规做法是遍历候选列表逐个抓行情,既慢又容易触发上游限流。Vibe-Trading 的screen_market工具换了一种思路:直接调用东财 push2clist接口,给定一个市场全集选择器(fs),服务端就返回每只上市标的一行数据(最新价 + 常用排名指标),并由服务端按所选字段(fid)预排序,客户端只需取前 N 行。
该工具的实现位于 agent/src/tools/market_screener_tool.py,工具名为screen_market,类为MarketScreenerTool,继承自BaseTool(见 agent/src/agent/tools.py),通过 agent/src/tools/init.py 中的BaseTool.__subclasses__()自动发现机制注册到工具注册表,无需手动配置即可被 LLM 调用。它在技能索引页 agent/src/skills/eastmoney/SKILL.md 中登记在"选股检索"分类下。
二、端点与市场全集选择器(fs)
端点
https://push2.eastmoney.com/api/qt/clist/get该 URL 在源码中以模块级常量_CLIST_URL定义(agent/src/tools/market_screener_tool.py)。clist是东财 push2 行情体系的"榜单列表"接口,与逐标的 K 线接口(push2his,见 agent/backtest/loaders/eastmoney_client.py)分工不同:前者回答"全市场谁排前面",后者回答"某只标的历史走势"。
市场全集选择器(fs)
| market | fs |
|---|---|
| a(A 股,SH/SZ/主板+创业板+北交所) | m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048 |
| us(NASDAQ/NYSE/AMEX) | m:105,m:106,m:107 |
| hk(主板 + 创业板等) | m:116,m:113,m:114,m:115,m:128 |
这三组选择器在源码_MARKET_FS字典中原样保存(agent/src/tools/market_screener_tool.py)。理解它们需要对照东财的 secid 寻址体系(见 agent/backtest/loaders/eastmoney_client.py 模块文档):
- A 股:
m:0+t:6(深市主板)、m:0+t:80(创业板)、m:1+t:2(沪市主板)、m:1+t:23(科创板)、m:0+t:81+s:2048(北交所)。注意 A 股 secid 中上海用市场号1,深市/北交所用0,与这里的m:前缀一一对应。 - 美股:
m:105(NASDAQ)、m:106(NYSE)、m:107(AMEX)。 - 港股:
m:116(主板)、m:113/m:114/m:115/m:128(创业板及其他市场),其中港股 secid 固定用116前缀 + 5 位零填充代码(如00700.HK→116.00700)。
三、排序字段与查询参数:fid 怎么映射
排序字段(sort_by → fid)
| sort_by | fid | 含义 |
|---|---|---|
change_pct | f3 | 涨跌幅(默认) |
volume | f5 | 成交量 |
amount | f6 | 成交额 |
turnover | f8 | 换手率 |
该映射在源码_SORT_FID字典中原样保存(agent/src/tools/market_screener_tool.py)。排序恒为降序(po=1)——"排行"语义天然是取最大的前 N 名。
端点查询参数
| 参数 | 取值 | 说明 |
|---|---|---|
pn | 1 | 页码,固定取第一页 |
pz | <top_n> | 每页条数 |
po | 1 | 排序方向,1 = 降序 |
fid | <排序字段> | 服务端排序依据 |
fs | <市场全集> | 市场全集选择器 |
fields | f2,f3,f4,f5,f6,f8,f12,f14 | 请求返回的列 |
这些参数由源码_screen_market函数在调用get_json时逐项拼装(agent/src/tools/market_screener_tool.py),fields常量_FIELDS定义在同文件 L52。测试 agent/tests/test_market_screener_tool.py 验证了sort_by="amount"会正确映射为fid=f6、po=1、fs=m:105,m:106,m:107,证明参数拼接链路与文档一致。
四、返回字段与信封结构
返回字段(field id → 输出键)
| field id | 输出键 | 描述 |
|---|---|---|
| f12 | code | 代码 |
| f14 | name | 名称 |
| f2 | price | 最新价 |
| f3 | change_pct | 涨跌幅 |
| f4 | change | 涨跌额 |
| f5 | volume | 成交量(手) |
| f6 | amount | 成交额(货币) |
| f8 | turnover_rate | 换手率(%) |
源码中由_shape_row函数完成 field id 到输出键的归一化(agent/src/tools/market_screener_tool.py)。需要注意两个实现细节:
- 哨兵值映射为 None:东财对无值单元格返回
"-"(或整数哨兵-),_num函数(同文件 L71-L89)会将其转换为None,而不是误导性的 0.0。测试用例中平安银行的f8为"-",断言结果为turnover_rate is None(agent/tests/test_market_screener_tool.py)。例如停牌标的的换手率就是None,消费方不应把它当 0 处理。 - diff 结构归一化:push2
clist返回的data.diff在不同主机上可能是 list 也可能是按索引键控的 dict,_screen_market会把 dict 形式list(diff.values())归一化为 list(agent/src/tools/market_screener_tool.py),测试test_diff_as_dict_is_normalized覆盖了此分支。
信封结构:成功时返回 JSON 字符串:
{ "ok": true, "market": "a", "source": "eastmoney", "data": { "market": "a", "sort_by": "change_pct", "rows": [ {"code": "600519", "name": "贵州茅台", "price": 1688.0, "change_pct": 9.98, "change": 153.0, "volume": 1234567.0, "amount": 2080000000.0, "turnover_rate": 1.23} ] } }行列表嵌套在data.rows下而非裸列表,这是为了与 Vibe-Trading 所有工具的data:{...}信封形状保持一致(源码 docstring 明确说明了这一点,见 agent/src/tools/market_screener_tool.py)。失败时返回{"ok": false, "error": "..."}。
五、工具入参:market / sort_by / top_n
| 名称 | 类型 | 必选 | 描述 |
|---|---|---|---|
market | str | Y | a(A 股)/us(美股)/hk(港股) |
sort_by | str | N | change_pct(涨跌幅,默认)/volume(成交量)/amount(成交额)/turnover(换手率),降序 |
top_n | int | N | 返回 top N(1–100,默认 30) |
这三个入参的定义在MarketScreenerTool.parameters(JSON Schema 形式,agent/src/tools/market_screener_tool.py)中,execute方法对每个参数做严格校验:
market必须属于_MARKET_FS的三个键之一,否则返回"market must be one of ['a', 'us', 'hk']";sort_by必须属于_SORT_FID的四个键之一;top_n必须是正整数(布尔值True也会被拒绝,因为isinstance(True, int)为真),随后被min(top_n, 100)钳制到上限 100。常量_MAX_TOP_N = 100、_DEFAULT_TOP_N = 30定义在同文件 L55-L56。
测试文件 agent/tests/test_market_screener_tool.py 完整覆盖了这些边界:缺失 market、非法 market、非法 sort_by、top_n=0、top_n=True全部返回ok: false错误信封,HTTP 失败(如 429)也会被兜底捕获并转成{"ok": false, "error": "..."}而不是抛异常。
六、限速保护:为什么可以放心调用
东财按源 IP限流,并会临时封禁突发请求的客户端,因此screen_market的每次请求都走共享的eastmoneyper-host 节流层:
MarketScreenerTool导入backtest.loaders.eastmoney_client.get_json,而后者调用 agent/backtest/loaders/_http.py 的throttled_get_json,以host_key="eastmoney"通过进程级HostThrottle保证同一 host 桶内相邻请求的最小间隔;- 最小间隔默认
1.0秒,可由环境变量VIBE_TRADING_EASTMONEY_MIN_INTERVAL调整(resolve_min_interval解析,见 agent/backtest/loaders/eastmoney_client.py),批量任务可适当调大; HostThrottle还在间隔之上叠加最多 0.4 秒的随机抖动,避免多个并发调用方同时到期齐射(见 agent/backtest/loaders/_http.py),并复用 per-process 的requests.Session摊薄 TCP/TLS 握手开销。
这意味着:不要绕过工具对端点直接发起裸 HTTP 突发请求。top_n上限 100 同时保证了全市场列表的响应体规模有界,不会撑爆 LLM 上下文——即使请求全市场,拿到的也只是一张最多 100 行的紧凑表格。
七、调用范例
直接调用(在agent/目录下运行,无需 token)
from src.tools.market_screener_tool import MarketScreenerTool # A 股今日涨幅榜前 20 print(MarketScreenerTool().execute(market="a", sort_by="change_pct", top_n=20)) # 美股成交额榜前 10 print(MarketScreenerTool().execute(market="us", sort_by="amount", top_n=10)) # 港股换手率榜前 50 print(MarketScreenerTool().execute(market="hk", sort_by="turnover", top_n=50))与代码搜索联动的研究流程:技能脚本 agent/src/skills/eastmoney/scripts/screen_search_example.py 演示了"先search_symbol解析标的、再screen_market看市场动向"的完整范式——先用SymbolSearchTool把公司名/代码片段解析为候选 symbol,再用screen_market拉取市场榜单,二者配合即可从"模糊查询"走到"全市场扫描"。
八、在 Agent 与多 Agent 编排中的使用
screen_market在设计上就是给 LLM 用的只读盘点工具:MarketScreenerTool的description明确指示模型"用这个工具找今天的大幅波动标的或最活跃标的,而不是逐个 symbol 抓取"(agent/src/tools/market_screener_tool.py),并声明repeatable = True,允许在同一轮对话中多次调用以对比不同市场/不同排序。
在 Vibe-Trading 的 swarm 多 Agent 编排中,screen_market被用作研究型 worker 的universe 枚举工具:
- 统计套利台 preset(agent/src/swarm/presets/statistical_arbitrage_desk.yaml):先
screen_market枚举当日热点/活跃标的,再以get_market_data拉价格面板; - 配对研究实验室 preset(agent/src/swarm/presets/pairs_research_lab.yaml):用
screen_market枚举{market}/{sector}候选池后再逐对扫描。
这体现了该工具的核心定位:全市场榜单是研究流水线的起点而非终点——先低成本获得"今天谁最热"的粗筛结果,再对入选标的做深度数据拉取与因子分析,避免一开始就盲目遍历全市场。
九、适用前提与限制
- 数据范围:仅覆盖 A 股、美股、港股三大市场,不含期货、期权、外汇等衍生品行情;
- 实时性:返回的是东财 push2 的行情列表快照,适合当日排名类问题;历史榜单序列不在本工具职责内;
- 限流依赖:可靠性建立在共享节流层之上,若在工具外绕过节流直连端点,可能触发东财按 IP 临时封禁;
- 字段精度:
volume以"手"为单位,amount为货币单位成交额,turnover_rate为百分比;停牌等无值场景下对应字段为None而非 0,下游计算需做空值防御。
【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考