daxiapi-cli 1.1.0 → 2.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # daxiapi-cli
2
2
 
3
- 大虾皮(daxiapi.com)金融数据API命令行工具。需要注册 daxiapi.com 网站,并且获取API Token之后才能使用。
3
+ 大虾皮金融数据API命令行工具。需要注册 daxiapi.com 网站,并且获取API Token之后才能使用。
4
4
 
5
5
  ## 安装
6
6
 
@@ -45,119 +45,124 @@ daxiapi config delete token
45
45
  ### 市场数据
46
46
 
47
47
  ```bash
48
- # 市场概览(默认)
48
+ # 市场概览(主流指数)
49
49
  daxiapi market
50
50
 
51
51
  # 市场温度
52
- daxiapi market -d
52
+ daxiapi market temp
53
53
 
54
- # 大小盘风格
55
- daxiapi market -s
54
+ # 市场风格
55
+ daxiapi market style
56
56
 
57
- # 指数估值
58
- daxiapi market -v
59
-
60
- # 收盘新闻
61
- daxiapi market -n
62
-
63
- # 涨跌停股票池
64
- daxiapi market -z
65
- ```
66
-
67
- ### 指数K线
68
-
69
- ```bash
70
- # 获取上证指数K线
71
- daxiapi index
57
+ # 市场估值
58
+ daxiapi market value
72
59
  ```
73
60
 
74
61
  ### 板块数据
75
62
 
76
63
  ```bash
77
- # 板块热力图
64
+ # 板块列表
78
65
  daxiapi sector
79
66
 
80
- # 指定排序字段和天数
81
- daxiapi sector -o zdf -l 10
67
+ # 指定排序和数量
68
+ daxiapi sector --order zdf --limit 10
69
+
70
+ # 行业板块数据
71
+ daxiapi sector bk
82
72
 
83
- # 获取板块内个股排名
84
- daxiapi sector -c BK0477 -o cs
73
+ # 板块内个股排名
74
+ daxiapi sector stocks --code BK0477
85
75
 
86
- # 获取概念内个股
87
- daxiapi sector -g GN1234
76
+ # 热门股票
77
+ daxiapi sector top
78
+
79
+ # 热门概念
80
+ daxiapi sector gn
88
81
  ```
89
82
 
90
- ### 个股查询
83
+ ### 股票数据
91
84
 
92
85
  ```bash
86
+ # 搜索股票或板块
87
+ daxiapi search 平安
88
+ daxiapi search 锂电 --type bk
89
+
93
90
  # 查询单个股票
94
91
  daxiapi stock 000001
95
92
 
96
93
  # 查询多个股票
97
94
  daxiapi stock 000001 600031 300750
98
95
 
99
- # JSON格式输出
100
- daxiapi stock 000001 --json
96
+ # 概念股查询
97
+ daxiapi stock gn GN1234
98
+ ```
99
+
100
+ ### K线数据
101
+
102
+ ```bash
103
+ # 获取K线数据
104
+ daxiapi kline 000001
101
105
  ```
102
106
 
103
- ### 搜索
107
+ ### 涨跌停
104
108
 
105
109
  ```bash
106
- # 搜索股票
107
- daxiapi search 三一重工
110
+ # 涨停池
111
+ daxiapi zdt
108
112
 
109
- # 搜索行业
110
- daxiapi search 机械 -t hy
113
+ # 跌停池
114
+ daxiapi zdt --type dt
115
+ ```
116
+
117
+ ### 工具
118
+
119
+ ```bash
120
+ # 代码转换
121
+ daxiapi secid 000001
111
122
  ```
112
123
 
113
124
  > 💡 提示:`daxiapi` 命令也可以使用简写 `dxp`
114
125
 
115
- ## 输出示例
126
+ ## 全局选项
116
127
 
