@ricequant2026/rqdata-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,231 @@
1
+ # Changelog
2
+
3
+ ## [1.0.0] - 2026-03-27
4
+
5
+ ### 首次发布
6
+
7
+ **核心特性**
8
+ - Go 实现的高性能 CLI 工具
9
+ - 支持 68 个金融数据 API 命令
10
+ - NDJSON/JSON/CSV 多格式输出
11
+ - 系统 Keyring 集成,安全存储凭证
12
+ - 自动 Token 管理和刷新
13
+ - Schema 自动生成,含中文参数描述
14
+
15
+ **数据覆盖**
16
+ - 指数数据(8 个命令)
17
+ - A股数据(23 个命令)
18
+ - 港股数据(8 个命令)
19
+ - 交易日历(5 个命令)
20
+ - 基金数据(9 个命令)
21
+ - 期货数据(8 个命令)
22
+ - 期权数据(7 个命令)
23
+ - 宏观数据(6 个命令)
24
+
25
+ **技术亮点**
26
+ - 单文件可执行,静态编译
27
+ - 跨平台支持(Linux/macOS/Windows)
28
+ - 类型安全的参数验证
29
+ - AI Agent 友好的 NDJSON 输出
30
+
31
+ **文档**
32
+ - 完整的快速上手指南
33
+ - 68 个命令的详细参考文档
34
+ - Go 构建指南
35
+
36
+
37
+ ### Added
38
+
39
+ #### 核心功能
40
+ - ✨ 完整的 RQData HTTP API 支持
41
+ - 🚀 CURL 连接复用优化(QPS 提升 44.4%)
42
+ - ⚡ Daemon 模式支持(长连接服务)
43
+ - 📊 多种输出格式(NDJSON、JSON、CSV)
44
+ - 🔒 严格的 Schema 验证
45
+ - 🎯 字段过滤功能(`--fields` 参数)
46
+
47
+ #### 数据模块
48
+ - 📈 **Index(指数)** - 指数列表、行情、成分股、权重
49
+ - 📊 **Stock CN(A股)** - 行情、财务、分红、融资融券、北向资金、停牌
50
+ - 🇭🇰 **Stock HK(港股)** - 行情、财务、分红
51
+ - 📅 **Calendar(交易日历)** - 交易日列表、前后交易日查询
52
+ - 📉 **Macro(宏观)** - Shibor、CPI、PPI、GDP
53
+
54
+ #### 认证系统
55
+ - 🔑 环境变量认证(推荐)
56
+ - 🔐 交互式登录
57
+ - 💾 Token 缓存机制
58
+ - ⏰ 自动 Token 刷新
59
+
60
+ #### 性能优化
61
+ - 🔄 CURL 连接复用
62
+ - 🌐 TCP Keep-Alive
63
+ - 📡 HTTP 持久连接
64
+ - ⚡ Daemon 模式(批量查询性能提升 25%)
65
+
66
+ #### 测试覆盖
67
+ - ✅ 74 个功能测试(100% 通过率)
68
+ - 📊 5 个性能测试场景
69
+ - 🔬 三方性能对比(CLI vs Daemon vs Python)
70
+ - 🧪 全模块性能验证
71
+
72
+ ### Performance
73
+
74
+ #### 性能基准
75
+ - **单次请求**: 0.140s(优化前 0.154s,提升 9.1%)
76
+ - **连续请求**: 0.150s/次(优化前 0.200s/次,提升 25%)
77
+ - **平均 QPS**: 7.22 req/s(优化前 5 req/s,提升 44.4%)
78
+ - **大数据吞吐**: 7,652 行/秒
79
+
80
+ #### 场景性能
81
+ - **1-3次查询**: CLI 直接模式最快(比 Python 快 68-78%)
82
+ - **3-10次查询**: CLI Daemon 模式最快(比 Python 快 60-78%)
83
+ - **20+次高频**: Python API 最快(比 CLI 快 12倍)
84
+ - **大数据量**: Python API 最快(比 CLI 快 2.5倍)
85
+
86
+ ### Documentation
87
+
88
+ - 📖 完整的 README.md
89
+ - 📚 API 文档
90
+ - 🔧 开发指南
91
+ - 📊 性能测试报告
92
+ - 🤝 贡献指南
93
+ - 📝 更新日志
94
+
95
+ ### Technical Details
96
+
97
+ #### 架构
98
+ - C++17 标准
99
+ - CMake 构建系统
100
+ - vcpkg 依赖管理
101
+ - 模块化设计
102
+
103
+ #### 依赖库
104
+ - libcurl - HTTP 客户端
105
+ - nlohmann-json - JSON 处理
106
+ - CLI11 - 命令行解析
107
+ - csv-parser - CSV 解析
108
+ - fmt - 格式化输出
109
+
110
+ #### 平台支持
111
+ - ✅ macOS (Apple Silicon & Intel)
112
+ - ✅ Linux (x86_64)
113
+ - 🚧 Windows (计划中)
114
+
115
+ ### Testing
116
+
117
+ #### 功能测试
118
+ - Index 模块: 8/8 通过 ✅
119
+ - Stock CN 模块: 23/23 通过 ✅
120
+ - Stock HK 模块: 8/8 通过 ✅
121
+ - Calendar 模块: 5/5 通过 ✅
122
+ - Fund 模块: 9/9 通过 ✅
123
+ - Futures 模块: 8/8 通过 ✅
124
+ - Options 模块: 7/7 通过 ✅
125
+ - Macro 模块: 6/6 通过 ✅
126
+ - **总计**: 74/74 通过(100%)✅
127
+
128
+ #### 性能测试
129
+ - 单次请求性能测试 ✅
130
+ - 连续请求性能测试 ✅
131
+ - 大数据量性能测试 ✅
132
+ - 高频请求性能测试 ✅
133
+ - 三方对比测试 ✅
134
+
135
+ ### Known Issues
136
+
137
+ - Stock HK 模块性能相对较慢(QPS 3.17)- 受 API 响应速度限制
138
+ - 高频场景(20+次/秒)性能不如 Python API - 受进程启动开销限制
139
+
140
+ ### Recommendations
141
+
142
+ #### 使用建议
143
+ - **临时查询(1-3次)**: 使用 CLI 直接模式
144
+ - **批量脚本(3-20次)**: 使用 CLI Daemon 模式
145
+ - **高频查询(20+次)**: 使用 Python API
146
+ - **大数据量(10K+行)**: 使用 Python API
147
+
148
+ ## [1.0.1] - 2026-03-10
149
+
150
+ ### Fixed
151
+
152
+ #### 财务数据功能修复
153
+ - 🐛 **修复 `stock cn financial` 命令 HTTP 400 错误**
154
+ - 问题:`get_pit_financials_ex` API 要求 `fields` 必填,但 CLI 在构建请求时把 `fields` 从 payload 中剔除
155
+ - 修复:针对 `get_pit_financials_ex` 方法,保留 payload 中的 `fields` 参数传给 API
156
+ - 影响:现在可以正常获取三大表财务数据(资产负债表、利润表、现金流量表)
157
+
158
+ - 🐛 **修复 `stock cn financial-indicator` 命令 HTTP 400 错误**
159
+ - 问题:使用了错误的 method `get_factor`(参数格式不匹配)
160
+ - 修复:改用 `get_pit_financials_ex` + 衍生指标字段
161
+ - 影响:现在可以正常获取 ROE、毛利率、净利率等财务衍生指标
162
+
163
+ #### 认证问题修复
164
+ - 🐛 **修复 Token 过期导致的 HTTP 401 错误**
165
+ - 问题:缓存的 token 过期后,CLI 继续使用导致认证失败
166
+ - 解决方案:删除 `~/.rqdata/token.cache` 后,CLI 自动重新认证获取新 token
167
+ - 建议:如遇 401 错误,运行 `rm -f ~/.rqdata/token.cache` 清除过期缓存
168
+
169
+ ### Added
170
+
171
+ #### 完整的 HALO 策略支持
172
+ - ✅ 现在可以用纯 CLI 完成 HALO 策略筛选
173
+ - ✅ 支持获取三大表财务数据
174
+ - ✅ 支持获取财务衍生指标(ROE、毛利率等)
175
+ - ✅ 支持批量查询 20 只股票的财务数据
176
+
177
+ ### Documentation
178
+
179
+ - 📝 添加财务数据 API 使用说明
180
+ - 📝 添加衍生指标字段名参考
181
+ - 📝 添加 Token 过期问题排查指南
182
+
183
+ ### Technical Details
184
+
185
+ #### 代码修改
186
+ - `src/commands/stock_cn.cpp` 第 71-84 行:修改 `execute_stock_cn_command` 函数,针对 `get_pit_financials_ex` 保留 `fields` 参数
187
+ - `src/commands/stock_cn.cpp` 第 426 行:`financial-indicator` 命令改用 `get_pit_financials_ex` 方法
188
+
189
+ #### 测试验证
190
+ - ✅ `stock cn financial` 命令测试通过
191
+ - ✅ `stock cn financial-indicator` 命令测试通过
192
+ - ✅ HALO 策略 20 只股票批量查询测试通过
193
+
194
+ ### Notes
195
+
196
+ #### 衍生指标字段名
197
+ - 使用完整名称:`return_on_equity_weighted_average`(不是 `roe`)
198
+ - TTM 字段使用大写:`net_profitTTM`(不是 `net_profit_ttm`)
199
+ - Quarter 格式使用小写:`2024q3`(不是 `2024Q3`)
200
+
201
+ ## [Unreleased]
202
+
203
+ ### Planned Features
204
+
205
+ - 🚧 Windows 平台支持
206
+ - 🚧 批量 API 支持
207
+ - 🚧 并行请求支持
208
+ - 🚧 MCP Server 支持
209
+ - 🚧 更多输出格式(Parquet、Arrow)
210
+
211
+ ### Future Optimizations
212
+
213
+ - 🔮 CSV 解析优化
214
+ - 🔮 二进制数据格式支持
215
+ - 🔮 内存池优化
216
+ - 🔮 并发连接池
217
+
218
+ ---
219
+
220
+ ## Version History
221
+
222
+ - **v1.0.1** (2026-03-10) - 财务数据修复
223
+ - **v1.0.0** (2026-03-10) - 初始版本发布
224
+
225
+ ---
226
+
227
+ ## Links
228
+
229
+ - [Repository](http://git.ricequant.com/projects/RQAI/repos/rqdata-cli)
230
+ - [Documentation](http://git.ricequant.com/projects/RQAI/repos/rqdata-cli/browse/docs)
231
+ - [Issues](https://jira.ricequant.com)(RiceQuant 内部 Jira)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 rq-cli contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,375 @@
1
+ # RQData CLI
2
+
3
+ > 高性能的 RQData 命令行工具,为量化研究和 AI Agent 设计
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Go Version](https://img.shields.io/badge/Go-1.21%2B-blue.svg)](https://golang.org)
7
+ [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)]()
8
+
9
+ ---
10
+
11
+ ## 📖 文档导航
12
+
13
+ - **[🚀 快速上手指南](docs/QUICKSTART.md)** - 5分钟完成安装和第一次查询
14
+ - **[🔧 Go 构建指南](BUILD_GO.md)** - Go 版本编译说明
15
+ - **[📝 更新日志](CHANGELOG.md)** - 版本历史和变更记录
16
+
17
+ ---
18
+
19
+ ## ✨ 特性
20
+
21
+ - 🚀 **高性能** - Go 原生实现,单文件可执行,无依赖
22
+ - 🤖 **AI Agent 友好** - NDJSON 流式输出,JSON Payload 输入
23
+ - 📊 **全面数据覆盖** - A股、港股、期货、期权、基金、指数、宏观数据
24
+ - 🔒 **类型安全** - 严格的 Schema 验证,自动参数类型推断
25
+ - 🎯 **字段过滤** - `--fields` 参数精确控制返回数据
26
+ - 📖 **自文档化** - `--schema` 标志输出完整 API 文档(含中文描述)
27
+ - 🔐 **安全认证** - 系统 Keyring 集成,Token 自动管理
28
+
29
+ ## 📦 快速安装
30
+
31
+ ### 通过 npm 安装(推荐)
32
+
33
+ ```bash
34
+ npm install -g @ricequant2026/rqdata-cli
35
+ ```
36
+
37
+ 安装完成后即可直接使用:
38
+
39
+ ```bash
40
+ rqdata --version
41
+ rqdata --help
42
+ ```
43
+
44
+ ### 从源码编译
45
+
46
+ ```bash
47
+ # 克隆仓库
48
+ git clone http://git.ricequant.com/scm/RQAI/rqdata-cli.git
49
+ cd rqdata-cli
50
+
51
+ # 编译(需要 Go 1.21+)
52
+ VERSION=1.0.0 ./build.sh
53
+
54
+ # 安装到系统路径
55
+ sudo mv rqdata /usr/local/bin/
56
+ ```
57
+
58
+ ### 跨平台构建
59
+
60
+ ```bash
61
+ # Linux
62
+ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w -X github.com/rqdata/rqdata-cli/cmd.Version=1.0.0" -o rqdata-linux main.go
63
+
64
+ # macOS (Intel)
65
+ CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -trimpath -ldflags="-s -w -X github.com/rqdata/rqdata-cli/cmd.Version=1.0.0" -o rqdata-macos-amd64 main.go
66
+
67
+ # macOS (Apple Silicon)
68
+ CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -trimpath -ldflags="-s -w -X github.com/rqdata/rqdata-cli/cmd.Version=1.0.0" -o rqdata-macos-arm64 main.go
69
+
70
+ # Windows
71
+ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-s -w -X github.com/rqdata/rqdata-cli/cmd.Version=1.0.0" -o rqdata.exe main.go
72
+ ```
73
+
74
+ 详见 [BUILD_GO.md](BUILD_GO.md)
75
+
76
+ ### 验证安装
77
+
78
+ ```bash
79
+ rqdata --version
80
+ rqdata --help
81
+ ```
82
+
83
+ ## 🔑 认证配置
84
+
85
+ ### 环境变量(推荐)
86
+
87
+ ```bash
88
+ # 添加到 ~/.zshrc 或 ~/.bashrc
89
+ export RQDATA_USERNAME="your_phone_or_email"
90
+ export RQDATA_PASSWORD="your_password"
91
+
92
+ # 重新加载
93
+ source ~/.zshrc
94
+ ```
95
+
96
+ ### 交互式登录
97
+
98
+ ```bash
99
+ rqdata auth login
100
+ ```
101
+
102
+ ### 验证
103
+
104
+ ```bash
105
+ rqdata auth status
106
+ ```
107
+
108
+ > 💡 没有账号?访问 [ricequant.com](https://www.ricequant.com) 申请试用
109
+
110
+ ## 🚀 快速开始
111
+
112
+ ### 示例 1: 获取股票行情
113
+
114
+ ```bash
115
+ rqdata stock cn price --payload '{
116
+ "order_book_ids": ["600000.XSHG", "000001.XSHE"],
117
+ "start_date": "2024-01-01",
118
+ "end_date": "2024-01-31"
119
+ }'
120
+ ```
121
+
122
+ ### 示例 2: 获取指数成分股
123
+
124
+ ```bash
125
+ rqdata index constituents --payload '{
126
+ "order_book_id": "000300.XSHG",
127
+ "date": "2024-01-31"
128
+ }'
129
+ ```
130
+
131
+ ### 示例 3: 获取宏观数据
132
+
133
+ ```bash
134
+ rqdata macro shibor --payload '{
135
+ "start_date": "2024-01-01",
136
+ "end_date": "2024-12-31"
137
+ }'
138
+ ```
139
+
140
+ ### 示例 4: 查看命令文档
141
+
142
+ ```bash
143
+ # 查看所有命令
144
+ rqdata --help
145
+
146
+ # 查看特定命令的参数说明
147
+ rqdata stock cn price --schema
148
+ ```
149
+
150
+ > 📖 更多示例请查看 [快速上手指南](docs/QUICKSTART.md)
151
+
152
+ ## 📚 支持的命令
153
+
154
+ ### 🔐 认证管理
155
+ - `rqdata auth login` - 交互式登录
156
+ - `rqdata auth status` - 查看认证状态
157
+
158
+ ### ⚡ Daemon 模式
159
+ - `rqdata daemon start` - 启动 daemon(批量查询性能提升 25%)
160
+ - `rqdata daemon stop` - 停止 daemon
161
+ - `rqdata daemon status` - 查看状态
162
+
163
+ ### 📈 指数数据(4个命令)
164
+ - `rqdata index instruments` - 获取指数列表
165
+ - `rqdata index price` - 获取指数行情
166
+ - `rqdata index constituents` - 获取成分股列表
167
+ - `rqdata index weights` - 获取成分股权重
168
+
169
+ ### 📊 A股数据(8个命令)
170
+ - `rqdata stock cn instruments` - 获取股票列表
171
+ - `rqdata stock cn price` - 获取股票行情
172
+ - `rqdata stock cn dividends` - 获取分红数据
173
+ - `rqdata stock cn financials` - 获取财务数据
174
+ - `rqdata stock cn shares` - 获取股本结构
175
+ - `rqdata stock cn margin` - 获取融资融券
176
+ - `rqdata stock cn suspended` - 获取停牌信息
177
+ - `rqdata stock cn northbound` - 获取北向资金
178
+
179
+ ### 🇭🇰 港股数据(4个命令)
180
+ - `rqdata stock hk instruments` - 获取港股列表
181
+ - `rqdata stock hk price` - 获取港股行情
182
+ - `rqdata stock hk dividends` - 获取分红数据
183
+ - `rqdata stock hk financials` - 获取财务数据
184
+
185
+ ### 📅 交易日历(3个命令)
186
+ - `rqdata calendar dates` - 获取交易日列表
187
+ - `rqdata calendar prev` - 获取前一交易日
188
+ - `rqdata calendar next` - 获取后一交易日
189
+
190
+ ### 📉 宏观数据(4个命令)
191
+ - `rqdata macro shibor` - 获取 Shibor 利率
192
+ - `rqdata macro price-cpi` - 获取 CPI 数据
193
+ - `rqdata macro price-ppi` - 获取 PPI 数据
194
+ - `rqdata macro gdp` - 获取 GDP 数据
195
+
196
+ > 📖 **总计 26 个命令**,完整文档请查看 [快速上手指南](docs/QUICKSTART.md)
197
+
198
+ ## 🎨 输出格式
199
+
200
+ ```bash
201
+ # NDJSON(默认,适合流式处理)
202
+ rqdata stock cn price --payload '{...}'
203
+
204
+ # JSON(结构化数组)
205
+ rqdata stock cn price --payload '{...}' --format json
206
+
207
+ # CSV(原始格式)
208
+ rqdata stock cn price --payload '{...}' --format csv
209
+ ```
210
+
211
+ ## 🎨 高级功能
212
+
213
+ ### Schema 自动生成
214
+
215
+ 使用 Python 脚本从 rqdatac 自动生成参数 schema:
216
+
217
+ ```bash
218
+ # 生成 schema.json(需要 rqdatac 环境)
219
+ /home/lhz/.miniconda3/envs/zz1000/bin/python scripts/generate_schema_json.py
220
+
221
+ # 查看命令参数说明
222
+ rqdata stock cn price --schema
223
+ ```
224
+
225
+ 输出包含完整的中文参数描述和类型信息。
226
+
227
+ ### 批量查询示例
228
+
229
+ ```bash
230
+ # 批量查询多个股票
231
+ for stock in 000001.XSHE 600000.XSHG 600519.XSHG; do
232
+ rqdata stock cn price --payload "{
233
+ \"order_book_ids\": [\"$stock\"],
234
+ \"start_date\": \"2024-01-01\",
235
+ \"end_date\": \"2024-01-31\"
236
+ }" > "${stock}.ndjson"
237
+ done
238
+ ```
239
+
240
+ ## 🛠️ 开发
241
+
242
+ ### 技术栈
243
+
244
+ - **语言**: Go 1.21+
245
+ - **依赖**:
246
+ - `github.com/spf13/cobra` - CLI 框架
247
+ - `github.com/zalando/go-keyring` - 系统 Keyring 集成
248
+ - `golang.org/x/term` - 终端交互
249
+ - **配置**:
250
+ - `internal/configs/commands.json` - 命令定义
251
+ - `internal/configs/schema.json` - 参数 Schema(自动生成)
252
+
253
+ ### 项目结构
254
+
255
+ ```
256
+ rqdata-cli/
257
+ ├── main.go # 入口文件
258
+ ├── cmd/ # 命令定义
259
+ ├── internal/ # 内部包
260
+ │ ├── auth/ # 认证模块
261
+ │ ├── client/ # HTTP 客户端
262
+ │ ├── configs/ # 配置文件(commands.json, schema.json)
263
+ │ ├── executor/ # 命令执行器
264
+ │ ├── formatter/ # 输出格式化
265
+ │ └── loader/ # 配置加载器
266
+ ├── scripts/ # 工具脚本
267
+ │ └── generate_schema_json.py # Schema 生成脚本
268
+ ├── tests/ # 测试
269
+ └── docs/ # 文档
270
+ ```
271
+
272
+ ### 构建与测试
273
+
274
+ ```bash
275
+ # 编译
276
+ VERSION=dev ./build.sh
277
+
278
+ # 运行
279
+ ./rqdata --help
280
+
281
+ # 测试
282
+ ./rqdata auth status
283
+ ./rqdata stock cn price --schema
284
+ ```
285
+
286
+ ## 📖 文档
287
+
288
+ - [Go 构建指南](BUILD_GO.md)
289
+ - [快速上手](docs/QUICKSTART.md)
290
+ - [命令列表](docs/rqdata_cli_commands.md)
291
+ - [更新日志](CHANGELOG.md)
292
+
293
+ ## 🚢 npm 发布
294
+
295
+ 项目现在采用“主包 + 平台包”的发布方式:
296
+
297
+ - `@ricequant2026/rqdata-cli`:主包,只包含 JS wrapper 和平台依赖声明
298
+ - `@ricequant2026/rqdata-cli-linux-x64`
299
+ - `@ricequant2026/rqdata-cli-darwin-x64`
300
+ - `@ricequant2026/rqdata-cli-darwin-arm64`
301
+ - `@ricequant2026/rqdata-cli-win32-x64`
302
+
303
+ 发布时先发平台包,再发主包:
304
+
305
+ ```bash
306
+ npm version patch
307
+ npm run publish:all
308
+ ```
309
+
310
+ `publish:all` 内部会对所有 scoped 包使用 `npm publish --access public`。
311
+
312
+ 如果只是先测试发布流程,建议先用预发布版本和 `next` tag:
313
+
314
+ ```bash
315
+ npm version prerelease --preid rc
316
+ npm run publish:next
317
+ ```
318
+
319
+ 如果只想验证发布命令本身而不真正上传:
320
+
321
+ ```bash
322
+ npm run publish:dry-run
323
+ ```
324
+
325
+ 如果只想本地生成所有 tarball:
326
+
327
+ ```bash
328
+ npm run pack:all
329
+ ```
330
+
331
+ 如果只想本地验证当前平台的主包执行链路:
332
+
333
+ ```bash
334
+ npm run build:npm
335
+ npm run link:platform
336
+ node bin/rqdata.js --version
337
+ ```
338
+
339
+ ## 📝 更新日志
340
+
341
+ ### v2.0.0 (2026-03-27) - Go 重写版本
342
+
343
+ - ✨ 使用 Go 完全重写,单文件可执行
344
+ - 🔐 系统 Keyring 集成,安全存储凭证
345
+ - 📖 Schema 自动生成,支持中文参数描述
346
+ - 🚀 静态编译,跨平台分发
347
+ - 🔧 修复 HTML 转义问题(`array<string>` 显示正确)
348
+ - 📊 完整的数据覆盖(指数、A股、港股、期货、期权、基金、宏观)
349
+
350
+ ### v1.0.0 (2026-03-10) - C++ 版本
351
+
352
+ - ✨ 初始 C++ 版本发布
353
+ - 🚀 CURL 连接复用优化
354
+ - 📊 完整的数据覆盖
355
+
356
+ 详见 [CHANGELOG.md](CHANGELOG.md)
357
+
358
+ ## 📄 许可证
359
+
360
+ MIT License - 详见 [LICENSE](LICENSE)
361
+
362
+ ## 🙏 致谢
363
+
364
+ - [RQData](https://www.ricequant.com) - 提供数据 API
365
+ - [CLI11](https://github.com/CLIUtils/CLI11) - 命令行解析
366
+ - [nlohmann/json](https://github.com/nlohmann/json) - JSON 处理
367
+
368
+ ## 📞 支持
369
+
370
+ - 🐛 Issues: [Jira](https://jira.ricequant.com)(RiceQuant 内部)
371
+ - 📚 文档: [项目文档](http://git.ricequant.com/projects/RQAI/repos/rqdata-cli/browse/docs)
372
+
373
+ ---
374
+
375
+ **注意**: 使用本工具需要有效的 RQData 账号。访问 [ricequant.com](https://www.ricequant.com) 申请试用或购买。
package/bin/rqdata.js ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require('node:child_process');
4
+ const { findCurrentTarget } = require('../scripts/npm/platforms');
5
+
6
+ function resolveBinary() {
7
+ const target = findCurrentTarget();
8
+
9
+ if (!target) {
10
+ console.error(`Unsupported platform: ${process.platform}-${process.arch}`);
11
+ process.exit(1);
12
+ }
13
+
14
+ let binary;
15
+
16
+ try {
17
+ ({ binary } = require(target.packageName));
18
+ } catch (error) {
19
+ console.error(`Missing platform package: ${target.packageName}`);
20
+ console.error('Reinstall the package on a supported platform or verify optional dependencies are enabled.');
21
+ process.exit(1);
22
+ }
23
+
24
+ if (!binary) {
25
+ console.error('rqdata binary is missing. Reinstall the package or rebuild release artifacts.');
26
+ process.exit(1);
27
+ }
28
+
29
+ return binary;
30
+ }
31
+
32
+ const result = spawnSync(resolveBinary(), process.argv.slice(2), {
33
+ stdio: 'inherit'
34
+ });
35
+
36
+ if (result.error) {
37
+ console.error(result.error.message);
38
+ process.exit(1);
39
+ }
40
+
41
+ process.exit(result.status === null ? 1 : result.status);
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@ricequant2026/rqdata-cli",
3
+ "version": "1.0.0",
4
+ "description": "RQData CLI for AI agents and quantitative research",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "rqdata": "bin/rqdata.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "scripts/npm/",
12
+ "README.md",
13
+ "LICENSE",
14
+ "CHANGELOG.md"
15
+ ],
16
+ "optionalDependencies": {
17
+ "@ricequant2026/rqdata-cli-linux-x64": "1.0.0",
18
+ "@ricequant2026/rqdata-cli-darwin-x64": "1.0.0",
19
+ "@ricequant2026/rqdata-cli-darwin-arm64": "1.0.0",
20
+ "@ricequant2026/rqdata-cli-win32-x64": "1.0.0"
21
+ },
22
+ "scripts": {
23
+ "build:npm": "node scripts/npm/build-packages.js",
24
+ "link:platform": "node scripts/npm/link-platform-package.js",
25
+ "pack:all": "node scripts/npm/pack-all.js",
26
+ "publish:all": "node scripts/npm/publish-all.js",
27
+ "publish:next": "NPM_TAG=next node scripts/npm/publish-all.js",
28
+ "publish:dry-run": "NPM_TAG=next NPM_DRY_RUN=1 node scripts/npm/publish-all.js",
29
+ "pack:dry-run": "npm pack --dry-run"
30
+ },
31
+ "keywords": [
32
+ "rqdata",
33
+ "cli",
34
+ "finance",
35
+ "quant",
36
+ "agent"
37
+ ],
38
+ "engines": {
39
+ "node": ">=18"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/rqdata/rqdata-cli.git"
44
+ },
45
+ "homepage": "https://github.com/rqdata/rqdata-cli",
46
+ "bugs": {
47
+ "url": "https://github.com/rqdata/rqdata-cli/issues"
48
+ }
49
+ }
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { mkdirSync, rmSync, readFileSync, writeFileSync, copyFileSync, chmodSync } = require('node:fs');
4
+ const path = require('node:path');
5
+ const { spawnSync } = require('node:child_process');
6
+ const { DIST_DIR, PLATFORM_TARGETS, PACKAGES_DIR } = require('./platforms');
7
+
8
+ const ROOT = path.resolve(__dirname, '..', '..');
9
+ const pkg = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
10
+ const VERSION = process.env.VERSION || pkg.version;
11
+ const GOCACHE_DIR = process.env.GOCACHE_DIR || path.join(ROOT, '.cache', 'go-build');
12
+
13
+ function run(command, args, options = {}) {
14
+ const result = spawnSync(command, args, {
15
+ cwd: options.cwd || ROOT,
16
+ stdio: 'inherit',
17
+ env: {
18
+ ...process.env,
19
+ ...options.env
20
+ }
21
+ });
22
+
23
+ if (result.status !== 0) {
24
+ process.exit(result.status === null ? 1 : result.status);
25
+ }
26
+ }
27
+
28
+ function buildTargets() {
29
+ rmSync(DIST_DIR, { recursive: true, force: true });
30
+ mkdirSync(DIST_DIR, { recursive: true });
31
+ mkdirSync(GOCACHE_DIR, { recursive: true });
32
+
33
+ for (const target of PLATFORM_TARGETS) {
34
+ const outputPath = path.join(DIST_DIR, target.output);
35
+ const ldflags = `-s -w -X github.com/rqdata/rqdata-cli/cmd.Version=${VERSION}`;
36
+
37
+ console.log(`Building ${target.key} -> ${target.output}`);
38
+ run('go', ['build', '-trimpath', '-ldflags', ldflags, '-o', outputPath, 'main.go'], {
39
+ env: {
40
+ CGO_ENABLED: '0',
41
+ GOCACHE: GOCACHE_DIR,
42
+ GOOS: target.goos,
43
+ GOARCH: target.goarch
44
+ }
45
+ });
46
+ }
47
+ }
48
+
49
+ function writePlatformPackage(target) {
50
+ const packageDir = target.packageDir;
51
+ const binarySource = path.join(DIST_DIR, target.output);
52
+ const binaryTarget = path.join(packageDir, 'bin', target.binName);
53
+
54
+ rmSync(packageDir, { recursive: true, force: true });
55
+ mkdirSync(path.join(packageDir, 'bin'), { recursive: true });
56
+
57
+ copyFileSync(binarySource, binaryTarget);
58
+ if (target.os !== 'win32') {
59
+ chmodSync(binaryTarget, 0o755);
60
+ }
61
+
62
+ writeFileSync(
63
+ path.join(packageDir, 'index.js'),
64
+ [
65
+ "const path = require('node:path');",
66
+ '',
67
+ `module.exports.binary = path.join(__dirname, 'bin', '${target.binName}');`,
68
+ ''
69
+ ].join('\n')
70
+ );
71
+
72
+ writeFileSync(
73
+ path.join(packageDir, 'README.md'),
74
+ `# ${target.packageName}\n\nPlatform binary package for @ricequant2026/rqdata-cli.\n`
75
+ );
76
+
77
+ writeFileSync(
78
+ path.join(packageDir, 'package.json'),
79
+ JSON.stringify(
80
+ {
81
+ name: target.packageName,
82
+ version: VERSION,
83
+ description: `Platform binary for @ricequant2026/rqdata-cli (${target.key})`,
84
+ license: pkg.license,
85
+ os: [target.os],
86
+ cpu: [target.cpu],
87
+ files: ['bin/', 'index.js', 'README.md', 'LICENSE'],
88
+ main: 'index.js'
89
+ },
90
+ null,
91
+ 2
92
+ ) + '\n'
93
+ );
94
+
95
+ copyFileSync(path.join(ROOT, 'LICENSE'), path.join(packageDir, 'LICENSE'));
96
+ }
97
+
98
+ function materializePackages() {
99
+ rmSync(PACKAGES_DIR, { recursive: true, force: true });
100
+ mkdirSync(PACKAGES_DIR, { recursive: true });
101
+
102
+ for (const target of PLATFORM_TARGETS) {
103
+ writePlatformPackage(target);
104
+ }
105
+ }
106
+
107
+ buildTargets();
108
+ materializePackages();
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { mkdirSync, rmSync, symlinkSync, existsSync } = require('node:fs');
4
+ const path = require('node:path');
5
+ const { findCurrentTarget } = require('./platforms');
6
+
7
+ const ROOT = path.resolve(__dirname, '..', '..');
8
+ const NODE_MODULES = path.join(ROOT, 'node_modules');
9
+
10
+ const target = findCurrentTarget();
11
+
12
+ if (!target) {
13
+ console.warn(`Unsupported platform for local link: ${process.platform}-${process.arch}`);
14
+ process.exit(0);
15
+ }
16
+
17
+ const destination = path.join(NODE_MODULES, target.packageName);
18
+ const destinationDir = path.dirname(destination);
19
+
20
+ mkdirSync(NODE_MODULES, { recursive: true });
21
+ mkdirSync(destinationDir, { recursive: true });
22
+ rmSync(destination, { recursive: true, force: true });
23
+ rmSync(path.join(NODE_MODULES, target.packageName.split('/').pop()), { recursive: true, force: true });
24
+
25
+ if (!existsSync(target.packageDir)) {
26
+ console.error(`Platform package has not been built: ${target.packageDir}`);
27
+ console.error('Run `npm run build:npm` first.');
28
+ process.exit(1);
29
+ }
30
+
31
+ symlinkSync(target.packageDir, destination, 'dir');
32
+ console.log(`Linked ${target.packageName} -> ${target.packageDir}`);
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { readFileSync } = require('node:fs');
4
+ const path = require('node:path');
5
+ const { spawnSync } = require('node:child_process');
6
+ const { PLATFORM_TARGETS } = require('./platforms');
7
+
8
+ const ROOT = path.resolve(__dirname, '..', '..');
9
+ const pkg = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
10
+
11
+ function run(command, args, cwd = ROOT) {
12
+ const result = spawnSync(command, args, {
13
+ cwd,
14
+ stdio: 'inherit',
15
+ env: process.env
16
+ });
17
+
18
+ if (result.status !== 0) {
19
+ process.exit(result.status === null ? 1 : result.status);
20
+ }
21
+ }
22
+
23
+ run('node', ['scripts/npm/build-packages.js']);
24
+
25
+ for (const target of PLATFORM_TARGETS) {
26
+ run('npm', ['pack'], target.packageDir);
27
+ }
28
+
29
+ run('npm', ['pack']);
30
+
31
+ console.log(`Packed ${pkg.name}@${pkg.version} and ${PLATFORM_TARGETS.length} platform packages.`);
@@ -0,0 +1,74 @@
1
+ const path = require('node:path');
2
+
3
+ const ROOT = path.resolve(__dirname, '..', '..');
4
+ const DIST_DIR = path.join(ROOT, 'dist');
5
+ const PACKAGES_DIR = path.join(ROOT, 'npm');
6
+ const NPM_SCOPE = '@ricequant2026';
7
+
8
+ const PLATFORM_TARGETS = [
9
+ {
10
+ key: 'linux-x64',
11
+ goos: 'linux',
12
+ goarch: 'amd64',
13
+ os: 'linux',
14
+ cpu: 'x64',
15
+ packageName: `${NPM_SCOPE}/rqdata-cli-linux-x64`,
16
+ packageDir: path.join(PACKAGES_DIR, 'rqdata-cli-linux-x64'),
17
+ output: 'rqdata-linux-amd64',
18
+ binName: 'rqdata'
19
+ },
20
+ {
21
+ key: 'darwin-x64',
22
+ goos: 'darwin',
23
+ goarch: 'amd64',
24
+ os: 'darwin',
25
+ cpu: 'x64',
26
+ packageName: `${NPM_SCOPE}/rqdata-cli-darwin-x64`,
27
+ packageDir: path.join(PACKAGES_DIR, 'rqdata-cli-darwin-x64'),
28
+ output: 'rqdata-macos-amd64',
29
+ binName: 'rqdata'
30
+ },
31
+ {
32
+ key: 'darwin-arm64',
33
+ goos: 'darwin',
34
+ goarch: 'arm64',
35
+ os: 'darwin',
36
+ cpu: 'arm64',
37
+ packageName: `${NPM_SCOPE}/rqdata-cli-darwin-arm64`,
38
+ packageDir: path.join(PACKAGES_DIR, 'rqdata-cli-darwin-arm64'),
39
+ output: 'rqdata-macos-arm64',
40
+ binName: 'rqdata'
41
+ },
42
+ {
43
+ key: 'win32-x64',
44
+ goos: 'windows',
45
+ goarch: 'amd64',
46
+ os: 'win32',
47
+ cpu: 'x64',
48
+ packageName: `${NPM_SCOPE}/rqdata-cli-win32-x64`,
49
+ packageDir: path.join(PACKAGES_DIR, 'rqdata-cli-win32-x64'),
50
+ output: 'rqdata-windows-amd64.exe',
51
+ binName: 'rqdata.exe'
52
+ }
53
+ ];
54
+
55
+ function currentPlatformKey() {
56
+ return `${process.platform}-${process.arch}`;
57
+ }
58
+
59
+ function findCurrentTarget() {
60
+ return PLATFORM_TARGETS.find((target) => target.key === currentPlatformKey()) || null;
61
+ }
62
+
63
+ function findTargetByKey(key) {
64
+ return PLATFORM_TARGETS.find((target) => target.key === key) || null;
65
+ }
66
+
67
+ module.exports = {
68
+ DIST_DIR,
69
+ NPM_SCOPE,
70
+ PACKAGES_DIR,
71
+ PLATFORM_TARGETS,
72
+ findTargetByKey,
73
+ findCurrentTarget
74
+ };
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('node:path');
4
+ const { spawnSync } = require('node:child_process');
5
+ const { PLATFORM_TARGETS } = require('./platforms');
6
+
7
+ const ROOT = path.resolve(__dirname, '..', '..');
8
+ const NPM_TAG = process.env.NPM_TAG || 'latest';
9
+ const NPM_DRY_RUN = process.env.NPM_DRY_RUN === '1';
10
+
11
+ function run(command, args, cwd = ROOT) {
12
+ const result = spawnSync(command, args, {
13
+ cwd,
14
+ stdio: 'inherit',
15
+ env: process.env
16
+ });
17
+
18
+ if (result.status !== 0) {
19
+ process.exit(result.status === null ? 1 : result.status);
20
+ }
21
+ }
22
+
23
+ function publishArgs() {
24
+ const args = ['publish', '--access', 'public', '--tag', NPM_TAG];
25
+
26
+ if (NPM_DRY_RUN) {
27
+ args.push('--dry-run');
28
+ }
29
+
30
+ return args;
31
+ }
32
+
33
+ run('node', ['scripts/npm/build-packages.js']);
34
+
35
+ for (const target of PLATFORM_TARGETS) {
36
+ run('npm', publishArgs(), target.packageDir);
37
+ }
38
+
39
+ run('npm', publishArgs());