daxiapi-cli 2.2.0 → 2.3.1
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 +56 -0
- package/bin/index.js +3 -0
- package/commands/config.js +7 -17
- package/commands/dividend.js +3 -1
- package/commands/hotrank.js +63 -0
- package/commands/market.js +5 -3
- package/commands/report.js +32 -0
- package/commands/sector.js +5 -1
- package/commands/stock.js +4 -2
- package/commands/turnover.js +18 -0
- package/lib/api.js +178 -187
- package/lib/caibao.js +69 -0
- package/lib/dividendUtils.js +216 -0
- package/lib/iconv.js +4 -0
- package/lib/output.js +4 -2
- package/lib/request.js +44 -0
- package/lib/thsUtils.js +148 -0
- package/lib/utils.js +58 -2
- package/package.json +39 -35
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
const DIVIDEND_SCORE_CONSTANTS = {
|
|
2
|
+
ROLLING_WINDOW: 440,
|
|
3
|
+
PERCENTILE_LOW: 5,
|
|
4
|
+
PERCENTILE_HIGH: 95,
|
|
5
|
+
SCORE_MA_PERIOD: 5,
|
|
6
|
+
EMA_PERIOD: 20,
|
|
7
|
+
MA_PERIOD: 80,
|
|
8
|
+
RSI_PERIOD: 20,
|
|
9
|
+
MIN_VALID_VALUES: 10,
|
|
10
|
+
MIN_SCORE: 0,
|
|
11
|
+
MAX_SCORE: 100,
|
|
12
|
+
CS_WEIGHT: 0.35,
|
|
13
|
+
MA80_WEIGHT: 0.35,
|
|
14
|
+
RSI_WEIGHT: 0.3
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function calculateEMA(period, data) {
|
|
18
|
+
const closes = data.map(d => d.close);
|
|
19
|
+
const cs = [];
|
|
20
|
+
let ema = closes[0];
|
|
21
|
+
const multiplier = 2 / (period + 1);
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < closes.length; i++) {
|
|
24
|
+
if (i === 0) {
|
|
25
|
+
ema = closes[i];
|
|
26
|
+
} else {
|
|
27
|
+
ema = (closes[i] - ema) * multiplier + ema;
|
|
28
|
+
}
|
|
29
|
+
cs.push(((closes[i] - ema) / ema) * 100);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {cs};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function calculateMA(period, data) {
|
|
36
|
+
const closes = data.map(d => d.close);
|
|
37
|
+
const ma = [];
|
|
38
|
+
const maBias = [];
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < closes.length; i++) {
|
|
41
|
+
if (i < period - 1) {
|
|
42
|
+
ma.push('-');
|
|
43
|
+
maBias.push('-');
|
|
44
|
+
} else {
|
|
45
|
+
let sum = 0;
|
|
46
|
+
for (let j = 0; j < period; j++) {
|
|
47
|
+
sum += closes[i - j];
|
|
48
|
+
}
|
|
49
|
+
const avg = sum / period;
|
|
50
|
+
ma.push(avg);
|
|
51
|
+
maBias.push(((closes[i] - avg) / avg) * 100);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [ma, maBias];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function calculateRSI(closes, period = 20) {
|
|
59
|
+
const rsiValues = [];
|
|
60
|
+
let gains = 0;
|
|
61
|
+
let losses = 0;
|
|
62
|
+
|
|
63
|
+
for (let i = 0; i < closes.length; i++) {
|
|
64
|
+
if (i < period) {
|
|
65
|
+
rsiValues.push(null);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const change = closes[i] - closes[i - 1];
|
|
70
|
+
if (i === period) {
|
|
71
|
+
let sumGain = 0;
|
|
72
|
+
let sumLoss = 0;
|
|
73
|
+
for (let j = 1; j <= period; j++) {
|
|
74
|
+
const c = closes[j] - closes[j - 1];
|
|
75
|
+
if (c > 0) {
|
|
76
|
+
sumGain += c;
|
|
77
|
+
} else {
|
|
78
|
+
sumLoss += Math.abs(c);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
gains = sumGain / period;
|
|
82
|
+
losses = sumLoss / period;
|
|
83
|
+
} else {
|
|
84
|
+
const currentGain = change > 0 ? change : 0;
|
|
85
|
+
const currentLoss = change < 0 ? Math.abs(change) : 0;
|
|
86
|
+
gains = (gains * (period - 1) + currentGain) / period;
|
|
87
|
+
losses = (losses * (period - 1) + currentLoss) / period;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (gains + losses === 0) {
|
|
91
|
+
rsiValues.push(50);
|
|
92
|
+
} else {
|
|
93
|
+
const rs = gains / losses;
|
|
94
|
+
rsiValues.push(parseFloat((100 - 100 / (1 + rs)).toFixed(2)));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return rsiValues;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function percentile(p, arr) {
|
|
102
|
+
if (!arr.length) {
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
const sorted = [...arr].sort((a, b) => a - b);
|
|
106
|
+
const index = Math.ceil((p / 100) * sorted.length) - 1;
|
|
107
|
+
return sorted[Math.max(0, index)];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function calculateRollingScore(value, historyValues, lowPercentile, highPercentile) {
|
|
111
|
+
const validValues = historyValues.filter(v => v !== null && !isNaN(v));
|
|
112
|
+
if (validValues.length < DIVIDEND_SCORE_CONSTANTS.MIN_VALID_VALUES || value === null) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const low = percentile(lowPercentile, validValues);
|
|
117
|
+
const high = percentile(highPercentile, validValues);
|
|
118
|
+
|
|
119
|
+
if (low === high) {
|
|
120
|
+
return 50;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let score = ((value - low) / (high - low)) * 100;
|
|
124
|
+
score = Math.max(DIVIDEND_SCORE_CONSTANTS.MIN_SCORE, Math.min(DIVIDEND_SCORE_CONSTANTS.MAX_SCORE, score));
|
|
125
|
+
return parseFloat(score.toFixed(2));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function calculateScores(data) {
|
|
129
|
+
const dataCopy = data.map(item => ({...item}));
|
|
130
|
+
|
|
131
|
+
const closes = dataCopy.map(d => d.close);
|
|
132
|
+
const {cs} = calculateEMA(DIVIDEND_SCORE_CONSTANTS.EMA_PERIOD, dataCopy);
|
|
133
|
+
const [_, ma80Bias] = calculateMA(DIVIDEND_SCORE_CONSTANTS.MA_PERIOD, dataCopy);
|
|
134
|
+
const rsi = calculateRSI(closes, DIVIDEND_SCORE_CONSTANTS.RSI_PERIOD);
|
|
135
|
+
for (let i = 0; i < dataCopy.length; i++) {
|
|
136
|
+
dataCopy[i].cs = cs[i] === '-' ? null : parseFloat(cs[i]);
|
|
137
|
+
dataCopy[i].ma80Bias = ma80Bias[i] === '-' ? null : parseFloat(ma80Bias[i]);
|
|
138
|
+
dataCopy[i].rsi = rsi[i];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const csValues = dataCopy.map(d => d.cs);
|
|
142
|
+
const ma80BiasValues = dataCopy.map(d => d.ma80Bias);
|
|
143
|
+
|
|
144
|
+
for (let i = 0; i < dataCopy.length; i++) {
|
|
145
|
+
const current = dataCopy[i];
|
|
146
|
+
if (current.cs === null || current.ma80Bias === null || current.rsi === null) {
|
|
147
|
+
current.csScore = null;
|
|
148
|
+
current.ma80Score = null;
|
|
149
|
+
current.rsiScore = null;
|
|
150
|
+
current.totalScore = null;
|
|
151
|
+
current.scoreMA = null;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const startIdx = Math.max(0, i - DIVIDEND_SCORE_CONSTANTS.ROLLING_WINDOW + 1);
|
|
156
|
+
const csHistory = csValues.slice(startIdx, i + 1);
|
|
157
|
+
const ma80History = ma80BiasValues.slice(startIdx, i + 1);
|
|
158
|
+
|
|
159
|
+
current.csScore = calculateRollingScore(
|
|
160
|
+
current.cs,
|
|
161
|
+
csHistory,
|
|
162
|
+
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_LOW,
|
|
163
|
+
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_HIGH
|
|
164
|
+
);
|
|
165
|
+
current.ma80Score = calculateRollingScore(
|
|
166
|
+
current.ma80Bias,
|
|
167
|
+
ma80History,
|
|
168
|
+
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_LOW,
|
|
169
|
+
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_HIGH
|
|
170
|
+
);
|
|
171
|
+
current.rsiScore = current.rsi;
|
|
172
|
+
|
|
173
|
+
if (current.csScore !== null && current.ma80Score !== null && current.rsiScore !== null) {
|
|
174
|
+
current.totalScore = parseFloat(
|
|
175
|
+
(
|
|
176
|
+
current.csScore * DIVIDEND_SCORE_CONSTANTS.CS_WEIGHT +
|
|
177
|
+
current.ma80Score * DIVIDEND_SCORE_CONSTANTS.MA80_WEIGHT +
|
|
178
|
+
current.rsiScore * DIVIDEND_SCORE_CONSTANTS.RSI_WEIGHT
|
|
179
|
+
).toFixed(2)
|
|
180
|
+
);
|
|
181
|
+
} else {
|
|
182
|
+
current.totalScore = null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (let i = 0; i < dataCopy.length; i++) {
|
|
187
|
+
const current = dataCopy[i];
|
|
188
|
+
if (current.totalScore === null) {
|
|
189
|
+
current.scoreMA = null;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const scoreHistory = dataCopy
|
|
194
|
+
.slice(Math.max(0, i - DIVIDEND_SCORE_CONSTANTS.SCORE_MA_PERIOD + 1), i + 1)
|
|
195
|
+
.filter(d => d.totalScore !== null)
|
|
196
|
+
.map(d => d.totalScore);
|
|
197
|
+
|
|
198
|
+
if (scoreHistory.length >= DIVIDEND_SCORE_CONSTANTS.SCORE_MA_PERIOD) {
|
|
199
|
+
current.scoreMA = parseFloat((scoreHistory.reduce((a, b) => a + b, 0) / scoreHistory.length).toFixed(2));
|
|
200
|
+
} else {
|
|
201
|
+
current.scoreMA = current.totalScore;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return dataCopy;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports = {
|
|
209
|
+
DIVIDEND_SCORE_CONSTANTS,
|
|
210
|
+
calculateEMA,
|
|
211
|
+
calculateMA,
|
|
212
|
+
calculateRSI,
|
|
213
|
+
percentile,
|
|
214
|
+
calculateRollingScore,
|
|
215
|
+
calculateScores
|
|
216
|
+
};
|
package/lib/iconv.js
ADDED
package/lib/output.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const {encode} = require('@toon-format/toon');
|
|
1
2
|
function output(data) {
|
|
2
3
|
// 检查是否是dividend score结果
|
|
3
4
|
if (data && data.scores && Array.isArray(data.scores)) {
|
|
@@ -5,11 +6,11 @@ function output(data) {
|
|
|
5
6
|
console.log('');
|
|
6
7
|
console.log('```toon');
|
|
7
8
|
console.log('[60]{"日期","分数","cs值","rsi值"}:');
|
|
8
|
-
|
|
9
|
+
|
|
9
10
|
data.scores.forEach(item => {
|
|
10
11
|
console.log(` ${item.date},${item.score || '-'},${item.cs || '-'},${item.rsi || '-'}`);
|
|
11
12
|
});
|
|
12
|
-
|
|
13
|
+
|
|
13
14
|
console.log('```');
|
|
14
15
|
} else {
|
|
15
16
|
console.log(data);
|
|
@@ -17,5 +18,6 @@ function output(data) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
module.exports = {
|
|
21
|
+
encode,
|
|
20
22
|
output
|
|
21
23
|
};
|
package/lib/request.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
const API_DOMAINS = {
|
|
4
|
+
JQKA: 'https://dq.10jqka.com.cn'
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const API_PATHS = {
|
|
8
|
+
HOT_LIST: '/fuyao/hot_list_data/out/hot_list/v1',
|
|
9
|
+
MARKET_ANALYSIS: '/fuyao/market_analysis/data/out/v1'
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
async function get(path, params = {}, options = {}) {
|
|
13
|
+
const domain = options.domain || 'JQKA';
|
|
14
|
+
const baseUrl = API_DOMAINS[domain] || API_DOMAINS.JQKA;
|
|
15
|
+
const url = `${baseUrl}${path}`;
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const response = await axios.get(url, {
|
|
19
|
+
params,
|
|
20
|
+
timeout: 30000,
|
|
21
|
+
headers: {
|
|
22
|
+
'User-Agent':
|
|
23
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
24
|
+
Referer: 'https://www.10jqka.com.cn/',
|
|
25
|
+
Accept: 'application/json, text/plain, */*'
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return response.data;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error.response) {
|
|
32
|
+
const err = new Error(`HTTP ${error.response.status}: ${error.response.statusText}`);
|
|
33
|
+
err.response = error.response;
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
get,
|
|
42
|
+
API_DOMAINS,
|
|
43
|
+
API_PATHS
|
|
44
|
+
};
|
package/lib/thsUtils.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
class S {
|
|
2
|
+
constructor(startTime, base_fileds = [4, 4, 4, 4, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 2, 1]) {
|
|
3
|
+
let endTime;
|
|
4
|
+
if (startTime && startTime > 10000000) {
|
|
5
|
+
endTime = startTime + 3600 * 3;
|
|
6
|
+
} else {
|
|
7
|
+
const now = new Date();
|
|
8
|
+
const date = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
|
|
9
|
+
const s = Date.parse(`${date} ${now.getHours()}:03:23`) / 1000;
|
|
10
|
+
startTime = parseInt(s, 10);
|
|
11
|
+
endTime = parseInt(s + 3600 * 3, 10);
|
|
12
|
+
}
|
|
13
|
+
const data = {
|
|
14
|
+
0: 33554944,
|
|
15
|
+
1: startTime,
|
|
16
|
+
2: endTime,
|
|
17
|
+
3: 3086956040,
|
|
18
|
+
4: 7,
|
|
19
|
+
5: 10,
|
|
20
|
+
6: 0,
|
|
21
|
+
7: 0,
|
|
22
|
+
8: 0,
|
|
23
|
+
9: 0,
|
|
24
|
+
10: 0,
|
|
25
|
+
11: 0,
|
|
26
|
+
12: 0,
|
|
27
|
+
13: 4064,
|
|
28
|
+
14: 0,
|
|
29
|
+
15: 0,
|
|
30
|
+
16: 0,
|
|
31
|
+
17: 3
|
|
32
|
+
};
|
|
33
|
+
for (let n = 0, t = base_fileds.length; t > n; n++) {
|
|
34
|
+
this[n] = data[n];
|
|
35
|
+
}
|
|
36
|
+
this.base_fileds = base_fileds;
|
|
37
|
+
}
|
|
38
|
+
random() {
|
|
39
|
+
return (Math.random() * parseInt(4294967295, 10)) >>> 0;
|
|
40
|
+
}
|
|
41
|
+
toBuffer() {
|
|
42
|
+
for (var r = this.base_fileds, n = [], t = -1, e = 0, a = r.length; a > e; e++) {
|
|
43
|
+
for (let u = this[e], f = r[e], d = (t += f); (n[d] = u & parseInt('11111111', 2)), --f != 0; ) {
|
|
44
|
+
--d;
|
|
45
|
+
u >>= parseInt(10, 8);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
getSession() {
|
|
51
|
+
let r = this.toBuffer();
|
|
52
|
+
return this.encode(r);
|
|
53
|
+
}
|
|
54
|
+
encode(r) {
|
|
55
|
+
let n = T(r);
|
|
56
|
+
let t = [2, n];
|
|
57
|
+
P(r, 0, t, 2, n);
|
|
58
|
+
return N(t);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
decodeBuffer(r) {
|
|
62
|
+
let n = dr;
|
|
63
|
+
let t = this.base_fileds;
|
|
64
|
+
let e = 0;
|
|
65
|
+
n = B;
|
|
66
|
+
for (let a = 0, o = t.length; o > a; a++) {
|
|
67
|
+
let i = t[a];
|
|
68
|
+
let u = 0;
|
|
69
|
+
do {
|
|
70
|
+
u = (u << parseInt(1000, 2)) + r[e++];
|
|
71
|
+
} while (--i > 0);
|
|
72
|
+
this[a] = u >>> 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
strhash(t) {
|
|
76
|
+
for (var o = 0, i = 0, u = t.length; u > i; i++) {
|
|
77
|
+
((o = (o << 5) - o + t.charCodeAt(i)), (o >>>= 0));
|
|
78
|
+
}
|
|
79
|
+
return o;
|
|
80
|
+
}
|
|
81
|
+
updateServerTime(stime, ua) {
|
|
82
|
+
// """更新服务器时间"""
|
|
83
|
+
const ts = parseInt(Date.now() / 1000, 10);
|
|
84
|
+
const random = parseInt(this.random(), 10);
|
|
85
|
+
this[0] = random;
|
|
86
|
+
this[1] = parseInt(stime, 10);
|
|
87
|
+
this[2] = ts;
|
|
88
|
+
this[3] = this.strhash(ua);
|
|
89
|
+
return this.getSession();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function T(r) {
|
|
94
|
+
for (var n = 0, t = 0, e = r.length; e > t; t++) {
|
|
95
|
+
n = (n << 5) - n + r[t];
|
|
96
|
+
}
|
|
97
|
+
return n & 255;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function P(r, n, t, e, a) {
|
|
101
|
+
for (let f = r.length; f > n; ) {
|
|
102
|
+
t[e++] = r[n++] ^ (a & 255);
|
|
103
|
+
a = ~(a * parseInt(203, 8));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function N(r) {
|
|
108
|
+
const S = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
109
|
+
for (var E = 0, A = r.length, b = []; A > E; ) {
|
|
110
|
+
let B = (r[E++] << parseInt('10000', 2)) | (r[E++] << 8) | r[E++];
|
|
111
|
+
b.push(
|
|
112
|
+
S.charAt(B >> parseInt('10010', 2)),
|
|
113
|
+
S.charAt((B >> parseInt('14', 8)) & parseInt('77', 8)),
|
|
114
|
+
S.charAt((B >> 6) & parseInt('3f', 16)),
|
|
115
|
+
S.charAt(B & parseInt('3f', 16))
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return b.join('');
|
|
119
|
+
}
|
|
120
|
+
const s = new S();
|
|
121
|
+
|
|
122
|
+
const getHeader = (options = {}) => {
|
|
123
|
+
let headers = {
|
|
124
|
+
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
|
|
125
|
+
Pragma: 'no-cache',
|
|
126
|
+
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
|
|
127
|
+
'Cache-Control': 'no-cache',
|
|
128
|
+
'Upgrade-Insecure-Requests': '1',
|
|
129
|
+
Referer: 'https://basic.10jqka.com.cn/601633',
|
|
130
|
+
'User-Agent':
|
|
131
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36',
|
|
132
|
+
...options
|
|
133
|
+
};
|
|
134
|
+
const ss = s.updateServerTime(parseInt(Date.now() / 1000, 10), headers['User-Agent']);
|
|
135
|
+
headers.Cookie = `v=${ss}`;
|
|
136
|
+
return headers;
|
|
137
|
+
};
|
|
138
|
+
module.exports = {
|
|
139
|
+
getHeader
|
|
140
|
+
};
|
|
141
|
+
// const s = new S();
|
|
142
|
+
// console.log(s.getSession());
|
|
143
|
+
// AnR2o5Q9lSuShAFn00OHkARhQznmTZg32nEsew7VAP-CeRsjNl1oxyqB_Apd
|
|
144
|
+
// AkhKJwjh3Gs-RbDvsuvGsWTNGrVa8az7jlWAfwL5lEO23epHqgF8i95lUA9Q
|
|
145
|
+
// 2,0,2,0,93,140,24,229,93,140,122,126,183,255,54,8,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,224,0,0,0,0,0,0,0,1,3
|
|
146
|
+
// 2,0,2,0,93,140,24,229,93,140,123,170,183,255,54,8,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,224,0,0,0,0,0,0,0,1,3
|
|
147
|
+
// 2,0,2,0,93,140,24,229,93,140,123,44,183,255,54,8,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,224,0,0,0,0,0,0,0,1,3
|
|
148
|
+
// 2,0,2,0,93,140,24,229,93,140,124,95,183,255,54,8,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,224,0,0,0,0,0,0,0,1,3
|
package/lib/utils.js
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
const isWeekday = date => {
|
|
2
|
+
const t = new Date(date).getDay();
|
|
3
|
+
return t >= 1 && t <= 5;
|
|
4
|
+
};
|
|
5
|
+
// 交易时间配置
|
|
6
|
+
const TRADING_HOURS = {
|
|
7
|
+
MORNING_START: 570, // 9:30 (分钟)
|
|
8
|
+
MORNING_END: 690, // 11:30
|
|
9
|
+
AFTERNOON_START: 780, // 13:00
|
|
10
|
+
AFTERNOON_END: 900 // 15:00
|
|
11
|
+
};
|
|
12
|
+
const isTradingTime = date => {
|
|
13
|
+
const t = new Date(date);
|
|
14
|
+
const n = 60 * t.getHours() + t.getMinutes();
|
|
15
|
+
return (
|
|
16
|
+
(n >= TRADING_HOURS.MORNING_START && n <= TRADING_HOURS.MORNING_END) ||
|
|
17
|
+
(n >= TRADING_HOURS.AFTERNOON_START && n <= TRADING_HOURS.AFTERNOON_END)
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const isTradingNow = e => {
|
|
22
|
+
const t = new Date();
|
|
23
|
+
return !(!isWeekday(t) || !isTradingTime(t) || (null != e && e > 0 && t.valueOf() - e > 6e5));
|
|
24
|
+
};
|
|
1
25
|
function getSecid(code) {
|
|
2
26
|
code = String(code);
|
|
3
27
|
if (code.indexOf('.') !== -1) {
|
|
@@ -25,7 +49,39 @@ function getSecid(code) {
|
|
|
25
49
|
}
|
|
26
50
|
return `0.${code}`;
|
|
27
51
|
}
|
|
28
|
-
|
|
52
|
+
const formatThsVolumeTime = e => {
|
|
53
|
+
let t;
|
|
54
|
+
let n;
|
|
55
|
+
let r;
|
|
56
|
+
let l;
|
|
57
|
+
let a;
|
|
58
|
+
let s;
|
|
59
|
+
let i = (null == e || null == (t = e.charts) ? void 0 : t.point_list) || [];
|
|
60
|
+
let o = (null == e || null == (n = e.charts) ? void 0 : n.header) || [];
|
|
61
|
+
let c = null;
|
|
62
|
+
let d = null;
|
|
63
|
+
let u = null;
|
|
64
|
+
let h = null;
|
|
65
|
+
let m = o.find(e => 'turnover' === e.key || '当日成交额' === e.name);
|
|
66
|
+
c = null != (r = null == m ? void 0 : m.val) ? r : null;
|
|
67
|
+
const p = o.find(e => 'turnover_change' === e.key || '较昨日变动' === e.name);
|
|
68
|
+
d = null != (l = null == p ? void 0 : p.val) ? l : null;
|
|
69
|
+
const f = o.find(e => 'predict_turnover' === e.key || '预测全天成交额' === e.name);
|
|
70
|
+
if (((u = null != (a = null == f ? void 0 : f.val) ? a : null), i.length > 0)) {
|
|
71
|
+
const e = i[i.length - 1];
|
|
72
|
+
e && (h = null != (s = e[0]) ? s : null);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
currentTurnover: c,
|
|
76
|
+
changeAmount: d,
|
|
77
|
+
predictTurnover: u,
|
|
78
|
+
dataTimestamp: h
|
|
79
|
+
};
|
|
80
|
+
};
|
|
29
81
|
module.exports = {
|
|
82
|
+
isWeekday,
|
|
83
|
+
isTradingTime,
|
|
84
|
+
isTradingNow,
|
|
85
|
+
formatThsVolumeTime,
|
|
30
86
|
getSecid
|
|
31
|
-
};
|
|
87
|
+
};
|
package/package.json
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
2
|
+
"name": "daxiapi-cli",
|
|
3
|
+
"version": "2.3.1",
|
|
4
|
+
"description": "大虾皮金融数据API命令行工具",
|
|
5
|
+
"bin": {
|
|
6
|
+
"daxiapi": "./bin/index.js",
|
|
7
|
+
"dxp": "./bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node bin/index.js --help"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"stock",
|
|
14
|
+
"api",
|
|
15
|
+
"daxiapi",
|
|
16
|
+
"cli",
|
|
17
|
+
"finance"
|
|
18
|
+
],
|
|
19
|
+
"author": "daxiapi.com",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"iconv-lite": "^0.5.0",
|
|
23
|
+
"request-promise-native": "^1.0.7",
|
|
24
|
+
"@ksky521/html-picker": "^1.0.0",
|
|
25
|
+
"@toon-format/toon": "^2.1.0",
|
|
26
|
+
"axios": "^1.6.0",
|
|
27
|
+
"chalk": "^4.1.2",
|
|
28
|
+
"commander": "^11.1.0",
|
|
29
|
+
"conf": "^10.2.0"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=14.0.0"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"bin",
|
|
36
|
+
"commands",
|
|
37
|
+
"lib",
|
|
38
|
+
"README.md"
|
|
39
|
+
]
|
|
40
|
+
}
|