117
- ### 市场概览
128
+ ```bash
129
+ # 查看帮助
130
+ daxiapi --help
131
+ daxiapi market --help
118
132
 
119
- ```
120
- 📈 市场概览
121
-
122
- 主要指数:
123
- ┌─────────┬────────┬───────────┬───────┬─────────┬─────────┐
124
- │ (index) │ 名称 │ 涨跌幅 │ CS │ 5日 │ 20日 │
125
- ├─────────┼────────┼───────────┼───────┼─────────┼─────────┤
126
- │ 0 │ '上证' │ '0.50%' │ 5.23 │ '2.10%' │ '3.50%' │
127
- │ 1 │ '深证' │ '0.80%' │ 6.45 │ '2.50%' │ '4.20%' │
128
- │ 2 │ '创业' │ '1.20%' │ 8.12 │ '3.00%' │ '5.10%' │
129
- └─────────┴────────┴───────────┴───────┴─────────┴─────────┘
133
+ # 查看版本
134
+ daxiapi --version
130
135
  ```
131
136
 
132
- ### 个股详情
137
+ ## 错误处理
138
+
139
+ CLI 工具提供详细的错误提示和解决建议:
140
+
141
+ ### 认证错误 (401)
133
142
 
134
143
  ```
135
- 📊 个股详情
144
+ 错误: API Token 无效或已过期
145
+
146
+ 解决方法:
147
+ 1. 检查 Token 是否正确配置:
148
+ daxiapi config set token YOUR_TOKEN
136
149
 
137
- 三一重工 (600031)
138
- ────────────────────────────────────────
139
- 价格: 18.50 涨跌幅: 2.50%
150
+ 2. 或设置环境变量:
151
+ export DAXIAPI_TOKEN=YOUR_TOKEN
140
152
 
141
- 动量指标:
142
- CS(短期): 8.25 SM(中期): 5.30 ML(长期): 3.20
143
- RPS: 85 SCTR: 72
153
+ 3. Token 可在 daxiapi.com 用户中心获取
154
+ ```
155
+
156
+ ### 限流错误 (429)
144
157
 
145
- 形态标签: Good, LPS
146
- 技术形态: VCP, SOS
147
158
  ```
159
+ ❌ 错误: 请求频率超限
148
160
 
149
- ## 核心指标说明
150
-
151
- | 指标 | 说明 |
152
- |------|------|
153
- | CS | 短期动量,股价与20日均线乖离率。>0在均线上方,>30可能反转 |
154
- | SM | 中期动量,短期与中期均线乖离率。>0多头排列 |
155
- | ML | 长期动量,中期与长期均线乖离率 |
156
- | RPS | 欧奈尔相对强度,>80为强势股 |
157
- | SCTR | 技术排名百分比,如60代表强于市场60%股票 |
158
- | VCP | 马克米勒维尼波动收缩模式 |
159
- | SOS | Wyckoff强势走势行为 |
160
- | LPS | Wyckoff最后支撑点 |
161
+ 解决方法:
162
+ 1. 请稍后重试
163
+ 2. 检查您的请求频率是否过高
164
+ 3. 升级账户获取更高配额
165
+ ```
161
166
 
162
167
  ## 限流规则
163
168
 
package/bin/index.js CHANGED
@@ -1,213 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { program } = require('commander');
4
- const chalk = require('chalk');
5
- const config = require('../lib/config');
6
- const api = require('../lib/api');
7
- const output = require('../lib/output');
8
-
9
- // 显示欢迎信息
10
- function showWelcome() {
11
- console.log(chalk.cyan.bold('\n📊 大虾皮 CLI - A股量化数据工具\n'));
12
- }
13
-
14
- // 检查Token配置
15
- function checkToken() {
16
- const token = config.getToken();
17
- if (!token) {
18
- console.log(chalk.yellow('⚠️ 未配置 API Token'));
19
- console.log(chalk.gray(' 请先运行: daxiapi config set token YOUR_TOKEN'));
20
- console.log(chalk.gray(' 或设置环境变量: DAXIAPI_TOKEN=YOUR_TOKEN\n'));
21
- process.exit(1);
22
- }
23
- return token;
24
- }
3
+ const {program} = require('commander');
4
+ const package = require('../package.json');
25
5
 
26
6
  program
27
7
  .name('daxiapi')
28
- .version('1.0.0')
29
- .description('大虾皮(daxiapi.com)金融数据API命令行工具');
30
-
31
- // ==================== 配置命令 ====================
32
- program
33
- .command('config')
34
- .description('配置管理')
35
- .argument('<action>', 'set/get/delete')
36
- .argument('[key]', '配置项名称')
37
- .argument('[value]', '配置项值')
38
- .action((action, key, value) => {
39
- switch (action) {
40
- case 'set':
41
- if (!key || !value) {
42
- console.log(chalk.red('用法: daxiapi config set <key> <value>'));
43
- console.log(chalk.gray('示例: daxiapi config set token abc123...'));
44
- return;
45
- }
46
- config.set(key, value);
47
- console.log(chalk.green(`✓ 已设置 ${key}`));
48
- break;
49
- case 'get':
50
- if (!key) {
51
- const all = config.getAll();
52
- console.log(JSON.stringify(all, null, 2));
53
- } else {
54
- console.log(config.get(key) || '');
55
- }
56
- break;
57
- case 'delete':
58
- config.delete(key);
59
- console.log(chalk.green(`✓ 已删除 ${key}`));
60
- break;
61
- default:
62
- console.log(chalk.red('未知操作:', action));
63
- }
64
- });
65
-
66
- // ==================== 市场数据命令 ====================
67
- program
68
- .command('market')
69
- .description('市场数据')
70
- .option('-d, --degree', '获取市场温度')
71
- .option('-s, --style', '获取大小盘风格')
72
- .option('-v, --value', '获取指数估值')
73
- .option('-n, --news', '获取收盘新闻')
74
- .option('-z, --zdt', '获取涨跌停股票池')
75
- .action(async (options) => {
76
- showWelcome();
77
- const token = checkToken();
78
-
79
- try {
80
- if (options.degree) {
81
- const data = await api.getMarketDegree(token);
82
- output.text(data);
83
- } else if (options.style) {
84
- const data = await api.getMarketStyle(token);
85
- output.table(data);
86
- } else if (options.value) {
87
- const data = await api.getMarketValueData(token);
88
- output.valueTable(data);
89
- } else if (options.news) {
90
- const data = await api.getMarketNews(token);
91
- output.newsList(data);
92
- } else if (options.zdt) {
93
- const data = await api.getZdtPool(token);
94
- output.text(data);
95
- } else {
96
- // 默认获取市场概览
97
- const data = await api.getMarketData(token);
98
- output.marketOverview(data);
99
- }
100
- } catch (err) {
101
- output.error(err);
102
- }
103
- });
104
-
105
- // ==================== 指数K线命令 ====================
106
- program
107
- .command('index')
108
- .description('获取上证指数K线数据')
109
- .action(async () => {
110
- showWelcome();
111
- const token = checkToken();
112
-
113
- try {
114
- const data = await api.getIndexK(token);
115
- output.klines(data);
116
- } catch (err) {
117
- output.error(err);
118
- }
119
- });
120
-
121
- // ==================== 板块数据命令 ====================
122
- program
123
- .command('sector')
124
- .description('板块数据')
125
- .option('-c, --code <code>', '板块代码,获取板块内个股')
126
- .option('-o, --order <field>', '排序字段', 'cs')
127
- .option('-l, --limit <days>', '天数', '5')
128
- .option('-g, --gn <gnId>', '概念代码,获取概念内个股')
129
- .action(async (options) => {
130
- showWelcome();
131
- const token = checkToken();
132
-
133
- try {
134
- if (options.code) {
135
- const data = await api.getSectorRankStock(token, options.code, options.order);
136
- output.stockList(data);
137
- } else if (options.gn) {
138
- const data = await api.getGainianStock(token, options.gn);
139
- output.stockList(data);
140
- } else {
141
- const data = await api.getSectorData(token, options.order, parseInt(options.limit));
142
- output.sectorHeatmap(data);
143
- }
144
- } catch (err) {
145
- output.error(err);
146
- }
147
- });
148
-
149
- // ==================== 个股查询命令 ====================
150
- program
151
- .command('stock <codes...>')
152
- .description('获取个股数据,支持多个股票代码')
153
- .option('-j, --json', '输出JSON格式')
154
- .action(async (codes, options) => {
155
- showWelcome();
156
- const token = checkToken();
157
-
158
- try {
159
- const data = await api.getStockData(token, codes.join(','));
160
- if (options.json) {
161
- console.log(JSON.stringify(data, null, 2));
162
- } else {
163
- output.stockDetail(data);
164
- }
165
- } catch (err) {
166
- output.error(err);
167
- }
168
- });
169
-
170
- // ==================== 搜索命令 ====================
171
- program
172
- .command('search <keyword>')
173
- .description('搜索股票或行业')
174
- .option('-t, --type <type>', '类型: stock/hy', 'stock')
175
- .action(async (keyword, options) => {
176
- showWelcome();
177
- const token = checkToken();
178
-
179
- try {
180
- const data = await api.queryStock(token, keyword, options.type);
181
- output.searchResult(data);
182
- } catch (err) {
183
- output.error(err);
184
- }
185
- });
186
-
187
- // ==================== K线数据命令 ====================
188
- program
189
- .command('kline <code>')
190
- .description('获取个股K线数据')
191
- .option('-l, --limit <days>', '数据条数', '300')
192
- .option('-t, --type <type>', 'K线类型: day/week/month', 'day')
193
- .option('-j, --json', '输出JSON格式')
194
- .option('-s, --simple', '简单输出格式')
195
- .action(async (code, options) => {
196
- showWelcome();
197
- // K线数据不需要token,使用免费数据源
198
-
199
- try {
200
- const data = await api.getKline(code, parseInt(options.limit), options.type);
201
- if (options.json) {
202
- console.log(JSON.stringify(data, null, 2));
203
- } else if (options.simple) {
204
- output.klineSimple(data, 10);
205
- } else {
206
- output.klineData(data, 20);
207
- }
208
- } catch (err) {
209
- output.error(err);
210
- }
211
- });
212
-
213
- program.parse();
8
+ .alias('dxp')
9
+ .version(package.version)
10
+ .description('大虾皮金融数据API命令行工具');
11
+
12
+ require('../commands/config')(program);
13
+ require('../commands/market')(program);
14
+ require('../commands/sector')(program);
15
+ require('../commands/stock')(program);
16
+ require('../commands/kline')(program);
17
+ require('../commands/zdt')(program);
18
+ require('../commands/secid')(program);
19
+ require('../commands/search')(program);
20
+
21
+ program.parse(process.argv);
@@ -0,0 +1,67 @@
1
+ const config = require('../lib/config');
2
+ const { handleError, createParameterError } = require('../lib/error');
3
+
4
+ module.exports = function(program) {
5
+ const configCmd = program.command('config');
6
+
7
+ configCmd
8
+ .command('set <key> <value>')
9
+ .description('设置配置项')
10
+ .action((key, value) => {
11
+ try {
12
+ if (!key || !value) {
13
+ throw createParameterError(
14
+ '参数无效',
15
+ [
16
+ "参数 'key' 不能为空",
17
+ "参数 'value' 不能为空"
18
+ ],
19
+ [
20
+ 'daxiapi config set token YOUR_TOKEN',
21
+ 'daxiapi config set baseUrl https://daxiapi.com'
22
+ ]
23
+ );
24
+ }
25
+
26
+ config.set(key, value);
27
+ console.log(`✓ ${key} 已设置`);
28
+ } catch (error) {
29
+ handleError(error);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ configCmd
35
+ .command('get')
36
+ .description('查看所有配置')
37
+ .action(() => {
38
+ try {
39
+ const allConfig = config.getAll();
40
+ console.log(JSON.stringify(allConfig, null, 2));
41
+ } catch (error) {
42
+ handleError(error);
43
+ process.exit(1);
44
+ }
45
+ });
46
+
47
+ configCmd
48
+ .command('delete <key>')
49
+ .description('删除配置项')
50
+ .action((key) => {
51
+ try {
52
+ if (!key) {
53
+ throw createParameterError(
54
+ '参数无效',
55
+ ["参数 'key' 不能为空"],
56
+ ['daxiapi config delete token']
57
+ );
58
+ }
59
+
60
+ config.delete(key);
61
+ console.log(`✓ ${key} 已删除`);
62
+ } catch (error) {
63
+ handleError(error);
64
+ process.exit(1);
65
+ }
66
+ });
67
+ };
@@ -0,0 +1,34 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const {handleError, createParameterError} = require('../lib/error');
4
+ const {output} = require('../lib/output');
5
+
6
+ module.exports = function(program) {
7
+ program
8
+ .command('kline <code>')
9
+ .description('K线数据')
10
+ .action(async (code) => {
11
+ try {
12
+ const token = config.getToken();
13
+ if (!token) {
14
+ const error = new Error('未配置 API Token');
15
+ error.response = {status: 401};
16
+ throw error;
17
+ }
18
+
19
+ if (!code) {
20
+ throw createParameterError(
21
+ '参数无效',
22
+ ['参数 \'code\' 不能为空'],
23
+ ['daxiapi kline 000001']
24
+ );
25
+ }
26
+
27
+ const data = await api.getKline(token, code);
28
+ output(data);
29
+ } catch (error) {
30
+ handleError(error);
31
+ process.exit(1);
32
+ }
33
+ });
34
+ };
@@ -0,0 +1,87 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const { handleError } = require('../lib/error');
4
+ const { output } = require('../lib/output');
5
+
6
+ module.exports = function(program) {
7
+ const marketCmd = program.command('market');
8
+
9
+ marketCmd
10
+ .description('市场数据')
11
+ .action(async () => {
12
+ try {
13
+ const token = config.getToken();
14
+ if (!token) {
15
+ const error = new Error('未配置 API Token');
16
+ error.response = {status: 401};
17
+ throw error;
18
+ }
19
+
20
+ const data = await api.getMarketData(token);
21
+ output(data);
22
+ } catch (error) {
23
+ handleError(error);
24
+ process.exit(1);
25
+ }
26
+ });
27
+
28
+ marketCmd
29
+ .command('temp')
30
+ .description('市场温度')
31
+ .action(async () => {
32
+ try {
33
+ const token = config.getToken();
34
+ if (!token) {
35
+ const error = new Error('未配置 API Token');
36
+ error.response = {status: 401};
37
+ throw error;
38
+ }
39
+
40
+ const data = await api.getMarketTemp(token);
41
+ output(data);
42
+ } catch (error) {
43
+ handleError(error);
44
+ process.exit(1);
45
+ }
46
+ });
47
+
48
+ marketCmd
49
+ .command('style')
50
+ .description('市场风格')
51
+ .action(async () => {
52
+ try {
53
+ const token = config.getToken();
54
+ if (!token) {
55
+ const error = new Error('未配置 API Token');
56
+ error.response = {status: 401};
57
+ throw error;
58
+ }
59
+
60
+ const data = await api.getMarketStyle(token);
61
+ output(data);
62
+ } catch (error) {
63
+ handleError(error);
64
+ process.exit(1);
65
+ }
66
+ });
67
+
68
+ marketCmd
69
+ .command('value')
70
+ .description('市场估值')
71
+ .action(async () => {
72
+ try {
73
+ const token = config.getToken();
74
+ if (!token) {
75
+ const error = new Error('未配置 API Token');
76
+ error.response = {status: 401};
77
+ throw error;
78
+ }
79
+
80
+ const data = await api.getMarketValueData(token);
81
+ output(data);
82
+ } catch (error) {
83
+ handleError(error);
84
+ process.exit(1);
85
+ }
86
+ });
87
+ };
@@ -0,0 +1,35 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const {handleError, createParameterError} = require('../lib/error');
4
+ const {output} = require('../lib/output');
5
+
6
+ module.exports = function (program) {
7
+ program
8
+ .command('search <keyword>')
9
+ .description('搜索股票或板块代码')
10
+ .option('-t, --type <type>', '搜索类型:stock(股票)或 bk(板块)', 'stock')
11
+ .action(async (keyword, options) => {
12
+ try {
13
+ const token = config.getToken();
14
+ if (!token) {
15
+ const error = new Error('未配置 API Token');
16
+ error.response = {status: 401};
17
+ throw error;
18
+ }
19
+
20
+ if (!keyword) {
21
+ throw createParameterError(
22
+ '参数无效',
23
+ ["参数 'keyword' 不能为空"],
24
+ ['daxiapi search 平安', 'daxiapi search 锂电 --type bk']
25
+ );
26
+ }
27
+
28
+ const data = await api.queryStockData(token, keyword, options.type);
29
+ output(data);
30
+ } catch (error) {
31
+ handleError(error);
32
+ process.exit(1);
33
+ }
34
+ });
35
+ };
@@ -0,0 +1,34 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const {handleError, createParameterError} = require('../lib/error');
4
+ const {output} = require('../lib/output');
5
+
6
+ module.exports = function(program) {
7
+ program
8
+ .command('secid <code>')
9
+ .description('代码转换')
10
+ .action(async (code) => {
11
+ try {
12
+ const token = config.getToken();
13
+ if (!token) {
14
+ const error = new Error('未配置 API Token');
15
+ error.response = {status: 401};
16
+ throw error;
17
+ }
18
+
19
+ if (!code) {
20
+ throw createParameterError(
21
+ '参数无效',
22
+ ["参数 'code' 不能为空"],
23
+ ['daxiapi secid 000001']
24
+ );
25
+ }
26
+
27
+ const data = await api.getSecId(token, code);
28
+ output(data);
29
+ } catch (error) {
30
+ handleError(error);
31
+ process.exit(1);
32
+ }
33
+ });
34
+ };